whstl
3 days 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).
ozim
3 days ago
From 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 ;)
ahartmetz
3 days ago
I 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
3 days ago
First 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.”
bluGill
3 days ago
Everything about object oriented from the book was added by editors because OO was the fad at the time. Most of the patterns apply to other styles of code. The authors were not confined to studying OO programs
ozim
3 days ago
I don’t think we are writing about the same book: ”Design Patterns: Elements of Reusable Object-Oriented Software”.
That’s the one I write about, it has foreword from Grady Booch and was tied to OOPSLA meeting with C++ and Smalltalk examples. To add OOP stuff to it sounds like a different book because that book is about OOP by definition.
bluGill
3 days ago
That book. The title was not from the main author.
ahartmetz
3 days ago
AFAIK, the title is never chosen by the author (except maybe for the most successful ones)
bluGill
3 days ago
Pretty much and so you need to be careful about what you state about any book based on title. Though most of the time the title doesn't mislead this baddly.
of course at the time they really thought nobody would question if oo was the best way to program so it didn't seem usefully misleading. Patterns apply to non oo programning as well
user
3 days ago
whstl
3 days ago
The original book completely failed to communicate that, though. This is common knowledge today, but wasn’t for a long time.
user____name
2 days ago
The biggest problem with "design pattern thinking" is that it suggest the solution to a given problem is always another abstraction.
asalahli
3 days 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
rendall
3 days ago
Unfortunately, Fielding's dissertation itself alone gives inadequate guidance to construct or even fully identify a REST API, and so a over the subsequent years a mishmash of sometimes contradictory blog posts, discussion forums, militancy, angry flame wars, and books fleshed out the REST.
The 2007 book RESTful Web Services was wildly influential in popularizing the standard by clarifying and presenting a set of further guidelines or constraints that it called Resource-Oriented Architecture.
LegionMammal978
3 days ago
As far as I can tell, he's not even describing an "API" as we'd normally use the term today. For all practical purposes, it's pretty much just "using an HTTP server and hyperlinks to let (human) users discover and interact with resources". (Or replace "HTTP" with another protocol like it in all but name.) If it has any structure past that, then it's not REST in his sense.
Personally, I think "API" is an unclear term for that kind of structure. The only actual interfacing is the HTTP protocol between the server and web browser. But the browser traditionally only acts as a proxy for the user, who is the one being served access to the resources.
whstl
3 days ago
> As far as I can tell, he's not even describing an "API" as we'd normally use the term today. For all practical purposes, it's pretty much just "using an HTTP server and hyperlinks to let (human) users discover and interact with resources".
Bingo.
Like Monads, it mostly later interpretations missing the mark.
maleldil
3 days ago
How does this relate to monads? They have a proper definition of the signatures required and the laws they must obey.
whstl
2 days ago
I said “Later interpretations of Monads”, I did not say “monads”.
Fielding’s dissertation is fine in itself. The web itself, AtomPub, OData, among others, all follow REST and HATEOAS.
Same for Monads: the laws are fine and the implementation in Haskell is fine, but meme tutorials and later implementations miss the mark.
whstl
3 days ago
This 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.
mcny
3 days ago
I don't know who is to blame for this -- I think it should be the entire team, not just the developer for every time I click a link from a message somewhere on my phone and a website opens which opens an app and it says "congratulations, you have performed this operation (that isn't idempotent)". Like ok, but why are you doing stuff with a get action... Shouldn't you prompt people to ask in the app hey I am about to do something, do you want me to?
Pamar
3 days ago
What about "microservice", then?
whstl
3 days ago
This 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
3 days ago
I 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
3 days ago
It 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.
XajniN
2 days ago
You’ve never seen `public static class Extensions` in a project named Something.Shared?
whstl
2 days ago
In the microservices world this is the monolith itself sitting in the center :/
Even in architectures that start as distributed, I’ve seen the “involuntary monolith” arising.
Way too common, unfortunately.
ssdspoimdsjvv
3 days ago
Of course, it just becomes the HelperUtilService!
pjmlp
3 days ago
Same thing, a typical OS has tons of microservices talking over OS IPC.
Sun RPC was microservices.
But understanding they are several decades old concept isn't cool, doesn't sell conference tickets, books and consulting training.
lmm
2 days ago
> 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
The original pattern is extremely abstract and a bad idea. There has been precisely one successful implementation of the original REST "pattern", the web, and only because the pattern was retrofitted onto it; most of the things in REST-as-originally-defined are bad ideas, as any apples-to-apples comparison will show.
I get oppositely frustrated because "REST" was adopted as a rallying cry for one or two good ideas (fitting your protocol to the GET/POST and 2xx/4xx/5xx distinctions from HTTP instead of treating it as a completely opaque transport layer; not wrapping everything in oodles of XML) and the term brought along a lot of bad ideas as baggage. But the meaning of the term shifted towards doing the things that are good because the original meaning was bad.
RossBencina
3 days 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
3 days ago
Don'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
3 days ago
It 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
5 hours ago
I 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)
chrchr
3 days ago
The 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.
1718627440
3 days 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
3 days ago
You 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.
scrame
3 days ago
yeah, 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.
kriops
3 days ago
Monads 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/
It’s the same kind of problem, where naming signals something the implementation is not.
(Am I allowed to link my own blog btw?)
whstl
3 days ago
> The problem is when implementations aren’t actually monads at all
Exactly, this was my point, it wasn't clear.
The original definition, and Haskell's implementation are good in itself. Monads in Haskell are not that difficult or too abstract.
It was Monad tutorials and partial implementations missed the mark, like in your example.
Myself, similarly, I've seen way too many Option<T> implementations in Typescript that are less safe than if (value !== null) {}, because they replace a static check with an exception in runtime.
lock1
3 days ago
Unrelated 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.
lmm
2 days 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.
reverius42
2 days ago
I think they mean, not allowing null outside, and using the None variant of Option to represent a lack of something.
lmm
2 days ago
Removing null completely is a good end goal, but in order to get from there to here we need to migrate trillions of lines of code (and having an option type available is necessary to even get started), and if that option type can't accommodate all the values that are valid in the language and existing codebases (which currently includes null, like it or not) then we can't even get started.
kriops
3 days ago
Optional::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.
ekidd
3 days ago
Yes, monads are abstract, but the definition is also very precise. Specifically (using C++/Rust notation for parameterized types), if we have a type "M<T>", we also need:
fn unit<T>(value: T) -> M<T>
fn map<T1, T2, F>(input: M<T1>, f: F) -> M<T2>
where F: Fn(T1) -> T2
...and finally the magic bit: fn flatten<T>(input: M<M<T>>) -> M<T>
This, in turn, allows defining what you really want: fn flatMap<T1, T2, F>(input: M<T1>, f: F) -> M<T2>
where F: Fn(T1) -> M<T2>
...where the mapping creates an "extra" layer of M<...>, and then we flatten it away immediately.(There are other rules than ones I listed above, but they tend to be easy to meet.)
Once you have flatMap, you can share one syntax for promises/futures, Rust-style Return and "?", the equivalent for "Option", and a few dozen other patterns.
Unfortunately, to really make this sing, you need to be able to write a type definition which includes all possible "M" types. Which Rust can't do. And it also really helps to be able to pick which version of a function to call based on the expected return type. Which Rust actually can do, but a lot of other low- and mid-level languages can't.
So monads have a very precise definition, and they appear in incomplete forms all over the place in modern languages (especially async/await). But it's hard to write the general version outside of languages like Haskell.
The main reason to know about monads in other languages is that if your design is about 90% of the way to being a monad, you should probably consider including the last 10% as well. JavaScript promises are almost monads, but they have a lot of weird edge cases that would go away if they included the last 10%. Of course, that might not always be possible (like in many Rust examples). But if you fall just barely short of real monads, you should at least know why you do.
(For example, Rust: "We can't have real monads because our trait system can't quite express higher-order types, and because ownership semantics mean our function types are frankly a mess.")
bobajeff
3 days 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.)
whstl
2 days ago
Casey’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.
1718627440
3 days ago
Care to provide the link for to that presentation?
bobajeff
3 days ago
Casey Muratori – The Big OOPs: Anatomy of a Thirty-five-year Mistake – BSC 2025
skydhash
3 days 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
3 days ago
This 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
jimmaswell
3 days ago
I'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.
user____name
2 days ago
I'm a fan of teaching people the wrong way first, then ask them if they can find ways to improve the situation, and only after that give the "best practice" solution.
Doing things the wrong way shows them why, asking them to try to solve it themselves teaches them under which conditions the issues present themselves -- this is actually the most important part, don't write 200 lines of abstraction just to work around the fact that you use a paltry 4 globals.
procaryote
2 days ago
It might be great for the person, but it's sure a drag to clean up after people learning to use a hammer by smashing anything they can find.
Actually, a better way to learn these patterns might be to clean up existing code. If the pattern is applicable it should then simplify and clarify the code. You'll also likely to run into crud left by other people, and will learn the appropriate level of disgust
heisenbit
3 days ago
Point in case: A singleton holding a factory to create a single instance of a fairly simple class.
procaryote
3 days ago
I'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
frumplestlatz
3 days 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.
antonvs
3 days ago
[flagged]
metanonsense
3 days ago
But isn’t that exactly what GP meant? There is an original, very precise but also very abstract definition (and what is more abstract than category theory). Then people come along who give a different definition that matches the original one in their specific context („three laws in Haskell“). After that people take these three laws and apply them (sometimes overly simplistic) to other contexts („just give it a flatMap in Scala to get a monad“). And at some point the original meaning got lost, and there are competing definitions out.
frumplestlatz
3 days ago
Those three laws are the mathematical definition.
Yes, they’re encoded in Haskell, but they’re the same monad laws from category theory.
charcircuit
3 days ago
Haskell doesn't encode them. And other concepts can be given a mathematical definition if someone wanted to formalize them.
frumplestlatz
3 days ago
That is pedantry. As for the other concepts, formalizations of OO have been done — generally to support formal verification of OO languages.
They are incredibly complicated, comprising papers of tens to hundreds of pages, and either extremely language specific, usually only formalizing a portion of the full language, or general but too limited to specify the behavior of real world languages.
The two are not comparable.
I’m also not aware of any general formalization of MVC or how one would even begin to approach a canonical definition, much less formalization.
charcircuit
3 days ago
>I’m also not aware of any general formalization of MVC or how one would even begin to approach a canonical definition
You define it by defining Model, View, and Controller and how they interact with each other. For example take a look at the diagram from the article.
user
3 days ago
antonvs
3 days ago
> other concepts can be given a mathematical definition if someone wanted to formalize them.
There's really no comparison. Monads have a very small and simple definition. That's not true of either OOP or MVC. Formalizations of OOP do exist - they're complex and messy and mainly serve to demonstrate how poorly motivated classic OOP is.
charcircuit
3 days ago
>they're complex and messy
Ultimately they are expressed in code by either the compiler or a framework. If you just want a high level formalization I don't think it would be that complex or messy.
antonvs
3 days ago
> three laws in Haskell
The laws are mathematical ones, that can't be expressed in the Haskell type system.
> And at some point the original meaning got lost
This is false. The original meaning is a mathematical one, and its use in Haskell conforms to that.
That meaning is not "lost", it's the only valid and rigorous definition there is. People who think the meaning is lost are simply ignorant. All they would have to do to correct that ignorance is a minimal amount of research.
antonvs
3 days ago
Can you cite an example of a competing definition of monads?
whstl
3 days ago
In the parent comment I did qualify my statement, in it I am talking about monads "once it gets 'explained' and migrated to other languages", not about Monad in Haskell and definitely not about Monad laws.
frumplestlatz
3 days ago
Perhaps you can provide a concrete example.
I’ve seen Haskell’s type class hierarchy successfully realized in all sorts of languages, from Scala to Swift.
- https://github.com/scalaz/scalaz
As for monads themselves, the concept emerges everywhere, with or without Haskell’s particular type classes. Case in point is Swift’s handling of Optional and Optional chaining.
lmm
2 days ago
People unaware of the laws invent things that are almost monads but break in edge cases. E.g. Scala's collections with flatMap where you can mix and match collection types are almost, but not quite, monadic. Javas Optionals as discussed in parallel threads are similarly almost, but not quite, monadic. And this kind of almost correct implementation is more dangerous than a blatantly incorrect one.
RossBencina
3 days ago
Mathematical rigor is only one type of rigor. I think you can make your point without framing attempts to tame real-world complexity as "broad and handwavy," or deriding people's struggle for understanding as "delusional ignorance."
frumplestlatz
3 days ago
Placing monads in the same category as MVC, OO, or design patterns is ignorance.
Mathematical rigor is also not comparable to whatever sense of rigor might apply to those concepts.
“Delusional” might be harsh; I’d go with “confused”.
whstl
3 days ago
Uncalled for. Try to follow the guidelines instead of calling people names.
frumplestlatz
3 days ago
Speaking authoritatively about subjects with which one is unfamiliar is likely to have one’s speech recognized as ignorant and confused. This is not uncalled for, particularly when coupled with a substantive explanation as to why.
antonvs
3 days ago
What about the guidelines for downvotes?
If factual comments are downvoted without consequences, then the site becomes nothing but a place for reinforcement of social fads.
RossBencina
2 days ago
> Mathematical rigor is also not comparable to whatever sense of rigor might apply to those concepts.
The two senses of rigor at hand are comparable at the level of frameworks of human knowledge. Comparable (not equivalent!), for example, in the sense of what these ways of knowing are seeking to know, and how they are seeking to know it. We are discussing software development practice here, so what is it exactly that these two ways of knowing are seeking to know?
The way I see it, in the context of software development, the commonality between Monads and a specific design pattern, say MVC, is that they are both tools in the developer's toolkit. Specifically, tools for structuring software abstractions. A bonafide concrete Monad gives guaranteed well defined compositional behavior for a particular class of operations on a particular class of objects. The Monad definition gives an abstraction for composable software abstractions. A design pattern describes a configuration of abstract software elements and/or roles, and a schema for composing these elements and the communications (protocols) between them. A single design pattern often describes a family of potential realisations. A design pattern, when documented properly (as in the PLoPD books), and applied appropriately, can be reduced to a practical solution that is no less robust (in practice) than the employment or definition of an object with a monadic interface. From a practical software development perspective they are of the same kind.
From a formal methods point of view the two are different. Monad has a settled mathematical definition, well understood properties, an exists within an established branch of mathematics. Application of the Monad definition to computer programming is supported by a body of established computer science that confers various mathematically proven properties. By contrast, a design pattern does not have a mathematical definition at all, and importantly for this conversation it does not claim to have a definition. A design pattern documents a way of doing things that is known to have worked for multiple past systems. It is literally an abstraction of a common pattern of practice, together with context, recommendations for use, contraindicated scenarios and so on (see my "context" comment elsewhere on this post). This is no more handwavy, and no less apposite, than the guidance given to an apprentice craftsman. Of course there is nothing to prevent someone from reducing a design pattern to a formal definition and attempting to verify properties of interest on it (I imagine this has been done).
Most developers today are not equipped to formally define and verify a Monad, or to reduce a design pattern to a formal definition and prove properties on it. Most software systems do not automatically check and enforce the Monad laws. In software practice, there is little between them. They are both tools for organising abstract software structure.
frumplestlatz
3 days ago
I 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
3 days ago
You 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.)
yakshaving_jgt
3 days ago
What does a “monadic architecture” look like? I’ve been writing web applications in Haskell for the past decade and all of them are MVC.
hurril
2 days ago
I am going to interpret your question as one asked in good spirit.
I like this book: https://www.manning.com/books/functional-design-and-architec...
yakshaving_jgt
2 days ago
> I am going to interpret your question as one asked in good spirit.
Thanks. It was.
> I like this book
I have that book, but I haven't read it. Which part specifically should I look at to understand what you mean by "monadic architecture"? Or do I need to read the entire book first? I'm searching through that book right now, and as far as I can tell, it doesn't mention "monadic architecture" even once.
hurril
2 days ago
An architecture that consists of monads.
yakshaving_jgt
2 days ago
That doesn't really tell me anything though. I use monads, and applicatives, and functors, and monoids, semigroups, etc…
When you use Hakyll to generate a static site, you use a bunch of monads. But is a Hakyll site a "monadic architecture"? I'm not quite sure how I'd describe it as an architecture — it's really just an imperative program. It's to some degree a bit like a Makefile.
A Yesod application on the other hand I would readily describe as MVC, and yet it's all monads all over the place.
What about something like The Elm Architecture? Elm provides a bunch of monads (not directly as an abstraction, but through a few specific instances) but its architecture I would describe as perhaps FRP, or unidirectional data flow state machine kinda thing.
So that's three examples with clearly distinct architectures, and all three are architectures that "consist of monads".
So, I don't really understand what "monadic architecture" means.
frumplestlatz
3 days ago
I 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.
hurril
2 days ago
See, I don't think you don't really understand my point. I said this elsewhere: I have been programming Scala and Haskell for more than 15 years, which I am sure you have as well. This is not ment as a proof of my point as that would be arguing form authority. This is not my intention. But there are more things at play here.
What I think you are doing is: well quantum mechanics is just simple mathematical construction and some artithmetic.
Is it really? Is it _just_ that?
koolala
3 days ago
Quaternions are monads since they are associative?
laszlokorte
3 days ago
No, because they dont define the >>= operator (which is the one to be associative) in the first place.
user
3 days ago
aryehof
3 days 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.
whstl
3 days ago
This 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.
user____name
2 days ago
Yup, 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
2 days ago
Not 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."
jibbit
3 days ago
it is less of an oversimplification than 'nothing like what existed either before or after'
whstl
3 days ago
Clipping 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.
mpweiher
3 days ago
Hmm...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).
to11mtm
3 days ago
IDK 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
3 days ago
For 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
3 days ago
To 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.
asimpletune
3 days ago
I 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
3 days ago
Plenty 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.
user
3 days ago
jibbit
3 days ago
unfortunately 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
3 days ago
My 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
adityaathalye
3 days ago
MVC (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.
tonyedgecombe
3 days ago
In case anybody else wondered: https://en.wikipedia.org/wiki/Expression_problem
brazukadev
3 days ago
This 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
3 days ago
Well, 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-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/
---
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/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...
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)MalinGamer123
3 days ago
Understanding the Expression Problem in MVC and OOP