Architectural Decisions

Architecture represents the significant design decisions that shape a system, where significant is measured by cost of change.

Grady Booch

Table of Content

  1. API definition
  2. Network protocol
  3. Programming language
  4. Framework
  5. Authentication
  6. EventBus
  7. CI/CD

This page will document our design decisions, providing insight into the decisions, justifications, considered alternatives and implications. It will help to understand why Keep was designed and how it works in the actual implementation.

To familiarize yourself with Keep’s functionality, you might want to read the following pages:

This is a living document.

Keep objectives

Make Domino development and access available to a broad audience with diverse development background. Keep the barrier to entry low without sacrificing enterprise and container deployability. Ensure access control through declaration on the server and its databases, relieving end-user applications from that task

Keep Classes


1. API definition

Keep uses the OpenAPI v3 (a.k.a Swagger) specification to describe its APIs

Justification

OpenAPI provides definitions and descriptions that are both machine and human readable, with several (Swagger, Redoc, Apicurio) gui implementations to make it accessible to different audiences.

The OpenAPI specification combines endpoint definitions, data types, examples and textual explanations in a single document. So a potential drift between documentation and implementation is less likely.

Accessing data via REST is available to all programming languages without the need to generate custom libraries. There is rich tooling (Code generation if required) available. Security of https is well understood.

OpenAPI is governed by the OpenAPI Initiative, an open source consortium under the auspices of the Linux foundation. No single company can steer it into a new direction.

Alternatives

We also looked at SOAP (outdated), protocol buffers (backend format, no support in browser, despite being donated to Cloud Computing Foundation driven by single vendor, code generation limited to a few languages, documentation of proto files poor), Java RPC (single language only), Websockets (not suitable for backend, no documentation format) and oDATA (decided to implement that as a database specific option)

Implication

OpenAPI allows for contract-first-design with well defined and documented APIs. We are not limited by CRUD operation considerations, but can offer higher function calls (like accepting meetings, sending eMails etc.) We can load in one Keep instance different API definitions. We use that for versioning and add-on APIs like Admin or Quattro.

We use the OpenAPI specified OperationId to identify what EventBus routes and processing classes shall be used. This fosters clear understanding for maintainers of how data flows through the system. It allows Keep to check at startup to see how complete it is.


2. Network protocol

Keep uses HTTP(S) distributed over 4 ports:

  • Keep REST API (the main access)
  • Keep Admin commands (usually limited to localhost)
  • Prometheus metrics (usually only accessible by prometheus)
  • KeepJWT service for responding to IdVault requests (typically on one Keep node)

However we are not limited to HTTP. The EventBus model (see below) allows us to implement additional protocols. We have an experimental PubSub access using Redis to the EventArch. There’s also an ability to use gRPC, once its format (Protocol Buffers or JSON) is clarified

Justification

HTTP is a well understood and well supported protocol. Given the framework we used (see below), support for Http/2 is already available. Using HTTP not only allows application servers (NodeJS, Websphere, SpringBoot etc ), but also Webclients hosted on static URLs to access Keep, opening access to front-end developers who want to use Domino as backend.

Alternatives

We also looked at nRPC (Notes only, no SDK), gRPC (server to server only, no browser support), native sockets (not routable), custom (outright crazy), UDP (not supported in browsers).

Implication

HTTP the the most used and most widely supported transport protocol. Given that we also cater to MS-Excel (on Windows), and pure browser applications, it was the only logical choice.


3. Programming Language

Keep is written in Java 8 (for now).

Justification

Domino provides its own JVM (OpenJava 8), so Java was an option. Furthermore it allows access to the C API with required flexibility without the limitations (see alternatives) of the C API. Keep bypassed Domino’s Java API and can run “outside” of Domino. This allows Keep to try Java 11 (or later) and/or GraalVM moving forward.

Alternatives

We looked at LotusScript (not flexible enough to process OpenAPI, caching, etc) and C/C++. Given the team composition (very limited C knowledge) and time frame, writing C was not feasible. Furthermore the secondary goal, easy extensibility, couldn’t be achieved given the typical dev skills found in customer environments. We looked at RUST (loved it, but no skills available).

Implication

