What are everyone's thoughts on a single global state input cell with a map of values, like is done often in Reagent, vs a lot of input cells w/ state. I get the pros and cons of each, but what are other people doing? The bad news (or maybe limitation of my knowledge) with a global state map in one cell seems to be that your downstream formula cells can't live in the same map. I've found myself preferring a bunch of input cells in my current application because of this, but I would love some input from others on a "best practice" you have found.
I used Hoplon in a large code base at my last job and it was mostly like that - lots of individual cells. I always wanted to consolidate our state more so that the updates could be more clearly atomic. I found myself worrying about the states of various cells defined in different namespaces. It reminded me of imperative programming patterns, which felt backwards to me as an Clojure programmer. That said, we avoided refactoring and the "many disparate cells" thing wasn't too unwieldy. I just wonder what it would have been like if we had fewer cells - I suspect it would have been easier to manage. This is probably one of those things where there isn't a "one size fits all" answer. You should experiment with consolidating multiple related cells into one and see how you like it. In the few places where I used that pattern, I thought it felt pretty good.
Great feedback, Dave. There’s a little comfort in knowing that others have felt the same and struggled with the same.
I wouldn’t say that my application has become unwieldy yet (thankfully). But that feeling that I wasn’t getting it right, or maybe that it wasn’t quite Clojure-y, was always nagging at me.
All this said, there’s something I love about the feel of Hoplon even after having built, reframe and reagent applications.
A great thing about Hoplon is that it isn't opinionated. You can use many cells, or one cell, or something in between. 🙂
part of the friction i think with lots of little anonymous cells is, despite being anonymous, they participate in the implicit global lifecycle of the cells they're wired to. so there's a kind of hidden namespace at work which can be a source of leaks and confusion about effects sort of like the problems you can have if you open files or sockets in functions without cleaning up, inside lambdas or whatever
in the past we've thought about using weak references or tying in to the newer DOM lifecycle events, to automate cell de-alloc and detach at the time weak references weren't widely supported, and i think the availability of the DOM stuff succeeded our efforts today there might be some way to make little anonymous cells more wieldy, though alternatively, could take it on as a visualization problem, and tie into the debugger or make a browser extension or something to better understand where all the cells are and what they do
Adding my 2 cents, I love the idea of one single input cell, I worked on big re-frame codebases and it was great. That said, every time I start a hoplon project, I always create many input cells. Sometimes I merge those when I need atomic updates but most of the time many cells are what I prefer.
@mynomoto that resonates here. The reframe apps I've worked on in the past have me feeling the same way. But with Hoplon, the best "feel" continues to be more individual input cells
I'd be curious to drill into this more. It seems to me like the experience going "either way" in Hoplon is pretty good. Meaning, you can start with many cells and conglomerate them into fewer cells as needed. Or you can start with one cell and derive smaller, "targeted" cells from it. Either way, you can use formulas and lenses to derive the representation that you want in various places. I'm curious if there are any limitations with one approach that would make the other one better.
My main thought on this is that if you define many cells and allow them to be settable from other namespaces, it can potentially turn into spaghetti because you have to understand / worry about what other pieces of code might be changing the cell values unexpectedly. It's the same principle behind immutable values in FP. You want to limit mutability to keep yourself sane.
Maybe I'm thinking about this the wrong way... Even if you just had 1 cell, you would still need to worry about what other pieces of code are mutating the parts of it.
I've even considered a namespace for the state and keeping the cells there (waiting for people to scream "DON'T DO THAT!")
That actually sounds reasonable. At my last job, we had a "global state" namespace where we put cells intended to be shared between other namespaces. It made it easier to understand what cells were potentially used in a lot of places.
It wasn't a black and white thing, though. We also had "public" cells defined in other namespaces and accessed from other places, and I think that made sense sometimes.
You have to think about a cell as being like a variable (or let's say an atom) that you define in one place and then expect for it to modified from other places. The challenge is to do that in a way where you can hold in your head all the places where the cell might be modified. I think to be true to FP principles, you should limit those modifications as much as possible.
> I'd be curious to drill into this more. It seems to me like the experience going "either way" in Hoplon is pretty good. Meaning, you can start with many cells and conglomerate them into fewer cells as needed. Or you can start with one cell and derive smaller, "targeted" cells from it. Either way, you can use formulas and lenses to derive the representation that you want in various places. I'm curious if there are any limitations with one approach that would make the other one better. @dave Yeah, hoplon works great either way and I believe that @campeterson is trying to understand the tradeoffs of the extremes. After a project is "big enough" it is hard to go from many small cells to a single cell as you mentioned as your experience. I think the same would apply in the case moving from a single cell to many cells. If we knew and agreed what way is best it would be better start that way.
On my last re-frame project we had one single namespace for all subscriptions and one single namespace for all effects. I liked to work that way as it was simple to check if something already existed before creating another one. I think having one namespace for cells could work in a similar way.
One thing worth considering is that sometimes you want to limit the scope of the state you're working with. A real world example from my last job is that we had separate namespaces for separate pages, forms, etc. Each page/form had its own isolated state that the rest of the application didn't touch. For example, there might be a set of form controls that we would hide unless you checked a box. For that sort of thing, it's nice to have an individual, private cell in that namespace called something like show-controls?. So there are some things where it's more pragmatic to have separate cells, instead of trying to put the entire state of your application into one cell and sharing it globally.
I think the lesson here is that when you have a piece of state, you should think carefully about whether it should be isolated / limited in scope, vs. shared globally as part of your application state "supercell". It's really a matter of preference, but I think both approaches make sense in different situations.
Thanks for all the discussion on this. I'm going to try a couple iterations and see what feels best. All-in-all, this app is fairly small in size, so it should be relatively easy to test out which approach feels best. It's also given me a few ideas to how I can scope the state appropriately.
Sounds great!