But MVC? That's pretty minimal in terms of what you're going to do anyway if you have functionality (model) and will be interacting with it (view). Controllers are often misunderstood, and in the case of Apple massively misapplied (Massive View Controllers).
The thing is that, whatever definition you use, you should have almost all of your code in one of those layers, a small minority on another, and shouldn't even remember exactly how to change the other (unless you start many projects). If that's not the case, your code architecture is working against you.
So for example Views in Cocoa actually fulfil both the View and (largely) the Controller role.
Which is why ViewControllers confused me greatly when they came out. Like they confuse most of the Apple-ecosystem code out there these days. While I do understand how they got there, that doesn't make it better...
offtopic: love your blog!
But in all the other cases, they just make everything more complicated and harder to understand.
I've once worked with a messy codebase, it was written in a very "naive" way, but that was also the strength of that code. Every view was in one file, every action was just one method, so you exactly knew what code was executed when. We tried to refactor it, but it became complicated really quickly (the domain was really complex), so we decided to just adopt to the style. We only split up components that became to big into smaller components, sometimes decoupled things a bit, but most of the time just kept all the logic.
And this product is successfully in use for over a decade now.
Yes, yes, and YES!
This is something that confused me greatly over the last years: teams/companies I was in contact with were really struggling getting MVC to work (never mind MV*) and I wasn't...but I wasn't doing anything special, at least not that I could tell.
I would implement my model, TDD-style, put minimal views on top, possible add a view-model here and there if there was some display-specific logic that was complex enough to warrant more extensive testing, voilà.
It was only recently, partly when working with some teams that were doing modularity for modularity's sake (and MVVM for MVVM's sake), and partly when writing down Blackbird[1] that I really noticed the per-view thing.
Don't do that.
>"headless browser" variant of your app
Exactly. Do this.
The app is an object. It has an API. It knows how to coordinate its pieces. The local I/O, the remote I/O, any timing stuff. All of it. Then you plonk the UI on top of that. You can have sub-parts, but you need one piece that ties it all together, on the model side.
> Same trick is impossible or very difficult to do with MVVM.
Well, it's impossible with the misapplication of MVVM that is common today. A view model is a perfectly fine addition if you have some complex but fairly presentation-specific logic. And you put that in a testable model that is fairly tied to one view.
Instead, people have used MVVM to double down on their view-centric misunderstanding of MVC, with anemic models that know just enough to service a specific view.
Meaning any kind of cross-app logic can't go in the model. Meaning it is going to go into the view parts (or rather: the misnamed and misapplied controllers). Which is exactly where it has absolutely no business whatsoever being.
Sigh.
[1] https://blog.metaobject.com/2022/06/blackbird-simple-referen...
Please forgive the lack of background of this next question, but does this mean you do not support BFF pattern?
Have you heard of Dubray's SAM (State-Actor-Model) approach?
Curious about your replies and thank-you for your time.
Let me present: Kotlin Multiplatform Mobile[0] (or KMM, a real mouthful I'll grant you). Something I'm very excited about, because you could do exactly that. Seems like an interesting thing to keep an eye on.
From my limited, surface understanding, that is what KMM reminds me of: a way to define UI in Java, which means the entire stack could be in a single language (or mix of JVM languages).
Yes, exactly that. Not my idea, of course. See for example Hexagonal Architecture. Or good old NeXT Enterprise Objects Framework, later extended by WebObjects.
> Have you heard of Dubray's SAM
No I hadn't, thanks for the tip!
He identifies one of the core problems with how MVC is incorrectly applied:
"The core issue here is [that in] traditional MVC, the action (controller) would call an update method on the model and upon success (or error) decide how to update the view. "
https://www.infoq.com/articles/no-more-mvc-frameworks/
However, he incorrectly claims that this is "traditional MVC". It is not. In fact, traditional MVC clearly forbids this, as it states that the View updates itself from the model. The View is active, you don't push data to the view.
Model -> View communication is a notification. That's it. (This is also how it is implemented in Smalltalk MVC, which is the prototypical and archetypical MVC implementation).
It feels to me that the database tends to be more stable over time than the application: frameworks, design approach, and architectures come and go, but tables, stored procs, and views have always been there.
That said, supposing we were to start with the data model and many business rules expressed in the database first, would you reach for GraphQL to help the app manage the data it needs, or acquiesce custom db objects to provide the required data?
With SAM, I thought there would be a way to avoid BFF, while conforming to a TLA+-ish way of enforcing (the model's valid) states at all times.
I know I am handwaving a lot of ideas. Just wanted to get your input on the backend side of things.
Thank-you.
> Exactly. Do this.
> The app is an object. It has an API. It knows how to coordinate its pieces. The local I/O, the remote I/O, any timing stuff. All of it. Then you plonk the UI on > top of that. You can have sub-parts, but you need one piece that ties it all together, on the model side.
This is exactly what I did with all projects I've worked on. It helped that I had to target both, iOS and macOS where sharing "business logic" was crucial, so you were kinda "forced" to think about that.
To put it simply, there is one question I'm asking myself, can I delete UI and then rewrite it from scratch without updating non UIView/NSView code (just calling MyClasses i.e. my APIs)? Let's just say, if I have to write NSSortDescriptor again, that means there is an architectural issue with my code, which has to be fixed.
Reading your comment, I have the impression you took it as "there shouldn't be any state management necessary", instead of "state management doesn't need a framework" sense.
"Why use a widely popular, well-documented, battle-tested framework? Just have one of your senior devs build something over the weekend. This will definitely reduce complexity."
Like... I get what you're saying. But "build your own" is not a default answer for an extremely complicated software engineering topic (which, yes, state management is!)
But, that led to the community building hundreds of addon libraries for the same sets of use cases, which is what led us to build our official Redux Toolkit package to simplify standard Redux usage patterns.
Did you mean to reply to a different comment?
Quoted from the comment they're replying to.
> [..] maybe “state management” is not something you need a framework for?
Quoted from their reply.
To me it seemed like the comment was attacking its parent for investigating state management frameworks in the first place - when it in fact called out "no framework" as a valid alternative to any number of frameworks.
(I hope that made sense)
- https://blog.isquaredsoftware.com/2022/07/npm-package-market...
Digging deeper, it seems to me that attempting to subvert the standard behaviour of the DOM will always produce a leaky abstraction, and it negates the benefits of working on a standardised platform.
I'll definitely agree that Redux _has_ been overused.
But it's also worth understanding _why_ Redux was created in the first place and why it got so popular.
As a brief recap: the first major wave of JS MVC frameworks had major flaws. Angular's dirty checking didn't scale and was impossible to debug. Backbone's event-based system led to events ricocheting around the app with no way to trace what would happen when a given value changed. Additionally, manual DOM manipulation made it hard to manage ongoing changes to the UI over time.
This led to Facebook designing React to let devs write encapsulated components with predictable output and behavior, but React didn't have a solution for larger global state. Facebook later announced a "Flux Architecture" concept that tried to make larger app state updates predictable through centralization.
The React community ran with this idea and produced dozens of Flux-inspired libraries. Redux took the ideas from several of those Flux libraries, and applied Functional Programming principles, with the goal of making it easier to understand when, where, why, and how your state is being updated and changing over time.
The community then adopted Redux because A) it was the best of all the Flux implementations, B) it _did_ address the issues people were running into around state management, C) it was designed to work well with React, and D) it also incidentally helped work around limitations in React's original Context API. (I've talked about the original intent and purpose extensively in my blog posts and conference talks [0] [1].)
After that, yes, Redux _did_ get shoved into many applications that didn't need it, in the same way that React has been used for many sites that didn't necessarily require that setup.
So, we've always recommended that people actually take the time to evaluate the specific problems they need to solve in their app, and make an informed decision on whether Redux is an appropriate solution for those problems [2].
Beyond that, we've specifically designed and built our official Redux Toolkit package [3] [4] to eliminate the old "boilerplate" concerns. "Modern Redux" with Redux Toolkit and React-Redux hooks is _much_ easier to learn and use than the original Redux patterns, and we get highly positive feedback on a daily basis from folks who enjoy using RTK. We also built an "RTK Query" data fetching and caching API [5], as data fetching is the most common thing that apps need to do today.
[0] https://blog.isquaredsoftware.com/2017/05/idiomatic-redux-ta...
[1] https://blog.isquaredsoftware.com/series/presentations
[2] https://redux.js.org/tutorials/essentials/part-1-overview-co...
[3] https://redux.js.org/introduction/why-rtk-is-redux-today
[4] https://blog.isquaredsoftware.com/2022/06/presentations-mode...
I never did really complex frontend applications, but once I used React Query or SWR most of the needs for global state were gone. And so the need for Redux.
Can someone explain this to me please? How is it possible, that Facebook, did not have a plan from the beginning for a larger global state, even though their own app is huge? How did they solve it in Facebook in the first place? or did they started using React for themselves AFTER solving the global state problem somehow?