Skip to content

Commit

Permalink
feat(concepts): add clean cloud architecture concept and terminology …
Browse files Browse the repository at this point in the history
…and link in docs
  • Loading branch information
TillaTheHun0 committed Jan 2, 2024
1 parent e527123 commit 8ecf681
Show file tree
Hide file tree
Showing 8 changed files with 161 additions and 21 deletions.
14 changes: 3 additions & 11 deletions src/.vitepress/config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -38,23 +38,15 @@ export default defineConfig({
text: '🤓 Concepts',
items: [
{
text: 'Why hyper',
text: '⚡️ Why hyper',
link: '/docs/concepts/why',
},
{
text: 'Terminology',
link: '/docs/concepts/terminology',
},
{
text: 'Ports and Adapters',
link: '/docs/concepts/ports-and-adapters',
},
{
text: 'Clean Cloud Architecture',
text: '🧼 Clean Cloud Architecture',
link: '/docs/concepts/clean-cloud-architecture',
},
{
text: 'hyper Response Shape',
text: '🟨 hyper Response Shape',
link: '/docs/concepts/hyper-shape',
},
],
Expand Down
4 changes: 2 additions & 2 deletions src/docs/api-reference/rest/cache.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ A good seeding strategy requires that you know when cache hits occur to ensure t

## Create a `Cache` Service

Create a hyper `Cache` Service in the [`Domain`](/docs/concepts/terminology#domain).
Create a hyper `Cache` Service in the hyper [`Domain`](/docs/concepts/clean-cloud-architecture#hyper-domain).

::: code-group

Expand Down Expand Up @@ -78,7 +78,7 @@ curl -X PUT https://$HOST/cache/$DOMAIN

## Destroy a `Cache` Service

Destroy a hyper `Cache` Service in the [`Domain`](/docs/concepts/terminology#domain). This will remove all key-value pairs stored in the `Cache` Service.
Destroy a hyper `Cache` Service in the hyper [`Domain`](/docs/concepts/clean-cloud-architecture#hyper-domain). This will remove all key-value pairs stored in the `Cache` Service.

:::danger
This is a destructive operation that will destroy the `Cache` Service and all key-value pairs stored within it. Be really sure you want to do this, before destroying your `Cache` Service.
Expand Down
4 changes: 2 additions & 2 deletions src/docs/api-reference/rest/data.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ If need the ability to perform Business Reporting and Analytics, using complex a

## Create a `Data` Service

Create a hyper `Data` Service in the [`Domain`](/docs/concepts/terminology#domain).
Create a hyper `Data` Service in the hyper [`Domain`](/docs/concepts/clean-cloud-architecture#hyper-domain).

::: code-group

Expand Down Expand Up @@ -81,7 +81,7 @@ curl -X PUT https://$HOST/data/$DOMAIN

## Destroy a `Data` Service

Destroy a hyper `Data` Service in the [`Domain`](/docs/concepts/terminology#domain). This will remove all documents stored in the `Data` Service.
Destroy a hyper `Data` Service in the hyper [`Domain`](/docs/concepts/clean-cloud-architecture#hyper-domain). This will remove all documents stored in the `Data` Service.

:::danger
This is a destructive operation that will destroy the `Data` Service and all documents stored within it. Be really sure you want to do this, before destroying your `Data` Service.
Expand Down
17 changes: 17 additions & 0 deletions src/docs/build/index.md
Original file line number Diff line number Diff line change
@@ -1 +1,18 @@
# Build on hyper

The hyper Service Framework is built using the
[Ports and Adapters](/docs/concepts/ports-and-adapters) architecture. Hyper's core business logic is driven by a Driving Adapter

The general idea with Ports and Adapters is that the business logic layer defines the models and rules on how they interact with each other, and also a set of consumer-agnostic entry and exit points to and from the business layer. These entry and exit points are called "Ports". All components _external_ to the business layer, interact by way and are interacted with through, the Ports. A Port defines an api, and knows nothing about the inner mechanism -- that's an Adapter's job.

Adapters perform the actual communication between external actors and the business layer. There are generally two types of Adapters: "Driving Adapters" and "Driven Adapters".

A driving adapter calls into the business layer, by way of a Port. The driving adapters can generally be thought of as the "presentation layer". It could be a web application, a desktop application, a _CLI_, anything that initiates some action on the business domain.

A driven adapter is called by the business layer, to interact with some backend tool, ie. a database, storage bucket, cache, etc. The business layer calls into the driven adapter by way of the Port. **Driven adapters implement the Port defined by the business layer**.

So the flow generally looks like

```
Driving Adapter <--> Port <--> Business Layer <--> Port <--> Driven Adapter
```
139 changes: 137 additions & 2 deletions src/docs/concepts/clean-cloud-architecture.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,138 @@
# Clean Cloud Architecture
# Clean Cloud Architecture & Terminology

TODO
hyper is built using a "[Ports and Adapters](<https://en.wikipedia.org/wiki/Hexagonal_architecture_(software)>)" approach.

The general idea with Ports and Adapters is that the business logic layer defines the models and rules on how they interact with each other, and also a set of consumer-agnostic entry and exit points to and from the business layer. These entry and exit points are called "Ports". All components _external_ to the business layer, interact by way and are interacted _with_, the Ports. A Port defines an api but knows nothing about the mechanism or the impetus. Those two things are an Adapter's job.

Adapters perform the actual communication between external actors and the business layer. There are generally two types of Adapters: "Driving Adapters" and "Driven Adapters".

A driving adapter calls into the business layer, by way of a Port. The driving adapters can generally be thought of as the "presentation layer". It could be a web application, a desktop application, a _CLI_, anything that initiates some action on the business domain.

A driven adapter is called by the business layer, to interact with some backend tool, ie. a database, storage bucket, cache, etc. The business layer calls into the driven adapter by way of the Port. **Driven adapters implement the Port defined by the business layer**.

So the flow generally looks like

```
Driving Adapter <--> Port <--> Business Layer <--> Port <--> Driven Adapter
```

## Benefits

Because the business layer enforces the Ports, and all external interactions with external components happens through the Ports, the business layer is encapsulated. The benefits of this for the system cannot be overstated.

It means the business layer, the models and the rules governing them, can be developed _before_ choosing things like a database, or a frontend framework. Better yet, the business layer can be _tested_ before choosing any of those things. **Covering business logic almost entirely with unit tests is a boon for confidence in the system.**

> When building software, a decision should be conceptualized as a set of _constraints_, and ideally the pros of accepting those constraints outweigh the cons. So we ought to defer accepting constraints until we have as much information as possible to inform that decision. Clean Architecture enables us to do just that.
It also allows for the separation of concerns. Each tier of the architecture can change without requiring changes in the other tiers. This is important because some tiers are more volatile than others; typically the UI of an application changes faster than business rules for example.

> The only time we must touch multiple tiers is if a Port is changed. And that is usually a find and replace
## hyper Clean Architecture Lingua Franca 📚

![hyper-architecture](/hyper-architecture.png)

### hyper Apps 🎮

The Driving Adapters in the hyper Service Framework are called `Apps` or `Apis`. The hyper Core team maintains
an HTTP-based RESTful [hyper `App`](/docs/build/custom-app) implementation, using the popular Web
Server framework [express](https://expressjs.com/). You can see the API Reference [here](/docs/api-reference/rest/index)

In the future, we would like to see more app offerings. A CLI app, a GRPC app, we've even discussed a Service Worker app, so that hyper could be run entirely in the browser, on a Service Worker 😎.

### hyper Core 🪨

The business layer in hyper is called [core](https://github.com/hyper63/hyper/tree/main/packages/core) which contains all of the business logic and enforces each Port. Core also defines the Port that a hyper `App` invokes.

### hyper Ports 🔌

There are multiple Ports defined in the hyper Service Framework. The current ones are `Data`, `Cache`, `Storage`, `Queue`, and `Search`.

### hyper Adapters 🛠

The Driven Adapters in The hyper Service Framework are simply called `Adapters`. You can see many of them that the Core team has implemented [here](https://github.com/hyper63?q=hyper-adapter&type=all&language=&sort=). Each adapter implements a `Port` and does the heavy lifting of communicating with an underlying technology being used to power the `Port`.

### hyper Services

A hyper `Service` is combination of the components described above:

- A hyper `App`
- hyper Core
- An `Adapter` Port
- A hyper `Adapter`

For example, a hyper `Data` Service might be:

```
RESTful api -> Core -> Data Port -> CouchDB Adapter
// or
GraphQL api -> Core -> Data Port -> Postgres Adapter
// or
CLI -> Core -> Data Port -> DynamoDB Adapter
```

A hyper `Cache` Service might be:

```
GRPC api -> Core -> Cache Port -> Redis Adapter
// or
GraphQL api -> Core -> Cache Port -> Sqlite Adapter
// or
CLI -> Core -> Cache Port -> FlatFile Adapter
```

A hyper `Search` Service might:

```
GRPC api -> Core -> Search Port -> Elasticsearch Adapter
// or
RESTful api -> Core -> Search Port -> Minisearch Adapter
// or
CLI -> Core -> Search Port -> Algolia Adapter
```

I hope you're noticing something:

**`Adapters` and `Apps` are _interchangeable_**. This is how we can test our business layer without choosing a database, for example. We can simply stub the `Adapter` that implements the `Port` that the core business logic interacts with.

## hyper Server

A hyper `Server` is an instance that hosts multiple hyper `Services` and may be consumed via whatever the hyper `App` api exposes.

## hyper Domain

hyper `Services` are created on a hyper `Server`, within a hyper `Domain`.

A `Domain` is simply a logical grouping of hyper `Services` hosted on a hyper `Server`.

hyper `Domains` are commonly used to distinguish a set of hyper `Services` leveraged by an application.
For example, if you had `foo` application and a `bar` application, they each might have their own `Domain` and own connection string to the hyper `Server`:

```js
const connect = require("hyper-connect");

const DOMAIN = "foo";

const { data, cache } = connect(`https://${SUB}:${SECRET}@HOST/${DOMAIN}`);

// Create a Data Service and Cache Service in the foo domain
await data.create();
await cache.create();

// #############################
// In another deployable, or perhaps a logically-separated
// part of the same deployable ie. Modular-Monolith
// ##############################

const DOMAIN = "bar";

const { data, storage } = connect(`https://${SUB}:${SECRET}@HOST/${DOMAIN}`);

// Create a Data Service and Storage Service in the bar domain
await data.create();
await storage.create();
```

:::info
A `Connection String` used with `hyper-connect` is ALWAYS tied to a single hyper `Domain`. If you need to consume multiple `Domains` in the same context, simply instantiate multiple instances of `hyper-connect`, like in the example above.
:::
3 changes: 0 additions & 3 deletions src/docs/concepts/ports-and-adapters.md

This file was deleted.

1 change: 0 additions & 1 deletion src/docs/concepts/terminology.md

This file was deleted.

Binary file added src/public/hyper-architecture.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 8ecf681

Please sign in to comment.