Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions website/.vitepress/config.mts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@ export default defineConfig({
text: "Domains",
link: "/domains",
},
{
text: "Layers",
link: "/layers",
},
{
text: "Layer Groups",
link: "/layer-groups",
},
],
socialLinks: [{ icon: "github", link: "https://github.com/pwlmc/morando" }],
},
Expand Down
47 changes: 47 additions & 0 deletions website/docs/layer-groups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Layer Groups

## Layers Belong to Groups

The idea of a layer group comes from a simple observation: all code in modern
front-end applications can be grouped into four broad levels of abstraction.
They are:

| Layer Group | Description | Default layer |
| ------------ | --------------------------------------------------------------------------------------------------------------------------------------- | ------------- |
| Definitions | The most abstract layer group. It contains foundational, reusable types, and invariants that are independent of implementation details. | `defs` |
| Operations | The business logic layer. It holds operations, services, and utilities that do not involve presentation logic. | `ops` |
| Presentation | The user interface layer. It contains components, views, and UI-specific code that present data and interact with users. | `ui` |
| Bootstrap | The application entry layer. It wires together lower layers and bootstraps the app. | `main` |

Every Morando project needs to define four layers at minimum: at least one layer
in each of the four layer groups.

## Default Layers

Each layer group needs to have at least one layer defined. For convenience,
Morando provides predefined default layers - one for each group. Those layers
are: `defs`, `ops`, `ui`, and `main`.

Projects are free to customize their list of layers, but this is not standard
practice. Morando comes with predefined layer lists for the most popular
front-end frameworks. Choosing one that fits your project's tech stack should
remove the need to define custom layers altogether.

## Custom Layers Example

For educational purposes, let's pretend we want to define a custom layer list
for our React single-page web application. In such an application, it makes
sense to define an additional `hooks` operations layer in addition to the
default `ops` layer. We might also want to have more specialized presentation
layers instead of a single general `ui` layer. Let's say we want our
presentation layers to consist of `components` and `pages`. The final list of
layers could then look something like this (from lowest to highest):

| Layer name | Layer Group |
| ------------ | ------------ |
| `defs` | Definitions |
| `ops` | Operations |
| `hooks` | Operations |
| `components` | Presentation |
| `pages` | Presentation |
| `main` | Bootstrap |
77 changes: 76 additions & 1 deletion website/docs/layers.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,78 @@
# Layers

TBA
## Modules vs. Layers

While modules are specific to your project, layers are closely related to the
tech stack.

Every project that uses Morando architecture will inevitably contain different
modules. That is expected, because modules express the application's business
domain. You cannot expect an online banking app to have the exact same set of
modules as, for example, a hotel-booking app. Some modules may be similar, for
instance, both may include a `@/Routing` module, but the core business modules
will still diverge.

Layers are different. In all Morando applications, you will find some universal
base layers that are always present. In many apps, the list of layers will be
identical. That makes it much easier to switch between projects when you have a
consistent set of layers to anchor yourself to. Let's define what layers are so
we can see how this emerges.

## What Are Layers?

A layer is simply a name that represents a level of abstraction in a Morando
project.

The lowest layers are those that contain the most core and abstract definitions
on top of which you want to build the rest of your application. The higher the
layer, the more implementation-specific and less abstract it becomes.

For each project, the list of layers needs to be defined upfront because without
it we can't validate the project's architecture. More details on what a concrete
list of layers might look like will be discussed in the
[Layer groups](./layer-groups.md) chapter. For now, it is enough to assume that
layers are an ordered list of names defined for a Morando project.

## Files Are Classified to Layers

In Morando architecture, every file must be classified to a layer.

A file is assigned to a layer by a classifier function. Because Morando never
parses a file's code, the classifier usually tries to assign a file based on its
location in the project, file name, extension, and so on. For example, in a
React project that defines a `components` layer, a `Button.tsx` file may be
classified to that layer because it starts with an uppercase letter and has a
`tsx` extension.

The classifier's algorithm is an implementation detail specific to the concrete
list of layers, and we will not discuss it here. That said, there is one
universal classifier for all Morando projects, already mentioned in the
[Modules](./modules.md#modules-are-flat) chapter.

Layer folders are special folders named exactly as the layer. They are optional
folders that can be placed inside a module and act as classifiers for all files
inside them. For example, in the case of the following hypothetical module:

```text
Shared/
└── components/
├── foo.ts
└── bar.ts
```

`foo.ts` and `bar.ts` would be classified to the `components` layer. Of course,
that assumes the project defines the `components` layer; otherwise, the
`components/` folder would not be a valid layer folder.

## The Golden Rule of Layers

Before we move forward, we need to discuss one important rule that makes layers
so important for a project's stability and validity.

:::tip Layers Golden Rule
A file can depend only on files from the same or lower layer.
:::

The rule is global, which means it does not matter what module the file is
located in. As long as the file is not importing a file that is classified to a
layer higher than its own, the rule is not violated.
83 changes: 0 additions & 83 deletions website/docs/layers_old.md

This file was deleted.

12 changes: 6 additions & 6 deletions website/docs/modules.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ contain source code files. Below you can find an example of a `User` module:

```text
User/
├── UserAvatar.tsx
├── useUser.ts
├── model.ts
├── api.ts
└── model.ts
├── useUser.ts
└── UserAvatar.tsx
```

## Modules Are Flat
Expand All @@ -30,9 +30,9 @@ their names are strictly tied to the layers defined in your project. They are
_layer folders_, and to make them easier to tell apart from modules, their names
start with a lowercase letter.

We will cover them in the [Layers](./layers.md) chapter, but for this chapter,
it is enough to remember that they are optional. Like modules, layer folders
also cannot be nested.
We will cover them in the [Layers](./layers.md#files-are-classified-to-layers)
chapter, but for this chapter, it is enough to remember that they are optional.
Like modules, layer folders also cannot be nested.

Below is an example of a `Shared` module that contains `utils` and `components`
layer folders.
Expand Down
Loading