Keep depends (for now) on the modified Java 8 runtime Domino provides. This eliminates the need for an additional runtime install (e.g. NodeJS or dotNet). Using Java 8 the option stays open to upgrade to later JVM versions as they become available for Domino or fast forward and use its own JVM (or GraalVM) which is more cloud native.


4. Framework

Keep uses the Apache vert.x framework. Vert.x offers polyglot, event driven and reactive development capabilities and an EventBus.

Justification

Running Keep standalone outside the Domino HTTP stack allows for deployment into a Notes client, thus minimizing the barrier to entry for a developer who wants to test things out or develop off line. Vert.x is the foundation to (and is sponsored by) RedHat’s Quarkus cloud native Java stack. It furthermore offers excellent support for OpenAPI contracts. The EventBus allows separation of incoming protocols from the database operations, thus enabling the deployment of multi-protocol access.

Alternatives

We were looking at OSGi plugins (which would have limited us to Domino servers), Spring Boot (learning curve and bundled Tomcat) and plain servlets (not polyglot, outdated programming model)

Implication

We can deploy Keep to Linux (server), Windows (client & server), and Mac (client only) with minimal effort. The vert.x HTTP stack supports HTTP2 and SSL certificates in multiple formats. Using more than one port allows us to fine-tune access, so admin operations (shutdown, restart) and metrics can be network isolated from regular operations. Vert.x also offers deployment into multiple threads (Workers) and can make use of available cores by deploying extra instances of its unit of work, the verticle.

Caveat: Event driven or reactive programming is a new field for most classical Java developers. It requires a learning curve.


5. Authentication

Access to the Keep APIs requires a valid JavaScript Web Token (JWT), signed by a trusted party. There is an API Endpoint available that allows, if activated (default = yes), exchange of Domino credentials for a JWT token. Tokens generated by RedHat Keycloak and custom generated tokens have also been successfully tested.

Justification

Keep is API only, so any dance that requires user interaction must happen before Keep APIs are accessed. The ability to use Domino credentials (including local users in client only) to obtain a JWT token lowers the barrier to entry. JWT is an established industry standard (RFC7519) and also is the end result of an OpenID Connect (OICD) dance. So its use and risks are well understood and documented.

Alternatives

We also looked at OICD, SAML, and Kerberos. They all require user interaction to authorize access. Since Keep is API only, this is regarded an application responsibility.

Implication

Developers can get started with Keep without deploying an IdP (Identity Provider) infrastructure. By using an established standard, customers can integrate their own identity solution without the need to deploy a Domino only Identity and Access Manager.


6. EventBus

Keep uses the vert.x internal EventBus to separate database operations from network I/O.

Justification

The EventBus caters to multiple network protocols (PubSub, WebSockets, HTTP, gRPC) without duplicating database operations. Furthermore Verticles (units of work in vert.x) can run in their own threads, allowing full utilization of available cores. We wrapped the EventBus into a reactive observer pattern, so the regular maintainer doesn’t need to deal with EventBus specifics.

Alternatives

We looked at manual thread programming (too much effort), and Google Guava eventbus (not flexible enough).

Implication

Since all data flows from a point of entry over the eventbus to a database request handler, identity checking (validating the JWT token) needs to happen on both ends: Point of entry and database level, since we can’t know if a custom deployed point of entry plays by the rules. By segregating runtime flow into different verticles/threads, the EventBus allows us to run certain operations with server privileges without compromising the regular database operations bound by user and ACL settings.


7. CI/CD

Keep uses Apache Maven as its build system. The Maven plugin Google JIB generates container images for use in Docker, Kubernetes or OpenShift

Justification

Maven allows us to build Keep, its satellite projects, Docker containers and documentation from a single source. It runs tests (unit & integration), and generates code coverage and code quality reports, as well as technical documentation (like the page you currently read). Thus information stays in the repository and has a mild chance not to be outdated.

Alternatives

We looked at shell scripts (too messy), Apache Ant (nightmare in dependency management), Gradle (site plugin too weak) and Jenkins scripts (no local build).

Implication

Focusing on maven based builds allows us to run builds both locally and on our CI environment Jenkins. So a developer can ensure all is well before a pull request kicks off a build.