6 ms·
Not sure why author got the impression apple’s models had to be « dumb data containers ». Actually, having dumb models is the surest way to completely screw up
by bsaul 3y ago
Not sure why author got the impression apple’s models had to be « dumb data containers ».
Actually, having dumb models is the surest way to completely screw up your controllers design, since you’re now left with no other places to write your business logic in. This leads to either weird trees of controller inheriting each other for the sake of reusing some data processing piece, or singletons everywhere which makes the code super hard to reason upon, not to mention harder to unit test.
My take on the model layer is : write everything that’s not strictly specific to your UI there.
- vsareto 3y agoWe really need to call it Model-View-Controller-Service-Repository and be done with it. That is actually what happens 99% of the time. Logic is done within services and where the complex dependency graphs live. Repositories do the data retrieval. The controller is a traffic cop. The model is a data transfer object with maybe some calculated fields. The view makes things pretty.
- gabereiser 3y agoLol, but MVCSR (MVCaeser) sounds like an architectural dictatorship where one must follow all rules or else be outcast from citizenship. Where some executive will stab you in the back and sell it to a private equity firm to be cut and squeezed by all the lands and your intentions and beautiful code structure is murdered by junior bootcamp devs. /s
- LeonB 3y agoThe problem with the MVCaesar pattern is that sooner or later a Basic Routing Universal Transformer User Service stabs it in the back.
- gabereiser 3y agoIronically named Optimus.
- IggleSniggle 3y agoNot a MCSVR (McServer)?
- nightpool 3y agoNo, please for the love of god stop writing services. Having random grab-bags of methods makes it infinitely harder to find what code lives where, instead of putting it into models where we have 20+ years of OO design principles (single responsibility, open to extension, liskov substitution, interface segregation, etc) to guide us. "Fat models, skinny controllers" is a Rails guiding principle for a reason
- ebiester 3y agoUntil the moment that models have to call other models to get anything done. The problem is that the models often get too tied with the database implementation. Then, you're separating business logic that doesn't make sense to separate. The fat model ruins single responsibility because the database table is not a good proxy for one reason to change.
- LeonB 3y ago> models have to call other models. “You're very clever, young man, very clever," said the old lady. "But it's turtles all the way down!"
- deleted 3y ago[deleted]
- regularfry 3y agoThis is a specific problem with the Active Record pattern, rather than something intrinsic to MVC, and it's exactly why AR is fine for simple apps where the business logic looks a lot like manipulating a row in a database, but breaks down for anything more involved. But also there's no reason you can't have non-database-backed classes sat next to AR models, if they make sense in the domain. Not everything needs to be a database row.
- ebiester 3y agoWhat, then, is a service other than a model without a database table?
- KronisLV 3y ago> Model-View-Controller-Service-Repository Where would you put validation logic, though? I mean, some of it might need to just check whether a domain object has its fields filled out, but other validations might need to cross reference DB data to make sure that everything is valid in accordance to the business rules. Ergo, we might have Model-View-Controller-Service-Repository-Validator Even without being silly, it's interesting to see how different languages and frameworks handle common concerns, for example, with some you will have repositories, with other the model objects themselves will handle queries through some ORM.
- pravus 3y agoValidation logic needs to be spread throughout the system because your validations are all context sensitive to the operations being performed. It's not always possible to front-load that into a simple schema in your transports and each component needs to be correct in its own domain.
- KronisLV 3y ago> Validation logic needs to be spread throughout the system because your validations are all context sensitive to the operations being performed. While it certainly isn't always possible, I've definitely seen it be aggregated in a single place in monolithic codebases that focused on CRUD. Essentially, it was structured like so: +--------------+ +------------------------+ +-------------+ |Resource (API)|---|Service (business logic)|---|DB Repository| +--------------+ +------------------------- +-------------+ | \ +-----------------------+ \ +-----------------+ |Validator (validations)| \|REST clients etc.| +-----------------------+ +-----------------+ The Resources were typically just API endpoints (HTTP), that passed data onwards to Services. Those could then call upon other services or service requests on their own: store/persist data with Repositories, deal with scheduled processes, or pass data on to other systems through REST clients etc. Before Services did any of those, they reached out to a Validator to make sure that the data matches the business rules and constraints. Sometimes there was additional validation context passed in (essentially a map and some enums), sometimes there were certain constraints that an entity needed to always follow within the context of the business and so on. In practice, it was good because you could see all of the constraints in one place, that an entity has to match before it can be persisted in the DB, or passed onwards to another system. But then again, that's not always viable in more modern architectures. Of course, it wasn't the most traditional approach to MVC either, even if those concepts translate pretty well to it.
- strken 3y ago> My take on the model layer is : write everything that’s not strictly specific to your UI there. My take is this, except with the caveat that the larger a model gets, the closer to declarative it should become. You touched on this by saying the model layer rather than just the model, but it's worth emphasising. You can achieve this by abstracting out the messy bits, e.g. moving some hooks to a task queue (processing an image) and others to a declarative helper (validation as a schema instead of functions), turning a massive querybuilder jumble on one model into a library that lets you declare valid search and ordering by fields and operators for all models, etc. When a model becomes too big to fit in your editor window is probably a good time to start getting rid of most of its procedural code. One of the old Rails aphorisms was (and may still be) "fat models, skinny controllers", and while this was better than the alternative it still led to a lot of 500-line monsters.
- jfengel 3y agoHeh. "500”. I have had monsters ten times that size. And yet it wasn't obvious that refactoring was really an improvement. Sometimes the program is just big and does a lot of things. It's not good. It's a disaster waiting to happen. And yet until it does the code smell can continue to smell without strangling anybody.
- bsaul 3y agoYes, there's definitely a confusion in the meaning of the word "Model": All objects belonging to the model layer don't have to match a data type. For an online shopping app, you may have an "Item" object, but your purchase logic may be in a "Purchase" service object, which needs a "PurchaseRestAPI" to perform HTTP calls, etc.. They all belong to the "Model" layer. Correctly structuring your model layer is the key for a maintainable application. The problem with most mobile developers is that Apple has been demoing a lot of features on the view layer (because of the cool UI effects the user sees), but it's something that has to come in the end. First you need to model your domain logic properly. Then you can see how to represent it on a given user interface.
- usrusr 3y agoBut dumb, passive data structures still have their place in that "Model", and unfortunately, those are usually referred to as model. Note how I picked up your quotes and capitalization for the former, that's very helpful here. This is really where I see the root of why MVC is such a useless term: the "view" feels intuitively unambiguous, there's always something that is very tempting to declare model and everything else will either be declared controller in one broad sweep or assigned to one of the other two in an elaborate act of design-by-committee (even if you're all alone and it's only the different positions in your head). Personally, I've made it a pet heuristic to blanketly assume the worst whenever I hear MVC. Perhaps there's good code out there despite its makers trying to find salvation in those troublesome letters, but I assume the false positive rate to be acceptably low.
- gymbeaux 3y agoThe end of this rabbit hole is probably something like “actually DDD is best!” or whatever comes/has come after DDD (domain-driven design)
- ysavir 3y agoThere's two definitions these days for the term "model" in MVC: 1. An object that models part of the service/product. Meaning, not something related to the operation of the medium by which the service/product is delivered, but any operation that models the service/product itself, independent from medium. This could be a representation of a DB row, a service object, a decorator, or any other piece of logic that relates to what you do. 2. An object that reflects a DB row, but not anything that represents other parts of the service/product. I don't know the full history, but probably connected to the rise of ORMs and Rails, and when devs got in the habit of throwing almost all product logic either into controllers or Active Record models. And when you want to start putting the bulk of that code in dedicated, non-DB files, you have so many active record files that you don't want to muddy up the `models` directory with non-DB code too, so you create other directories alongside `models`, `views`, and `controllers` to house the other files. The author may have been using definition 2, where models are strictly seen as DB-related code, and having them be "dumb data containers" is useful as it enforces extracting operational logic to classes better suited for that logic. But since they get put in other directories, they aren't seen as "models", despite technically still belonging to the "model" part of MVC.
- regularfry 3y agoDef 2 is actively bad and wrong, though. It happens to fit simple apps (and simple bits of complex apps) so it looks reasonable, but what's really needed is an off-ramp to let the model actually be what it should be, which is a domain object. Active Record is an optimisation that by rights ought to be premature, but the downsides don't start to bite until a certain complexity threshold which a lot of apps might just never hit.
- ysavir 3y ago> Def 2 is actively bad and wrong, though. It happens to fit simple apps (and simple bits of complex apps) so it looks reasonable, but what's really needed is an off-ramp to let the model actually be what it should be, which is a domain object. I somewhat agree. The problem, I think, is that MVC is great at explaining the types of contributing code to a software project, but it doesn't lend well to a directory structure in a project. There are just so many more models compared to controllers/views that it's logical to make each type of model object be its own top-level directory, along with controllers and views (well, top level within an `app` directory, as is custom in a Rails project). So you end up in situations where people either have a "Model(record)/Service/Decorator/OtherModelPattern/OtherModelPattern/OtherModelPattern/Controllers/Views" system, a system where all the domain logic is put into ORM classes, or a system where all models are organized within the `models` directory, but possibly interfering with the intuitive file lookup of the framework (eg, if you tried putting all active record models in an `app/models/records` directory and having a huge break from Rails tradition). If Rails simply used "Record" instead of "Models" for the directory name, a lot of this could be a lot clearer, but we're now what, 18 years deep into the muddying of the MVC waters? As much as I'd love to see a return to using MVC properly, I'd rather concentrate on doing more productive things.
- hardware2win 3y ago>Actually, having dumb models is the surest way to completely screw up your controllers design, since you’re now left with no other places to write your business logic in. There is such a place: model
- mpweiher 3y ago> apple’s models had to be « dumb data containers ». They don't "have" to be, but that's very much the result of what Apple has been advocating, what the community tells itself and what happens. > Actually, having dumb models is the surest way to completely screw up your controllers design, since you’re now left with no other places to write your business logic in. Exactly. And the coordination logic. Alas, that is exactly what happens, and I've been in enough of these codebases. It's actually a bit more complex than that, as what people seem to aspire to is write self-contained widgets for their functionality, essentially slicing the application vertically most of the time. And that appears to have a bunch of causes, for example the PM->Design->Engineering process chain that also appears to be standard (and broken). > My take on the model layer is : write everything that’s not strictly specific to your UI there. YES. UNDERLINE. BOLD. BLINK. Repeat 100 times. Say it loud. Sing it. Shout it. The "Model" is an object that is the headless application. It implements and coordinates all the functionality. You put a thin GUI on top of that. Or a different GUI. Or an API. Or a WebUI. Or a CLI....
- whstl 3y ago> The "Model" is an object that is the headless application Wow, that's a great mental model (wink) to have. I never thought of it in those terms, but I think I do follow it, mainly because I tend to follow John Ousterhout's guideline of "Deep Modules, Small Interfaces". This way the model ends up being exactly what you're talking about. It is testable, issues are easier to reproduce, it's easier to reason about, it is portable to other contexts: server-rendered web app, JSON API, GraphQL API, desktop app, mobile. I think the biggest obstacle for people using popular frameworks is realizing that a "Model" doesn't have to be necessarily one single class. The important part is having a model-like API that is good and self-contained. Previously I didn't have a mental model for what is "good" but with your comment I think I can put that into words a little better. One of the biggest problems I have with Services and other patterns such as Operations, Interactors is that developers often couple them to Controllers and Views. Also often I see duplication happening when new patterns are added because they're seen as separate. If you think of them as "part of the model", however, and follow the "the model layer is its own headless application" those issues have a smaller chance of happening.
- 3y ago
- resonious 3y agoPersonally I kind of like dumb models. Dumb models means I don't have to think too hard about "a.affect(b)" vs "b.be_affected_by(a)". I can just write functions that do what I want right now. "do_my_thing(a, b)". No reason to be doing anything else when programming. If you have people making controllers inherit each other just to share functionality then they're probably brainwashed by OOP. Stuff like inheritance and mixins only exist to solve fake problems that make no sense outside of C# or Java. To me, singletons and plain-ole-functions are pretty easy to deal with in most languages - I just ask the editor where a function gets used or where it's defined. If your language doesn't support that kind of thing (looking at you, Ruby) then again that's another problem caused by tooling.
- pas 3y agodata objects have to be dumb, the managers don't. both C# and Java can be used in a sane way, but ... at what cost, right!? C# is tied too much to the regular MS circus, and it's just a few more years and Java will finally be great! oh wait. of course, actual, real-world walking-talking problems can be solved in both of these ecosystems, but ... almost always the real constraints are not the actual language. (... trying to do HFT with a JIT-less language, or some other faux pas)