Reagent looks terrific. So, why do I need re-frame? What benefit is there in the extra layers and conceptual overhead it brings?
Yes, we agree, Reagent is terrific. We use it enthusiastically ourselves. And, yes, we'd agree that if your application is small and simple, then standalone Reagent is a fine choice.
But it does only supply the V part of the MVC triad. As your application gets bigger and more complicated, you will need to find solutions to questions in the M and C realms.
Questions like "where do I put control logic?". And, "how do I store and update state?". And, "how should new websocket packets be communicated with the broader app"? Or GET failures? And, "how do I put up a spinner when waiting for CPU intensive computations to run, while allowing the user to press Cancel?" How do I ensure efficient view updates? How do I write my control logic in a way that's testable?
These questions accumulate.
Reagent, by itself, provides little guidance and, so, you'll need to design your own solutions. Your choices will also accumulate and, over time, they'll become baked into your codebase.
Now, any decision which is hard to revisit later is an architectural decision - "difficult to change later" is pretty much the definition of "architecture". So, as you proceed, baking your decisions into your codebase, you will be incrementally growing an architecture.
So, then, the question is this: is your architecture better than re-frame's? Because
that's what re-frame gives you ... an architecture ... answers to the
various challenges you'll face when developing your app, and mechanism for implementing
those answers.
Now, in response, some will enthusiastically say "yes, I want to grow my own architecture. I like mine!". Fair enough - its a fun ride!
Problems arise ONLY when this process is not conscious and purposeful. It is a credit to Reagent that you can accelerate quickly and get a bunch of enjoyable early wins. But, equally, that acceleration can have you off the road in a ditch because there are twists and turns on the way to a larger application.
I've had many people (20?) privately say to me that's what happened to them. And that's pretty much the reason for this FAQ - this happens a bit too often and there been a bit too much pain.
So, my advice is ... if your application is a little more complicated, be sure to make a conscious choice around architecture. Don't think "Reagent is all I need", because it isn't. One way or another you'll be using "Reagent + a broader architecture".
- Events are cardinal. Nothing happens without an event.
- Events are data (which means they are loggable, and can be queued, etc).
- Events are handled async (a critical decision. Engineered to avoid some
core.async
issues!). - For efficiency, subscriptions (reactions) should be layered and de-duplicated.
- Views are never imperative or side effecting (best effort).
- Unidirectional data flow only, ever.
- Interceptors over middleware. Provide cross cutting concerns like logging and debugging.
- Event handlers capture control and contain key code. Ensure purity via coeffects and effects.
- State is stored in one place and is committed-to transactionally, never piecemeal.
Hmm. I feel like I'm missing a few, but that's certainly an indicative list.
re-frame is only about 500 lines of code. So it's value is much more in the honed choices it embodies (and documents), than the code it provides.
Above I said:
Reagent, by itself, provides little guidance ...
which is true but, it does provide useful building blocks. If you do want to create
your own architecture, then be sure to check out Reagent's track
, reaction
and rswap
.
There's also other Reagent-based architectures like keechma and carry which make different choices - ones which may better suit your needs.
Up: FAQ Index