6 ms·
This problem that MVC has is similar to the problem with OOP itself, with monads, or with some design patterns: the original/popular definitions were so incredi
by whstl 1y ago
This problem that MVC has is similar to the problem with OOP itself, with monads, or with some design patterns: the original/popular definitions were so incredibly abstract and disconnected from real life usage that they ended up being whatever the person implementing it wanted it to be.
And then, 10, 20 years after the fact, people will start attacking popular implementations that differ from the original using some "new canonic interpretation" that is either extremely recent, or an interpretation that is old but was lost in time.
This is especially common around Smalltalk and OOP for some reason. Smalltalk's OOP is nothing like what existed either before or after, but since Alan Kay invented the term, Smalltalk is weaponised against C++/Java-style OOP. Not that C++/Java OOP is the bees knees, but at least their definition is teachable and copyable.
Design patterns suffer because in most explanations the context is completely missing. Patterns are totally useless outside very specific contexts. "Why the hell do I need a factory when I can use new"? Well, the whole point is that in some frameworks you don't want to use new Whatever, you dummy. If only this was more than a two-sentence blurb in the DDD book (and the original patterns book totally glosses over this, for almost all patterns).
And monads became the comical case, because they are totally okay in Haskell, but once it gets "explained" and migrated to other languages they become this convoluted mostly useless abstraction at best, footgun at worst (thinking of the Ruby one here).
- deleted 1y ago[deleted]
- aryehof 1y ago> Smalltalk's OOP is nothing like what existed either before or after, but since Alan Kay invented the term. Rubbish. In terms of OO language constructs, Smalltalk is almost entirely derived from Simula. Let’s not revise history.
- to11mtm 1y agoIDK I think it's still worth considering where certain languages 'got the right things right together' to be constructive... That said as someone fairly unfamiliar with Smalltalk I'd like an example of what other parts of Smalltalk play well with it's OOP Sauce...
- travisgriggs 1y agoFor me, one of the examples was control flow. Smalltalk had none. Or, rather, it had one: send a message to an object/receiver. It was cool that ifTrue:ifFalse: was just a message you sent to a Boolean with a closure (or two) as an argument. And various iterations as well, so you could write your own. This you can do in Swift/Kotlin/etc as well of course. Where Snalltalk went next level was that closures were objects to. And you got them to run with messages like value/value:/value:value:, etc. In most languages with anon functions/closure, you just use argument list (i.e. parens) to invoke it. But you can’t send messages to the closure itself. Smalltalk had a host of introspection methods you could send to it, different flavors of evaluation, and of course any of the ones it inherited from Object. But where it got really cool (imo), was that you could add your own methods to BlockClosure. So you could implement all kinds of control messages on anonymous functions yourself. This was cool, it was all objects, all the way down. Where “object” meant things you can add behavior to, and send messages to.
- arnsholt 1y agoTo expand a bit on why this is cool: it lets you introduce new abstractions (for example wrapping some code in a database transaction or specialised exception handling) on an equal footing with the rest of the language, all without macros.
- whstl 1y agoThis is an oversimplification, and part of the problem I mention. The "big leap" in Smalltalk was the idea that everything is an object and computation is message-passing, not just classes and instances. That’s not from Simula. Simula was more like an extension of Algol with OO bolted on. Smalltalk was a whole new conceptual model, which is not as simple to explain as Simula/C++/Java-style OOP.
- jibbit 1y agoit is less of an oversimplification than 'nothing like what existed either before or after'
- whstl 1y agoClipping the quote like that completely changes the meaning of what I said. I didn't say that. But I stand by what I actually said: Smalltalk's OOP is indeed very novel, even for today, especially compared to C++/Java, but it's also very different from Simula, especially the early Smalltalk versions. It's not without lineage (Ruby and IO) or peers (Erlang), but it's still an incredibly different flavor of OOP than Simula. This is not a slight, this is a compliment to Alan Kay. But to compare it to C++ is to miss the mark. C++ is from a different branch of OOP.
- user____name 1y agoYup, in Smalltalk a method call (message) is explicitly ignored when the object class doesn't implement it. The VM image is persistent. The devil is in the details.
- igouy 1y agoNot ignored! doesNotUnderstand: aMessage "Handle the fact that there was an attempt to send the given message to the receiver but the receiver does not understand this message (typically sent from the machine when a message is sent to the receiver and no method is defined for that selector). Raise the MessageNotUnderstood signal. If it is caught, answer the result supplied by the exception handler. If it is not caught, answer the result of resending the message within a guard for infinite recursion. This allows, for example, the programmer to implement the method and continue."
- mpweiher 1y agoHmm...have you looked at Smalltalk-72? Now Alan makes it clear that the inspiration for Smalltalk OO came from Simula (and a bit from the Burroughs 220 and 5000, from Sketchpad etc.), but to say that Smalltalk is just that is a stretch at best. The more direct line goes from Simula (Algol with classes) to C++ (C with classes).
- frumplestlatz 1y ago> with monads There are a set of three short laws that define what a monad is. I’m not sure that really fits in with MVC, OOP, or design patterns. https://wiki.haskell.org/index.php?title=Monad_laws https://wiki.haskell.org/index.php?title=Monad_laws
- antonvs 1y ago[flagged]
- frumplestlatz 1y agoI see that your comment is now downvoted into the negatives. When people are confused by something, they will often blame the target of their confusion instead of admitting to themselves that they don’t understand.
- hurril 1y agoYou both have good points. But there is monads the mathematical and programmatic concept, and there is also something a little bit handwavy in how these things are incorporated into an application architecture. The latter is what is being used on the one hand in comparison to MVC, etc, on the other. I.e.: a monadic architecture in Haskell is good, but one in Java is going to suck. A sort of half-way point is in The Elm Architecture, which is a sort of deconstructed IO monad. (Writing this as someone with decades of experience in writing monadic architectures.)
- frumplestlatz 1y agoI don’t really understand what a “monadic architecture” is supposed to mean. Haskell’s `Monad` type class is hardly the only possible encoding of a monad. They’re just a simple mathematical construction with useful properties, and — like functors and applicative functors — they emerge everywhere.
- 1y ago
- adityaathalye 1y agoMVC (and other OOP patterns) work around the fact that the language does not solve the Expression Problem. You could say, the key to getting MVC correct is understanding the Expression Problem, and designing its solution into your programming language in the first place, so you don't need MVC, but if you want to do it, it becomes actually neat and clean and modular.
- MalinGamer123 1y agoUnderstanding the Expression Problem in MVC and OOP
- tonyedgecombe 1y agoIn case anybody else wondered: https://en.wikipedia.org/wiki/Expression_problem https://en.wikipedia.org/wiki/Expression_problem
- brazukadev 1y agoThis makes no sense. MVC was created to use with SmallTalk and based on Alan Kay's OOP, of which late binding is one of 3 requirements, not static types.
- adityaathalye 1y agoWell, I tried to walk back from MVC, to the smallest possible generally composable abstraction for web app architecture, and I kept coming back to X/Y shaped tables. They're everywhere at all levels of composition; dependency injection, routing tables, joining any two modules arbitrarily, laying out source code on disk etc. etc. etc. So I built my own web app system (not a monolithic framework) to test out the opinion. And, I'd say it's working quite well---for me, at any rate. Have a gander: https://github.com/adityaathalye/clojure-multiproject-example https://github.com/adityaathalye/clojure-multiproject-exampl... See also, Polylith application architecture; a far more sophisticated and generalised form of what I'm doing in my system. https://polylith.gitbook.io/polylith/ https://polylith.gitbook.io/polylith/ --- The term "Expression Problem" was coined in context of statically typed languages, but the formulation has nothing to do with static typing per se. Its general form is polymorphic multiple dispatch (not Objects versus Functions, but Objects and Functions). See: Philip Wadler's explanation (where he coins the term): https://homepages.inf.ed.ac.uk/wadler/papers/expression/expression.txt https://homepages.inf.ed.ac.uk/wadler/papers/expression/expr... > The Expression Problem is a new name for an old problem. The goal is > to define a datatype by cases, where one can add new cases to the > datatype and new functions over the datatype, without recompiling > existing code, and while retaining static type safety (e.g., no casts). i.e. He was trying to bring the solution from the dynamic / interpreted language space, to the difficult case of statically typed languages. --- Anyway, I picture it as an "X/Y" problem. Something like this: https://www.evalapply.org/posts/clojure-web-app-from-scratch/deck.html#slide-org9e24aa7 https://www.evalapply.org/posts/clojure-web-app-from-scratch... 7.2. Solve The Expression Problem Playtime: - What if we frame everything in terms of the Expression Problem? - Add a new Y, extend all Xs to it? Without cooperation of existing Xs? - Add new X, extend all Ys to it? Without cooperation of existing Ys? | X * Y | y1 | y2 | y3 | ... | |-------+----+----+----+-----| | x1 | | | | | | x2 | | | | | | x3 | | | | | | ... | | | | | (edit: formatting)
- skydhash 1y ago> *Design patterns suffer because in most explanations the context is completely missing. Patterns are totally useless outside very specific contexts. It's hard to define how a pattern can be useful, because they're patterns, not recipes or snippets. They're supposed to fit in the reader's solution, not the author's examples. You're supposed to have the problem before reaching out for a solution and patterns are not solutions, they're models of solution, each with their own tradeoffs, costs and advantages.
- procaryote 1y agoThis is why reading a book on design patterns is more than most junior devs can handle without then spending years trying to shove extra complexity into everything to make it use said patterns Every `new` can be a factory or builder, but usually `new` is the right thing
- heisenbit 1y agoPoint in case: A singleton holding a factory to create a single instance of a fairly simple class.
- procaryote 1y agoI've seen so many singletons that just exist because java lacks conditional compilation, and you need either a test-something or a real-something. Of course I've also seen heaps of singletons that exist for no reason and could just have been a static class, sometimes because of cargo cult, sometimes because "what if we want to make it configurable later?" Such a waste of energy
- jimmaswell 1y agoI'd wager reading that book and spending years trying to shove the patterns into things is a net benefit iff you learn from it where and why the patterns were appropriate or not. I've never read one of these books, but a good one should give examples of when a pattern is counterproductive. In a greater sense, in our profession we tend to learn about new hammers by forcing them into the next (work or personal) project that vaguely resembles a nail, and I think that's largely OK if the alternative is stagnating.
- asalahli 1y ago> the original/popular definitions were so incredibly abstract and disconnected from real life usage that they ended up being whatever the person implementing it wanted it to be. This is what happened with REST too, and it frustrates me more than it probably should. The original pattern is such a good idea and not even remotely abstract. It's a well defined architectural pattern for a well defined problem yet people still managed to bastardize it to the point that the term REST barely means anything today
- whstl 1y agoThis is another good example. I remember people getting very angry here 10-15 years ago over HATEOAS. In most discussions REST has come to mean “cute URLs” thanks to Rails.
- Pamar 1y agoWhat about "microservice", then?
- whstl 1y agoThis is perhaps a case where miscommunication saved an entire industry. I once got a new hire from Uber and for months on end his complaint was that “the services are too big”.
- mcny 1y agoI once wrote a small class at work and by the time I left it was like over 8k lines long. People jokes it was my fault I called it HelperUtil instead of something more descriptive. It was a dumping ground for all the stuff people didn't want to think about. I wonder if something like that is possible in the microservice world?
- mattmanser 1y agoIt probably wasn't a joke. If you call something HelperUtil, it will become a dumping ground. That's a learnable lesson around naming, a mistake, but it's not learnable if it keeps getting described as a joke. C# accidentally solved this problem with extension methods, these little helper utils at least get grouped by type and not in one humongous file. Or maybe that was part of the design team's intention behind them all along. And because they're static you can easily see when services or state are getting passed into a method, clearly showing when it should in fact be some sort of service or a new type.
- ozim 1y agoFrom my experience patterns suffer from new devs thinking that patterns are guidelines for writing their code and that they should create code that is generic and implements patterns. (Yes if their job is implementing framework, not when their job is to use framework to build business app) Like everyone totally forgot patterns are mainly for understanding existing systems like you use a framework - hey this looks like a factory let’s use one from the framework we built stuff with instead of implementing our own. Besides of course every developer wanting to build framework so others adhere to what he built not the other way around ;)
- whstl 1y agoThe original book completely failed to communicate that, though. This is common knowledge today, but wasn’t for a long time.
- ahartmetz 1y agoI think of design patterns as possible solutions to certain problems. They should be used when the corresponding problem arises and their mental overhead is less than whatever the alternatives may be. I use them quite sparingly. I don't find them very useful (today) to understand existing systems that don't intentionally use the patterns. They don't occur very often in well-designed systems in the first place, even less so unintentionally.
- ozim 1y agoFirst of all design patterns were not some god given solutions. Those are solutions gathered from existing implementations and authors just gave names to those solutions. So they will be present in well designed systems just that they are not called by their „book name”. Then I clearly see it in all new frameworks just that each framework has their own name for implementation of the pattern. Patterns were mostly named so people can discuss easier about solutions that are there. I will quote first sentence of foreword from my copy of the book „All well-structured object oriented architectures are full of patterns.”
- 1y ago
- RossBencina 1y ago> Design patterns suffer because in most explanations the context is completely missing. "most explanations"? Most crappy explanations on the web and in introductory courses perhaps. The original GoF Design Patterns book and all of the Pattern Languages of Program Design books that followed it define and adhere to a pattern (form, template) for how to document design patterns. The main elements of this form are (GoF, p.3): 1. The *pattern name* ... 2. The *problem* describes when to apply the pattern. It explains the problem and its context [emphasis mine]. ... 3. The *solution* ... 4. The *consequences* are the results and trade-offs of applying the pattern. ... I am guessing this form comes from Christopher Alexander, but I don't have a copy of A Timeless Way of Building at hand.
- galaxyLogic 1y agoDon't overlook the "Forces". While "Problem" explains WHY you might need the specific pattern in question, the "forces" explain why some trivial solutions are not very good solutions, because you have to take into account the constraints, the assumptions about the context, why the problem is actually a problem. MVC is a great, even proverbial pattern, but I don't recall having seen it presentewd in the "Patterns Format" anywhere. Such a presentation would make it easier to understand no doubt.
- Kerrick 1y agoIt is presented in the patterns format in at least these places: - Pages 125–143 of Pattern-Oriented Software Architecture (1996) by Buschmann et al. ISBN 978-0471958697. - Pages 330–332 of Patterns of Enterprise Application Architecture (2003) by Martin Fowler. ISBN 978-0321127426.
- RossBencina 1y agoI have those books. I can confirm that your citations are correct. That said, Fowler's presentation is brief and doesn't really pass as "pattern form" in my view. POSA has its own slightly different pattern form Context/Problem/Solution/Structure/Dynamics/Implementation/Variants/Known Uses/Consequences:benefits/Consequences:liabilities/Credits(Trygve Reenskaug)
- asimpletune 1y agoI think OOP suffers in particular because patterns aren’t a mathematically defined thing like monads etc. They’re just a convention and I think that permits misunderstanding and dogmatism. It’s fine though.
- RossBencina 1y agoPlenty of confusion around monads, at least that was the case last time I checked. Design patterns are not "just a convention" they are practical solutions to often encountered problems. They are a way of extracting commonly applied, useful solutions and documenting them for reuse. If you go and read a properly documented design pattern I think it's pretty hard to misunderstand what it is, what it's good for, when to apply it, and when maybe don't. But it is definitely possible to misapply them. I'm still living in the shadow of implementing Observer, and then trying to implement undo as an Observer by translating observed events into Commands and placing them on to the undo stack. Messy.
- jibbit 1y agounfortunately this is just not true though. there was nothing abstract or disconnected from real life about MVC in smalltalk. while we're here.. this claim that 'Smalltalk's OOP is nothing like what existed either before or after' - hmmmm
- ionwake 1y agoMy whole life in the UK I spent a lot of time disappointing people with my complete lack of concern regarding OOP. Like I knew the gist of it and the patterns in similar types of code but no matter what I read I could never convince anyone I possessed the correct esoteric OOP viewpoint that they were hoping to be elucidated upon. Makes sense decades on it was all just personal abstractions
- kriops 1y agoMonads are well-defined, though. Monoids in the category of endofunctors, anyone? The problem is when implementations aren’t actually monads at all. The same goes for other functional concepts. I wrote a blog about Java’s Optional::map here: https://kristofferopsahl.com/javas-optional-has-a-problem/ https://kristofferopsahl.com/javas-optional-has-a-problem/ It’s the same kind of problem, where naming signals something the implementation is not. (Am I allowed to link my own blog btw?)
- lock1 1y agoUnrelated with GP post: What's wrong with Java's Optional? IIRC it doesn't fulfill monad axiom, but I don't think there's a huge problem with it. By the time you're using Option<>-like, I don't think you should use bare `null` at all in your project. Mixing Option<>-like and bare `null` sounds like playing with fire. Also, if you're using Java 17+ (`record` in your example), you're probably better off writing your own Option<T> to support sum-type matching & product-type destructuring.
- kriops 1y agoOptional::map returns an empty optional if the passed function returns null. This is incorrect and can be especially hurtful in intermediate operations. Allowing Optional::map to return an Optional<void> would have been correct. Alternatively, just don't call it 'map'. I agree implementing your Option<T> type is better. The problem is that people will use whatever is available in the standard library—I am not working in isolation.
- lmm 1y ago> IIRC it doesn't fulfill monad axiom, but I don't think there's a huge problem with it. By the time you're using Option<>-like, I don't think you should use bare `null` at all in your project. Mixing Option<>-like and bare `null` sounds like playing with fire. That's completely backwards IME. The whole point of Option is to allow you to make precise distinctions, and not allowing null in it when null is allowed in regular variables is a recipe for disaster. For example, the flagship use case of Optional is to make it possible to implement something like a safer Map#get(), where you can tell the difference between "value was not in the map" and "value was in the map, but null". A language that wanted to evolve positively could do something like: add Optional to the language, add Map#safeGet that returns Optional, deprecate Map#get, and then one chronic source of bugs would be gone from the language. (And yes, ideally no-one would ever put null in the map and you wouldn't have this problem in the first place - but people do, like it or not). Instead, Java introduced an Optional that you can't put nulls in, so you can't do this.
- chrchr 1y agoThe reason to use a factory instead of 'new' is that a factory can vary the return type, unlike a plain constructor. You need a factory when, based on the constructor parameters or the system configuration, different classes of object may be instantiated. I really have to disagree with your characterization of the GoF book. The premise is that it's a set of designs that can be applied when specific situations are encountered, though, granted, if you're reading the book before you've actually seen the situation where a particular pattern can be applied, it seems abstract. Certainly, popular conceptions of patterns taken out of context make that problem worse.
- scrame 1y agoyeah, they say in the introduction even that it is to give a language to common patterns that emerge in C++ style OOP. It gives examples of what it might look like, but isn't an instruction manual on what to do. Its to give a common language "this is a gateway" as opposed to "this is where stuff goes in", or "front-door" or whatever tribal names / descriptions people come up with.
- 1718627440 1y ago> a factory can vary the return type, unlike a plain constructor That's a language limitation and has nothing to do with the design pattern. You can do this just fine e.g. in Python.
- idontwantthis 1y agoYou could do that more or less in Javascript by creating and initializing different member variables in the constructor depending on a constructor argument but I would hate you for it.
- bobajeff 1y ago>since Alan Kay invented the term, Smalltalk is weaponised against C++/Java-style OOP. Often I see actual common practices of "OOP" being used as arguments against it. Which are then dismissed as 'not true OOP' by it's proponents. Only recently did I see someone give a presentation talking about not just the historical meaning of the term and it's origins but also the common practices that are associated with it and detailed some issues with it. (I'm guessing because he was tired of hearing the same defenses over and over again.)
- 1718627440 1y agoCare to provide the link for to that presentation?
- bobajeff 1y agoCasey Muratori – The Big OOPs: Anatomy of a Thirty-five-year Mistake – BSC 2025 https://www.youtube.com/watch?v=wo84LFzx5nI https://www.youtube.com/watch?v=wo84LFzx5nI
- whstl 1y agoCasey’s presentation was great, and demonstrates the problem I was talking about: a lot of those complex things lose something when they become “pop culture”. A lot of people never read Fielding’s dissertation or is aware of the monad laws but is producing bad code and bad tutorials. It takes someone like Casey, months of reaearch and 3 hours to actually dig those things out 60 years after the fact.