Skip to content

Commit

Permalink
BC-5096: adds docs regarding project structure (#2793)
Browse files Browse the repository at this point in the history
  • Loading branch information
OliverHappe authored Sep 8, 2023
1 parent dc06358 commit 50632e3
Show file tree
Hide file tree
Showing 12 changed files with 220 additions and 19 deletions.
37 changes: 18 additions & 19 deletions docs/1_CodeConventions.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# Code Conventions

<!-- vscode-markdown-toc -->
* [filenames](#filenames)
* [directory structure](#directorystructure)
* [data-testid(s)](#data-testids)
* [ts-ignore comments](#ts-ignorecomments)
* [Composables](#Composables)
- [Code Conventions](#code-conventions)
- [filenames](#filenames)
- [data-testid(s)](#data-testids)
- [ts-ignore comments](#ts-ignore-comments)
- [Composables](#composables)

<!-- vscode-markdown-toc-config
numbering=false
Expand All @@ -16,18 +16,17 @@
## <a name='filenames'></a>filenames

Files should be consistently named like this:
| file content | filename |
|----------------|------------------------------:|
| Components | `YourComponent.vue` |
| Pages | `YourPageName.page.vue` |
| Layouts | `yourLayoutName.layout.vue` |
| Composables | `yourComponent.composable.ts` |
| Tests | `yourTestFile.unit.ts` |
| Utils | `yourUtil.ts` |
| Pinia stores | `yourFilename.ts` |
| Vuex stores | `your-filename.ts` |

## <a name='directorystructure'></a>directory structure
| file content | filename |
| ------------ | ----------------------------: |
| Components | `YourComponent.vue` |
| Pages | `YourPageName.page.vue` |
| Layouts | `yourLayoutName.layout.vue` |
| Composables | `yourComponent.composable.ts` |
| Tests | `yourTestFile.unit.ts` |
| Utils | `yourUtil.ts` |
| Pinia stores | `yourFilename.ts` |
| Vuex stores | `your-filename.ts` |


**Near future**: The structure of this project will move from the old *Atomic Design* (= using molecules- and atoms- folders) to a more use-case-centeric approach.
Details are documented here: [Vue 3 project structure](https://docs.dbildungscloud.de/x/oYAgDQ)
Expand All @@ -46,8 +45,8 @@ Please use ``<div ... data-testid="some-example" ...>`` in your HTML-code if you

We also recommend to use **ref**s instead of data-testids. But if you do that, you need to be careful when removing them... as they could be used in the component-code AND in tests:

- [VueJs - template refs](https://vuejs.org/guide/essentials/template-refs.html)
- [VueTestUtils - ref](https://v1.test-utils.vuejs.org/api/#ref)
* [VueJs - template refs](https://vuejs.org/guide/essentials/template-refs.html)
* [VueTestUtils - ref](https://v1.test-utils.vuejs.org/api/#ref)

Also look here: *Frontend Arc Group: Meeting Notes 2022-11-04*

Expand Down
162 changes: 162 additions & 0 deletions docs/2_ProjectStructure.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
# Project Structure


## Description of the Structure

The projects code is separated into building blocks.

## What is a building-block?

A **building-block** is a "container" were we place most of our applications logic and components. Each building-block is defined by an `index.ts (Barrel-File)` describing it's exported content (public API of a building-block) and a `type`.

Utilizing linting rules and the index.ts we can ensure that each building-block only exposes files which are meant to be used application-wide. This way we achieve a strong separation of concern across the whole application.


Our linting rule is based on the following concept:

[Enforce Project Boundaries | Nx](https://nx.dev/core-features/enforce-project-boundaries)

`Note: in above documentation **libraries** are equivalent to building-blocks and **tags** represent the types defined below.`

## Types of building-blocks

**Page**

Contains a subpage of the application. Orchestrates Feature and UI building-blocks.

`Example: page-dashboard`

**Feature**

Complex features with **stateful / smart components**. Usually specialized to fulfill specific roles in the App. Can also contain presentational components that are specialized for this feature.

`Example: feature-calendar`

**UI**

**Stateless / presentational components** which get their data via props and emit events. Usually less specialized.

`Example: ui-forms`

**Data**

State and API-access. Does not contain any visual components. They are the data-sources of all smart components.

`Example: data-auth`

**Util**

Contains shared low-level code.

`Example: util-form-validators`

## Type: Page

### What is it?

A page building-block represents a **subpage** of the application. It contains the layout component and orchestrates feature and ui building blocks to create a subpage. It can not be imported into any other type of building-block. It is **only imported by the vue-router** and should be **lazy-loaded** if possible.

### Naming Convention

Placed in folder **page**

### Can import types

data, util, ui, feature

## Type: Feature

### What is it?

A feature building-block contains a set of files that represent a business use case in an application.

Most of the components of features are **stateful / smart components** that interact with data sources. This type also contains most of the UI logic, form validation code, etc.

### Naming Convention

Placed in folder **feature**

### Can import types

data, util, ui, feature


## Type: UI

### What is it?

A ui building-block mainly contains **Stateless / presentational components** which are used all across the application. They don't have access to stores and do not use features in their templates. All data needed for components in ui building-blocks comes from props.

### Naming Convention

Placed in folder **ui**

### Can import types

util, other ui

## Type: Data

### What is it?

A data building-block contains **stores and api-services**. It does not contain any view components. They serve as data-sources for feature and page building blocks.

### Naming Convention

Placed in folder **data**

### Can import types

util, other data

## Type: Util

### What is it?

A utility building-block contains **low level code** used by many building-blocks. Often there is no framework-specific code and the building-block is simply a collection of types, utilities, pure functions, factories or composables.

### Naming Convention

Placed in folder **util**

### Can import types

other util

# How to pick the correct type for my Task

`To render this graph in VS-Code markdown preview install this extension: bierner.markdown-mermaid`

```mermaid
flowchart TD
A[Your Task] --> B[Imagine the different requirements of the Task]
B --> C{Do I need a new subpage}
C -->|Yes| D(type: page)
C -->|No| E{Do I need UI?}
E --> |No| F{Do I need State?}
E --> |Yes| G{Do I need State?}
F -->|Yes| H(type: data)
F -->|No| I(type: util)
G -->|Yes| J(type: feature)
G -->|No| K(type: ui)
H --> L[Are all requirements of your task placed in a building-block?]
I --> L
J --> L
K --> L
D --> L
L -->|Yes| M[Happy Coding!]
L -->|No| O[You need an additional building-block]
O --> B
M -.-> P[Evaluate your choices as a part of your review and refactor when neccessary]
```

# Matrix of allowed imports

| Allowed to Import ➡<br> It is ⬇ | page | feature | data | ui | util |
| ------------------------------- | ---- | ------- | ---- | --- | ---- |
| page | |||||
| feature | |||||
| data | | || ||
| ui | | | |||
| util | | | | ||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
40 changes: 40 additions & 0 deletions docs/8_IdentifyingAndResolvingCircularDependencies.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Identifying and Resolving Circular Dependencies

## What is a circular dependency?
Circular depencies are a common issue when working with barrel-files (index.ts).

Let's look at a common dependency pattern:

![Circular Import](./assets/circular_dependency_1.png)


In this example there are two **Building-Blocks** (e.g. folders that have a barrel file) which depend on each other. Using the SharedComponent in both Building-Blocks will result in a circular dependency.

That basically means that the compiler can not resolve the order to load the Building-Blocks which causes an error.



## Resolving Circular Dependencies

The basic gist is: **break the circle** and separate the shared dependency in a separate module.

![Fixed Circular Import](./assets/circular_dependency_2.png)

In this configuration the compiler can find an order to resolve the building-blocks correctly.



## How to identify Circular Dependencies in Vue

I recreated the first example error in Vue. When Vue tries to render ComponentA I see the following Error in the console:

![Error Message](./assets/circular_dependency_3.png)

This can be quite hard to decipher on a first glance but it contains all the info we need to identify the root cause of the circular dependency.

![Error Message Explained](./assets/circular_dependency_4.png)

Based on the info from the message we can learn that ComponentB "closed the circle" by importing SharedComponent. From there we can trace back to see where SharedComponent is exposed and why it depends on ComponentB. In this case it is because they are both imported in ComponentA.

Keep in mind that the circular dependency can involve multiple building-blocks.

Binary file added docs/assets/circular_dependency_1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/circular_dependency_2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/circular_dependency_3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/assets/circular_dependency_4.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 50632e3

Please sign in to comment.