My Authors
Read all threads
Every client app uses some form of the MVP (model-view-presenter) pattern.

The challenge is that the M is responsible for way too much.

As a result, developers don't know *which tools* are responsible for which tasks.
Tasks of the model:

- Providing reactivity to state changes
- Holding onto state
- Updating remote data and providing async states (loading, success, error)
- Expressing model behavior. Also known as domain (interaction) logic.
Tools we can use:

- React hooks
- Redux
- Context API
- Apollo Client
- RESTful APIs
- xState
- react-query
We face the same problem on the server-side using MVC (model-view-controller).

The `M` is responsible for too much. Business logic lives in between frameworks, ORMs, and controllers.

It's impossible to unit test code and it's also impossible to handle complex domain logic.
The solution to this on the sever-side is the Clean Architecture. Also known as the hexagonal, layered, or ports-and-adapters architecture.

It separates the concerns as either domain, application, or infrastructure, and provides a way to know which layer handles which work.
Using the architecture, features (use cases, which are either a commands or queries) are developed in vertical slices.

This means that you could swap out transport (graphql, rest) or persistence (MySQL, Mongo, event store) technologies per feature.

jimmybogard.com/vertical-slice…
Examples:

1. Serving a GraphQL request and persisting with Raw SQL.

- View = Desktop React App
- Transport = GraphQL
- Application (use case) = Create user
- Domain = Email, Password, Username models
- Persistence = Raw SQL
2. Serving a REST request and persisting it as a domain event.

- View = Android app
- Transport = REST
- Application (use case) = Create user
- Domain = Email, Password, Username models
- Persistence = @eventstore
3. Serving a GraphQL request by resolving it using an ORM

- View = React Native app
- Transport = GraphQL
- Application (use case) = Get user by id
- Domain = skip
- Persistence = Sequelize ORM
The point is,

The clean architecture tells us what each layer is responsible for.

We're missing this same kind of clarity on the client-side.
To add to that- last year, the React community shunned container components entirely and presented Hooks as the end-all-be-all of where _everything-not-view-layer_ goes.

medium.com/@dan_abramov/s…
In reality, container components can't be avoided.

We need some component that:
- connects user events to interaction logic
- connects (reactive) data to UI components

This, below, is a container component in a React Hooks world.
I started thinking about this a couple of months ago.
If we decompose the `M` from MVP on the client-side, what are the layers?

- 🧠 Interaction logic (behavior of the model)
- 🚡 Data fetching (and reporting async states)
- 🗄️ State management (storage, updating the locally cached data, providing reactivity)
What's marked in `yellow` is the **pure** model.

This is the **behavior** of your application.

If you keep this free of libraries and frameworks, it's unit testable.
If the behavior of your app is really simple, then this will be less useful for you. Apps where you're mostly displaying data like dashboards or admin panels.

If your app has complex behaviour, ie: games, drag-and-drop, data viz, etc. Then separation of concerns is essential.
Unit testing complex behavior is essentially testing implementation details, but sometimes, that's the only way to validate correctness.

If you can validate correctness through the UI, integration tests might provide more bang for your buck.

So now if we know what the layers of our model are, we can probably apply the same technique to understanding which tools are used for what
Using Apollo Client and @DavidKPiano's xState lib

- Interaction logic: Hooks + xState
- State management: Apollo Client (global state)
- Data fetching: Apollo Client
Using Apollo Client and plain JavaScript as a model

- Interaction logic: Hooks + pojo-observer
- State Management: Apollo Client (global state)
- Data fetching: Apollo Client

github.com/xolvio/pojo-ob…
Using Redux, REST and React Hooks

- Interaction logic: Hooks
- State Management: Redux (global state). Connect for observability/reactivity, and Thunks for signaling async states.
- Data fetching: Fetch or Axios
Zooming out and back in, here's what I think the separation of concerns really looks like for most #ClientSideArchitecture.
Testing the view:
UI logic can be tested as a side-effect of the model.

To avoid testing view-layer specifics, a library like @TestingLib can be used to perform integration tests.

For simple apps, like the ones we described earlier, this is the **only** type of logic that exists, so the best way to test your app is working correctly _is_ by testing against the view.
Missing some Tweet in this thread? You can try to force a refresh.

Keep Current with 𝙆𝙃𝘼𝙇𝙄𝙇 𝙎𝙏𝙀𝙈𝙈𝙇𝙀𝙍

Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

Twitter may remove this content at anytime, convert it as a PDF, save and print for later use!

Try unrolling a thread yourself!

how to unroll video

1) Follow Thread Reader App on Twitter so you can easily mention us!

2) Go to a Twitter thread (series of Tweets by the same owner) and mention us with a keyword "unroll" @threadreaderapp unroll

You can practice here first or read more on our help page!

Follow Us on Twitter!

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3.00/month or $30.00/year) and get exclusive features!

Become Premium

Too expensive? Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal Become our Patreon

Thank you for your support!