🔠#8: Vue Clean Architecture, how to decide which testing strategy to use, and a code-sharing pattern idea
Thoughts about applying Clean Architecture principles to Vue.js projects, deciding which testing strategy to use to test our applications, and how to effectively share code between teams.
Hey,
Whenever I work on a side project, for me, the most fulfilling aspect of the process is playing around with ideas for structuring my code or testing some new technology. So last two weeks, I explored how to apply Clean Architecture principles to a Vue project.
Testing is a topic dear to my heart. Thus a couple of days ago, I ordered my thoughts about all the different testing strategies and wrote an article.
I watched a talk by the wonderful Monica Lent about Building Resilient Frontend Architecture. I highly recommend you check that out.
The topic of code sharing between teams inside a company was on my mind again, and I came up with a new idea for making it work.
About a week ago, I treated myself to a new M1-powered MacBook Air. And I have to say it is an incredible device. Fanless yet almost twice as fast as my 2019 MacBook Pro. I'm impressed.
This is the 8th issue of my Recent Discoveries newsletter. If you don't want to miss the next issue, hit subscribe.
Vue Clean Architecture
I'm experimenting with a Clean Architecture-inspired directory structure for a Vue application.
/my/project/src
├─ components
│ ├─ TheFooter.vue
│ ├─ TheHeader.vue
│ └─ ...
├─ modules
│ ├─ product
│ │ ├─ components
│ │ │ ├─ ProductCart.vue
│ │ │ ├─ ProductDetail.vue
│ │ │ └─ ...
│ │ ├─ composables
│ │ │ ├─ product-cart-view-model.vue
│ │ │ ├─ product-view-model.vue
│ │ │ └─ ...
│ │ ├─ services
│ │ │ └─ product.js
│ │ └─ utils
│ │ └─ format-price.js
│ └─ ...
├─ shared
│ ├─ components
│ │ ├─ BaseCard.vue
│ │ ├─ BaseButton.vue
│ │ └─ ...
│ └─ utils
│ ├─ as-array.js
│ └─ ...
└─ ...
I'm very sure about the approach of using modules
(others call them features
) to split the application up into logical concerns. But during the process, I added and then removed a couple of abstraction layers already.
At one point, I had services
, stores
, view-models
, and use-cases
. services
and stores
served as an abstraction layer for the infrastructure logic (API) and the idea behind use-cases
was that they help to decouple business logic from the framework / UI layer. I since have merged stores
, view-models
, and use-cases
into one: view-models
.
We place Application-specific business logic in view-models
. Because view-models
are not framework agnostic but contain Vue-specific reactive code, there is no decoupling between application-specific business logic and the framework layer. But I decided that this is ok because the overhead of decoupling business logic from reactive code is just not worth it.
We should place Domain-specific business logic (e.g., validation rules) in the service
layer. So here we have nice decoupling of framework code and business logic.
What I've learned so far:
Composables are a perfect way to share business logic between components.
Too many layers for the sake of decoupling business logic from framework code are just not worth it.
Reactivity is a fantastic concept but makes it harder to write framework agnostic code.
Manual testing, E2E testing, unit testing – how to decide which testing strategy to use?
When it comes to automated testing, there are a lot of different names for certain types of tests thrown around: E2E testing, acceptance testing, integration testing, unit testing,… to name a few. So in my latest article, I ordered my thoughts about all the existing testing strategies.
We learn about the strengths and weaknesses of the different testing strategies and when to use what. Read more.
Building Resilient Frontend Architecture by Monica Lent
Monica Lent's talk about frontend architecture was one of the funniest yet educational talks I've seen in a long time. I highly recommend you check it out.
In one section of the talk, she reminded me of the invaluable dependency cruiser package. We can use it not only to visualize dependencies between the modules of our project but also to validate them. This can be a handy tool to validate the architecture of a frontend application.
In-house code-sharing pattern idea
I recently wrote about how I think the You Break It, You Fix It principle should be applied when maintaining a shared codebase. But since then, I realized that there could be quite a few barriers that make people uncomfortable working like that.
So I've developed a refined approach for situations where the idea to make changes to code primarily maintained by other teams does not persuade people.
First of all, people changing the shared code still can update all consumers, which should be encouraged. But if they don't,
they have to make the change in the shared codebase in a backward-compatible way and mark the old way as deprecated.
They must create a ticket for every team that relies on the shared code to incorporate the breaking changes by a given deadline.
The last team that upgrades their code has to remove the deprecated code from the shared codebase.
This solves a couple of problems:
We do not force affected teams to make a change immediately because of the requirements of another team.
We can make changes to the shared codebase at any time without heavy coordination among other teams.
But this comes at the cost of having to make changes in a backward-compatible manner. Furthermore, I have to say that I did not yet prove if this works in production. Hence, for now, this is only an idea. But I think a promising one.
Sponsors
Storyblok is a headless CMS with a Visual Editor. They’re currently working on their V2 release! You can start using the V2 beta today!
Nuxt.js is a web framework for building modern apps & websites with Vue.