DEV Community

Discussion on: Redux is half of a pattern (1/2)

Collapse
 
xstos profile image
Chris C • Edited

I inherited a react/redux app here at work, and I found the organizational structure really hard to follow due to how everything was coupled. It had code smells all over it. The ideals were good, but the implementation left a lot to be desired.

Code is for people to read, so if patterns are confusing I disregard them and ignore "the experts". Amusingly the best and most understandable software pattern i've happened on in my career has been a mix of all these patterns.

C# has part of the answer with extension methods. You define data inside classes, and then create transformers (extension methods) between types (basically your entire codebase is a giant LINQ library). If the data being operated on is immutable, and you undo all the mistakes the OO architects created by getting rid of nulls, using discriminating unions, not using exceptions (or wrapping them at the lowest possible levels) and much more (fsharpforfunandprofit.com/fppatterns/) you end up with really modular code.

For the UI you use a hydrid model, where you make your datastructures implicitly serializable (as lispy as possible) with react-ish UI generator functions to render atoms of UI (again you end up with a LINQ library of functions to build UI very similar to react but without needing the jsx syntax). If you memoize the important bits, then your UI doesnt get recreated over and over. I then use a global event pipe for all the events. It all works great.

The only problem is, I've met precisely zero people that program this way, by stealing a bunch of patterns and mashing them together. FP abstractions sometimes get so into the weeds, that it's hard to read, so you have to strike a balance between all these aspects, by continuous refactoring and no upfront design. This is obviously really hard with more than one developer as the bad habits everybody has breaks all this stuff in a myriad of ways.

Rich Hickey has a talk where he states "simple is hard". That's what I do. I make everything so stupidly simple, it's modular as hell. Then I go to work, and get inundated with OO spaghetti code, and it saps the fun right outta life...

Collapse
 
oliverradini profile image
OliverRadini

Do you think that Redux falls into the bracket of complex and easy, rather than difficult and simple? (to use the categories defined in Rich Hickey's talk)

For me, it falls very much within the bucket 'simple and difficult'. It has a single representation of state, which is a value. State can only be updated by reducers, which are pure functions. Reducers can only be triggered by actions, which are just data.

I'm struggling to see what part of that is complex, and I've spent a lot of time trying to think about whether or not Redux is simple or complex. How it gets integrated with React components might be a little more complicated on the surface, but again this is basically always done using higher order functions, which are an abstraction of sorts, but relatively straight forward.

Please do correct me where I'm wrong because I'm not trying to just pick holes in what you say here, I agree with the rest of your comment entirely, I'm just trying to objectively question where Redux falls along the simple-complex spectrum.

I found that Redux became a lot more appealing to me personally once I sat down and properly read the paper 'Out of the Tar Pit'. I like the idea of silo-ing state and restricting its manipulation to a subset of a language.

Collapse
 
xstos profile image
Chris C • Edited

Hmm good question. I think the conceptual model is definitely simple, but as you say, since it's only a piece of the pattern, many devs opt for obtuse boilerplate (ignoring DRY), rather than buckling down to build higher level abstractions to achieve KISS and make code easy to reason about and navigate/digest. They are afraid to write utility code, or code generators (because it's perceived as hard) to essentially be as lazy as possible and write the least code. So they are lazy and wasteful instead and accrue tech debt and increase illegibility. Most devs don't write their code for humans to read with the simplest conceptual model. I love plain functions. Simple data, single argument, no side effects, simple data out. Most code should literally look like an excel spreadsheet. Classes are table rows, lists of classes are tables, formulas are static mapping methods to new tables. Unidirectional and simple.

My gut blames encapsulation as well. If one can't easily open an engine, and mod it, then we get these weird unreadable codebases like Dan Abramov was referring to. Everybody is solving a small slice of the problem and a lot of the problems internal to the project are hidden and not exposed to the community. I noticed this when I re-implemented entire utility libraries that I later noticed Microsoft had in their own reference source (often with the same signatures), but had not shared. So we get all these npm snapshots of pieces of the problem and people repeating the same solutions all over the place and they're hard to hook together and model cohesively. A big pet peeve of mine is that all code should be public and modifiable from anywhere. Swim not dive.

I suspect encapsulation doesn't scale well, because when one is 200 levels up from a problem (the npm packages folder depth is insane), perspective is lost. My gut says that if there was an R&D group that built an app from the ground up modeling everything like a physicist would, be it temporal logic (reactive extensions), asynchrony (promises), UI component models like react, the mapping of state to UI with redux, the low level rendering of graphics, etc. All those things would need to be in the same codebase to evolve together (as a modelling exercise). The fact that our dev environments don't come with hygienic macros or simple code generators built in (controversial I know), means we can't create DSLs to solve all our issues with minimal bloat when the libraries don't quite capture our requirements.

Unfortunately the difficult nature of code sharing and collaboration fragments this and separates concerns that perhaps shouldn't be separated. Not sure much of this diatribe helps anything though D:

PS: I am not a DRY extremist, I lazily model problems by how many times I see code repeating. Ad-hoc, on the fly with little forethought. Only when my bad code spidey sense tingles, do i step back and think about things. The repetition hints at missing conceptual models and informs what abstractions I create. This is really hard to do collaboratively however, as it requires training people to use a ruthless refactoring algorithm while they code. I still haven't had any luck teaching people how to do this at scale. I've never really taught people anything en-masse, so i'm sitting here on my high horse when perhaps I should be trying to convert a few people at work and see what comes of it. :)

Collapse
 
luiz0x29a profile image
Real AI

Redux is simple like assembly, which is not good.

Collapse
 
luiz0x29a profile image
Real AI • Edited

Actually, patterns are an anti-pattern that demonstrate clear as the day that the language is failing at modelling what should be modelling clearly and in a syntactical and understood way.

As someone who studies programming language development, every time I see pattern, I see a broken programming language or library.

Now knowing that, you are never going to be seeing patterns the same way for your entire life.

We shouldn't need to have patterns, we should be able to express an idea directly.
English doesn't have patterns, does it ? it has syntax, and semantics, but no pattern (well, it has some, but mostly they are legacy, we just ignore them anyway)

Collapse
 
luiz0x29a profile image
Real AI • Edited

" I've met precisely zero people that program this way. "
Meet me, you have 1 person now.

Come over to F#+Fable, we have more persons, and we are trying to do a thing here.