The article is grouping things together that don't belong in the same categories.
OO, functional, imperative, declarative: these are ways of controlling dispatch.
Monoliths and microservices are both ways to organize codebases and teams of programmers and control whether dispatch is intermediated by the network or not. Either way, both of these options are implemented by some kind of language in the previous category (OO, functional, imperative, or declarative).
Service-oriented architecture applies to both monoliths and microservices, and very few programmers still working in the industry have really seen what an alternative to service-oriented architecture actually looks like.
All those things do actually fit in the broad category of “ideas pertaining to programming”. The author is illustrating a general notion. Far from being a problem, the divergent examples support the basic thesis.
It is really about state, dispatch is an implementation detail and can be simulated in many languages.
The main difference between monoliths and microservices is in coherent and, if possible, atomic changes in state of different subsystems. Monoliths allow use of blocking primitives or atomic transactions in software transactional memory to achieve that, to do so with microservices is much harder.
The very existence of many implementations of database systems is an attestation that many, if not most, software systems require consistent and atomic transactional processing with regard to state.
State is central to all software.
With what dispatch method to achieve coherency in the processing of state changes is an implementation detail.
The real difference between monoliths and microservices is decoupling teams to enable them to move independently in their software development lifecycles.
I've seen people set up a microservice architecture that was really a distributed monolith because multiple services were reading/writing from the same database table at the same time. I've also seen them use a central locking service as part of that.
That just shows that it's possible to carry forward the state management practices of a monolith into microservices. State management is not the differentiator.
I agree this is mixing apples and oranges. To the degree that server architecture has to preserve state in various situations, though, coming from running my own dedicated monoliths and federated systems to service-oriented architecture about a decade ago, I have to grudgingly admit that the service model really is just cleaner and easier to wrangle. I'm thinking right now of a major version DB upgrade I have to pull this week where I'm going to have a go at the new blue/green provisioning provided by RDS. The old way would have required major downtime, rewiring web services, lots of risk of data collision, not to mention time on the phone with a datacenter just to get up and running. Ultimately the old ways always felt duct taped in some regard, like trying to switch the scenery of a stage production in the middle of an act. I hate that I'm so reliant on Amazon now, but it's just wildly more efficient.
Would you say that this distinction between SOA and micro services is correct, which I found in an O'Reilly report [1]:
> One of the fundamental concepts to remember is that microservices architecture is a share-as-little-as-possible architecture pattern that places a heavy emphasis on the concept of a bounded context, whereas SOA is a share-as-much-as-possible architecture pattern that places heavy emphasis on abstraction and business functionality reuse. By understanding this fundamental concept—as well as the other characteristics, capabilities, and shortcomings of both micro‐ services and SOA that I discussed in this report—you can make a more informed decision about which architecture pattern is right for your situation.
Or is this a distinction you would not make (or were not even aware of)?
[1] Mark Richards - Microservices vs. Service-Oriented architecture
>OO, functional, imperative, declarative: these are ways of controlling dispatch.
Not really. They are orthogonal to dispatch, which is why you can have different dispatch strategies with all (or at least most) of them. Dispatch is an implementation detail.
There is a bit of categorical mixing going on and the author fails to identify actual hierarchies within the programming styles. But he does see, correctly, that it all has to do with state management. I'll point out what he got mixed up:
First OO programming is a specific style of imperative programming. OO is simply imperative programming with state and functions scoped into instances. If you are doing OO, you are also still doing imperative programming.
You can't really compare OO to functional because it would be like comparing a very specific concept to a very general concept. Like comparing cars and planes, but instead you're comparing a 2020 tesla with all planes in general. No... either compare specific cars with specific planes or planes in general with cars in general.
Declarative programming, on the other hand, can be stateless or stateful so it doesn't really apply here. Declarative programming is sort of left field to all these programming styles because technically chatGPT is declarative. Declarative programming is more about linguistics, AI and natural language processing. It's completely orthogonal to state management.
Functional programming and Imperative Programming are the two correct categories to compare here. They are siblings in the hierarchy and they are distinct and in essence simply two different ways of handling state.
Case in point: If you change one thing in your imperative programs. One thing... then your imperative program immediately becomes functional.
This thing is immutable state. Imperative programming with immutable state IS functional programming. Change the way you manage state, then you essentially change the name of your programming style.
The two paradigms are in essence two different styles of state management. All the other stuff with OO and Declarative is sort of fluff and distracts from the true essence of the isomorphism the author noticed here.
I think your mistake is that it's not about the "abstract"/academic/philosophical or etymological meaning of those terms (functional, imperative, etc).
It's about their meaning (as used for decades) within the developer community at large, as established and commonly understood.
And in that, there's absolutely a functional vs OO dichotomy, the first meaning Lisp, Haskell, etc, and the latter meaning Java/C++/Smalltalk and such (doesn't even matter if Smalltalk for example has a different conceptual model for its OO or different dispatch mechanism, etc).
And sure, "well, actually Lisp has CLOS" -- but OO and functional as commonly used (and as the author uses it) means the part of functional that's about first class functions and immutable data and purity, and OO means Java/C++ style classes and coding style.
Ditto for "imperative", which in TFA just means "C style more direct manipulation of state", even if OO in say C++ is still imperative in the academic sense of the term (and, heck, even that is not that clear cut. "Procedural" programming for example is still imperative in its manipulation of data, but the terms have been used in academia and industry to describe different things. So it's not about a naive application of the definition, but rather about the intention behind the term).
>Declarative programming, on the other hand, can be stateless or stateful so it doesn't really apply here.
Again, for the purposes of TFA, it doesn't matter if declarative can be "stateless or stateful".
The author doesn't say that the programming language philosophies are about "different approaches to state across a single axis" (e.g. stateless vs stateful). He just says that they are about "different approaches to state" period.
In this case, regarding declarative programming, the difference is not "keeping state or not", but "the programming managing whether state is kept or not (and how)" vs "the language managing it and the programmer just declaring their intentions".
>This thing is immutable state. Imperative programming with immutable state IS functional programming.
Not in any colloquial use of the term. SSA form might be "functional programming", but it's not what 99% of devs (and the author) means by functional programming, which includes the trappings and idioms offered by traditional languages called functional programming languages.
> OO, functional, imperative, declarative: these are ways of controlling dispatch.
Two problems with this statement:
1. imperative & declarative are about dispatch, OO & functional are about much more (dispatch being one of the most negligible components)
2. dispatch is extremely concerned with state: e.g. for declarative, state is handled by the "dispatcher", whereas for imperative state is an extra responsibility of core logic - the approaches to state handling is one of the most important differentiators between these paradigms.
As for your 2nd & 3rd paragraphs, 100% agree but they don't seem to contradict the article so I'm not sure what point you're making.
Anything monolithic, where a single binary executable is run at the start, maybe spawning subprocesses to handle parallel tasks, possibly sharing memory through synching protocols to avoid interlocking.
SOA uses message passing only as the synch mechanism, but sharing memory allows for other strategies with synch primitives such as semaphores or mutexes (with the assumption that collaborating processes run on the same physical machine, or communicate through Remote Procedure Calls).
XML-RPC based apps might count but they’re generally all under SOA in my experience. A real-time desktop application with some networked features to manipulate documents like via websockets may count as CRUD but not follow any SOA kind of architectural or interface conventions.
> Service-oriented architecture applies to both monoliths and microservices, and very few programmers still working in the industry have really seen what an alternative to service-oriented architecture actually looks like.
In what industry? I'd agree that anyone making anything web-facing is using some form of SOA, but there are other things, too. Desktop apps (and to some extent mobile apps that aren't just a thin interface over a web API) still exist.
Unless you're arguing the maximalist approach, i.e., that anything with an API that tries to hide any form of implementation details is an example of SOA. In which case, that's not very interesting...
Imperative: modifying state is the point of a bit-flipping machine; get out of my way so I can have fun!
OOP: OK, I mostly had enough fun, can we try to tame the bit-flipping chaos with real-world analogies, without deflating all the fun?
Functional: Any Monad is by definition an Endofunctor, which also means it's an object in the category of Endofunctors, where the monadic μ(flatMap) and η(unit) operators satisfy the definition of a Monoid in that particular Monoidal Category. You got that?
Declarative: I'm gonna need a corner office with a view, and $200K/y.
I wish people would quit propagating this hostile view of functional programmers. The vast majority of them — even in academia — are happy to never mention or even fully learn about the scary math words, and most of those who _do_ learn about them work really hard to not make the community unwelcoming to those who don't know or don't want to know. But the reputation precedes, which causes people to avoid it altogether, which is really a shame.
The whole "a monad is a monoid in the category of endofunctors, what's the big deal?"-in-a-condescending-tone bit comes from "A Brief, Incomplete, and Mostly Wrong History of Programming Languages": a satirical blog post from 2009 (http://james-iry.blogspot.com/2009/05/brief-incomplete-and-m...). It is not indicative of the general community, but the joke has been reproduced enough that people who don't know anything will encounter it, think the practitioners are serious about it, and write off the whole thing as unwelcoming. It's a bummer.
It would help if functional didn’t collect all the people with their heads all the way up their own asses. Functional has more shibboleths than anybody except maybe professional consulting groups like IBM GS.
You can’t have exclusive language and then be surprised when nobody wants to worship at the altar of your obfuscation.
ETA: Look. I was reading 25 year old complaints about why Lisp isn’t popular 25 years ago. You can go on scratching your heads for another 25 years or you can start taking criticism instead of deflecting.
I feel I should point out that that ‘functional’ quote is (a) only applicable to pure, strongly-typed functional languages, and (b) pretty much irrelevant unless you happen to be interested in category theory.
Yep, the FP scene is split into the pragmatic and the academic sides.
I think it is not precisely delineated along the static vs dynamic sides: In addition to Elixir/Erlang, and Clojure we have eg F# and Elm from the static side in the pragmatic team.
...and it's a real shame that Haskell has to be like that. I feel like much of the, sorry, mathematical wankery, is well separable from the stuff that actually makes program behavior more predictable in the functional style. I hear that F# has some success at doing exactly that.
Some blog posts are wankery. Haskell in practice is as separate and separable from it as you want.
I learned what a mathematical monad is out of interest (after using them in practice for years), and my conclusion is that it was a huge waste of time with close to zero use for my programming in Haskell.
This made me smile. I'm not sure I get the declarative one though, can someone expand on this? Is it because the sentence is very declarative? or because declarative programming allows lets to declare expensive to compute stuff (by mistake) too easily?
Not really. For example ocaml allows oop in a functional programming language.
OOP is about encapsulation of data and algorithms which deal with that data in logical units (objects) and allowing certain operations eg inheritance, polymorphism (sometimes) etc over those objects. It can be declarative or imperative.
I’ve been a programmer all my life, got first sw job around 2000 in business-oriented area (consulting + programming + “ops”). Before that were 5-7 years of toy programming as a kid. I experimented with tech a lot, got into paradigms early and never restricted myself to a single language/env/os/hw. I haven’t created nothing big, stellar or rocket science, but a couple of my projects lived for 10-17 years and counting.
Mind you, this “state management” thing and the fuss around it, which pops up for last ten years more actively, was never a concern that I found particularly useful to have a name for. 20+ years of a mediocre career and I still don’t get it, neither why, nor what the problem is. Maybe that’s why it is mediocre? Living in a bs country doesn’t help either. Otoh, I can make things work and ship mvps next week once there’s a plan and determination. (No, it’s not PHP.)
I believe that the fuss part comes from the fact that software becomes more and more low-level uncontrollably, so there’s a lot of self-imposed state that business isn’t even aware of and which becomes per-LoC routine that is easy to stumble upon but hard to document or explain to a person outside. State belongs to business and is not in your control, all other state is parasite. Mapping business state 1:1 in your program keeps everything simple to do, to change, to grow. It’s usually imperative, sometimes declarative (that’s where programming emerges) and never functional. Parasitic state’s place is under a rug. Library, syntactic sugar, framework, db/service, platform, whatever.
To conclude, well, I have nothing to say really. Still confusing.
Maybe you simply gravitated towards sensible ways of dealing with it?
There are quite a bunch of things that are _hard_ (IMO) and related to state management a non-exclusive list of examples:
- GUIs in general, the more interactive they are, the more state you need to manage.
- Caching (at any level) is a form of state. You need to be aware of how and when data changes and who changes it and which parts of the caching are affected, when you care about it etc.
- Memory and disk allocation are state. You need to be aware of what your resources are and when to free them up. You might use locks to make sure your data doesn't get corrupted. At a higher layer you might have authorization models to restrict access.
- TCP is state. What do you do when connections fail or get interrupted? Do you store/buffer messages to be processed at a later time? What does that mean for the receiver?
- SQL databases are stateful. Do you ever need to know what happened when? How do you restore previous state? How do you make that efficient? Are backups/snapshots good enough or can you leverage something more granular?
It’s hard to tell. My gut feeling, especially the one I get from popular state management libraries, says I actually gravitate away from it, in a sense. I see what they are for, but it feels like they are made with a sugar-coated landing/tutorial page in mind, while at the same time making things more complex, basically trading more for less. They turn languages and paradigms indise out to get cool effects, but make your way of thinking diverge from how business requirements speak, creating a gap between programmers and consultants.
As others noted, the size of my projects may skew the perspective. But I’m not sure how big something should be (and tightly coupled) to start worrying about it, unless my primitives aren’t too great to use without a second thought. What bugs me even more us that popular libraries don’t even provide them out of box, suggesting to write code and to spread structures in a special convoluted way instead.
The text of a program does not show what is in memory, or what the devices attached to the machine are doing. You hope that if you run the program, in your head, you can reliably guess -- but often, you make mistakes.
Controlling "state" amounts to trying to force the world to match the text of your program as closely as possible, so you don't go wrong.
Thinking about state helps me write better code. If the codebase for a project is small enough, and I can enumerate all states and all ways that states can change into other states, I can make code that is so stable it can run indefinitely. Very satisfying. The next logical step from this point, I guess, is TLA+ (I still haven't tried it).
It's more of an issue the more network-y and multi-cpu your ecosystem is. I find the post rather banal and obvious. The state is literally the how and what.
For a lot of small to medium scale business software, state tends to be managed mostly by one central, source of truth, database that business logic gets applied to; there it does not matter much with what paradigm you handle the "request" state (be that a network request or a GUI/TUI request interface).
An idea that sounds convincing at first, but falls apart on closer examination. I found myself less and less convinced with each example, some of which really seem to be grasping at straws.
Programming philosophies encompass much more than just state management, and narrowing the focus to state doesn't seem particularly enlightening to me, at least with these summaries. I'd love to be proved wrong, though.
I think they are right about the first few: OO and FP are both most definitely about state management.
However, I definitely agree that it's a stretch to say that architectural patterns like monolith vs microservices are about state. Those have far more to do with structuring deployments and organizing work.
It seems that the author is trying to make a kind of grand statement but the epiphany isn't felt. A program without any state seems uninteresting, state without logic to manipulate it seems uninteresting as well - no computer ships with only registers or only an ALU after all. It seems that we must include logic in the discussion as well but if we do, the title needs to be updated to "all programming philosophies are about programming".
This is not a deliberately reductive take, I just can't think of any other meaning.
I feel this, but I think it's just a thing that programmers do. It was 10 years ago when I realized that all programming methods are about dealing with (conceptualizing/architecting) state. It made a lot of stuff "simple" to me that had previously been "complex" and I got a lot of value out of that change in paradigm. Not so much that I didn't assume all my peers didn't already know it (I find I'm usually "behind the curve" when it comes to piecing obvious things together), so didn't evangelize it to anyone, but I definitely understand why someone would.
It feels secret, because no one really talks directly about how all programming paradigms are about state. But once you realize it, you can start to see how a lot of high-level programmers reference it when they talk, all the time. Just something that "everybody knows", once you spend enough time working in code.
Personally, it wasn't the realization that it's all about state that was particularly exciting. It was using that new interpretation to understand how I could mix and match different types within a single project, to make each separable/modular piece of it, rather than dogmatically sticking to a single paradigm throughout. I think there's a definite mental breakthrough when a programmer can confidently use multiple different state paradigms to handle what would otherwise be a clunky or unwieldy implementation in a single paradigm.
I found that a big jump in my quality of design was when I started thinking about what state was necessary, what transformation needed to be done, and by what entity. Before that, I used to code for the task at hand, and create data structures mostly for the task at hand. Thinking about what each program might need to know and in what format relative to it's role just made things smoother.
It wasn't a large leap conceptually, but the mental model change came from a long lost hacker news comment along similar lines.
Programming (in the sense of software construction) paradigms, philosophies, indeed "languages" etc., are about regularizing plans of action for complex computational undertakings.. usually.
As someone coming from a functional perspective I would humbly characterize my position as:
> Functional - Modifying state is hard to get correct; so let's focus on the rest of the problem (the part we can get right!)
Pushing state to the edges is actually just a consequence of this impulse.
In the end it isn't a satisfying solution, because you end up with every bit of low-level, inconsequential state percolating up to the top and polluting every single data structure along the way.
I feel there must be a better approach ... in which the "impertinent" state can be abstracted away and managed orthogonally to the functional description of the program.
Almost certainly there’s no meaningful insight to my random thought, but your comment reminded me of a conversation I had with Joe Armstrong about 10 years ago, discussing control vs data plane for Riak.
Originally Riak shipped its data around as part of Erlang’s standard messaging mechanism, the process mailboxes. Over time that was recognized as a bottleneck and data started being handled differently (honestly it’s been such a long time I don’t remember the details, or how far down that road we went).
I have no conclusion to this ill-formed rumination, I’m afraid, just that your point about managing state independently reminded me of that conversation.
It's been a while but I used to enjoy telling folks in the early years of their career that software engineers and anarchists have a lot in common because both view "the state" as the main cause of problems.
Wow, that's great, thanks! As a dad and Certified Card-Carrying member of the International League of Punists I feel this is really profound. Not at all in my political direction, but who cares it's the pun that matters.
Also, it would make an epic t-shirt in the hands of someone with some actual artistic skills. Is there such as a thing as missing a cool t-shirt you haven't seen? :/
"Down with the State", "Shrink the State", "Less State -> More Good", "No State, No Problems", "Spread the State", "No State/Stay Pure"? Oh my kingdom for a programming-literate copywriter.
Funny, I arrived at this "all software is.." piece last week.
Hypothesis: All of software *is* about change management
----
It dawned on me that all the software design efforts - Design patterns, programming styles, management practices - are all geared towards one thing at its core - managing change. For example:
* Command pattern: Figure out all the things that can be called and instead of a giant if/switch, look them up by name and call them. That way when you need to *change* the list of things you want to call, nothing else is affected.
* Structured programming: Keep the common code in one place and call them from many places. That way when the common code *changes*, we can contain the change to one place
* Object Oriented Programming: Keep the data and behavior common to one actor in the system contained in an object/class so that when it *changes* we have to change only that thing.
* Functional programming: *Changing* data is bad. Instead create copies of data and change them.
* Scrum: It's hard to predict too far into the future because things *change*. So let's try to plan for just the next n weeks.
OO, functional, imperative, declarative: these are ways of controlling dispatch.
Monoliths and microservices are both ways to organize codebases and teams of programmers and control whether dispatch is intermediated by the network or not. Either way, both of these options are implemented by some kind of language in the previous category (OO, functional, imperative, or declarative).
Service-oriented architecture applies to both monoliths and microservices, and very few programmers still working in the industry have really seen what an alternative to service-oriented architecture actually looks like.
It is really about state, dispatch is an implementation detail and can be simulated in many languages.
The main difference between monoliths and microservices is in coherent and, if possible, atomic changes in state of different subsystems. Monoliths allow use of blocking primitives or atomic transactions in software transactional memory to achieve that, to do so with microservices is much harder.
The very existence of many implementations of database systems is an attestation that many, if not most, software systems require consistent and atomic transactional processing with regard to state.
State is central to all software.
With what dispatch method to achieve coherency in the processing of state changes is an implementation detail.
I've seen people set up a microservice architecture that was really a distributed monolith because multiple services were reading/writing from the same database table at the same time. I've also seen them use a central locking service as part of that.
That just shows that it's possible to carry forward the state management practices of a monolith into microservices. State management is not the differentiator.
> One of the fundamental concepts to remember is that microservices architecture is a share-as-little-as-possible architecture pattern that places a heavy emphasis on the concept of a bounded context, whereas SOA is a share-as-much-as-possible architecture pattern that places heavy emphasis on abstraction and business functionality reuse. By understanding this fundamental concept—as well as the other characteristics, capabilities, and shortcomings of both micro‐ services and SOA that I discussed in this report—you can make a more informed decision about which architecture pattern is right for your situation.
Or is this a distinction you would not make (or were not even aware of)?
[1] Mark Richards - Microservices vs. Service-Oriented architecture
Not really. They are orthogonal to dispatch, which is why you can have different dispatch strategies with all (or at least most) of them. Dispatch is an implementation detail.
First OO programming is a specific style of imperative programming. OO is simply imperative programming with state and functions scoped into instances. If you are doing OO, you are also still doing imperative programming.
You can't really compare OO to functional because it would be like comparing a very specific concept to a very general concept. Like comparing cars and planes, but instead you're comparing a 2020 tesla with all planes in general. No... either compare specific cars with specific planes or planes in general with cars in general.
Declarative programming, on the other hand, can be stateless or stateful so it doesn't really apply here. Declarative programming is sort of left field to all these programming styles because technically chatGPT is declarative. Declarative programming is more about linguistics, AI and natural language processing. It's completely orthogonal to state management.
Functional programming and Imperative Programming are the two correct categories to compare here. They are siblings in the hierarchy and they are distinct and in essence simply two different ways of handling state.
Case in point: If you change one thing in your imperative programs. One thing... then your imperative program immediately becomes functional.
This thing is immutable state. Imperative programming with immutable state IS functional programming. Change the way you manage state, then you essentially change the name of your programming style.
The two paradigms are in essence two different styles of state management. All the other stuff with OO and Declarative is sort of fluff and distracts from the true essence of the isomorphism the author noticed here.
It's about their meaning (as used for decades) within the developer community at large, as established and commonly understood.
And in that, there's absolutely a functional vs OO dichotomy, the first meaning Lisp, Haskell, etc, and the latter meaning Java/C++/Smalltalk and such (doesn't even matter if Smalltalk for example has a different conceptual model for its OO or different dispatch mechanism, etc).
And sure, "well, actually Lisp has CLOS" -- but OO and functional as commonly used (and as the author uses it) means the part of functional that's about first class functions and immutable data and purity, and OO means Java/C++ style classes and coding style.
Ditto for "imperative", which in TFA just means "C style more direct manipulation of state", even if OO in say C++ is still imperative in the academic sense of the term (and, heck, even that is not that clear cut. "Procedural" programming for example is still imperative in its manipulation of data, but the terms have been used in academia and industry to describe different things. So it's not about a naive application of the definition, but rather about the intention behind the term).
>Declarative programming, on the other hand, can be stateless or stateful so it doesn't really apply here.
Again, for the purposes of TFA, it doesn't matter if declarative can be "stateless or stateful".
The author doesn't say that the programming language philosophies are about "different approaches to state across a single axis" (e.g. stateless vs stateful). He just says that they are about "different approaches to state" period.
In this case, regarding declarative programming, the difference is not "keeping state or not", but "the programming managing whether state is kept or not (and how)" vs "the language managing it and the programmer just declaring their intentions".
>This thing is immutable state. Imperative programming with immutable state IS functional programming.
Not in any colloquial use of the term. SSA form might be "functional programming", but it's not what 99% of devs (and the author) means by functional programming, which includes the trappings and idioms offered by traditional languages called functional programming languages.
Two problems with this statement:
1. imperative & declarative are about dispatch, OO & functional are about much more (dispatch being one of the most negligible components)
2. dispatch is extremely concerned with state: e.g. for declarative, state is handled by the "dispatcher", whereas for imperative state is an extra responsibility of core logic - the approaches to state handling is one of the most important differentiators between these paradigms.
As for your 2nd & 3rd paragraphs, 100% agree but they don't seem to contradict the article so I'm not sure what point you're making.
SOA uses message passing only as the synch mechanism, but sharing memory allows for other strategies with synch primitives such as semaphores or mutexes (with the assumption that collaborating processes run on the same physical machine, or communicate through Remote Procedure Calls).
http://www.composingprograms.com/pages/48-parallel-computing...
https://en.wikipedia.org/wiki/Remote_procedure_call
In what industry? I'd agree that anyone making anything web-facing is using some form of SOA, but there are other things, too. Desktop apps (and to some extent mobile apps that aren't just a thin interface over a web API) still exist.
Unless you're arguing the maximalist approach, i.e., that anything with an API that tries to hide any form of implementation details is an example of SOA. In which case, that's not very interesting...
OOP: OK, I mostly had enough fun, can we try to tame the bit-flipping chaos with real-world analogies, without deflating all the fun?
Functional: Any Monad is by definition an Endofunctor, which also means it's an object in the category of Endofunctors, where the monadic μ(flatMap) and η(unit) operators satisfy the definition of a Monoid in that particular Monoidal Category. You got that?
Declarative: I'm gonna need a corner office with a view, and $200K/y.
The whole "a monad is a monoid in the category of endofunctors, what's the big deal?"-in-a-condescending-tone bit comes from "A Brief, Incomplete, and Mostly Wrong History of Programming Languages": a satirical blog post from 2009 (http://james-iry.blogspot.com/2009/05/brief-incomplete-and-m...). It is not indicative of the general community, but the joke has been reproduced enough that people who don't know anything will encounter it, think the practitioners are serious about it, and write off the whole thing as unwelcoming. It's a bummer.
You can’t have exclusive language and then be surprised when nobody wants to worship at the altar of your obfuscation.
ETA: Look. I was reading 25 year old complaints about why Lisp isn’t popular 25 years ago. You can go on scratching your heads for another 25 years or you can start taking criticism instead of deflecting.
Let’s treat data as what it is so I can sleep at night again.
I think it is not precisely delineated along the static vs dynamic sides: In addition to Elixir/Erlang, and Clojure we have eg F# and Elm from the static side in the pragmatic team.
Eg. Clojure is a modern functional language that is used for a lot of things & happens to be dynamic.
Some blog posts are wankery. Haskell in practice is as separate and separable from it as you want.
I learned what a mathematical monad is out of interest (after using them in practice for years), and my conclusion is that it was a huge waste of time with close to zero use for my programming in Haskell.
At it's core, it's about treating data like data and not about having to much about with "objects".
OOP is about encapsulation of data and algorithms which deal with that data in logical units (objects) and allowing certain operations eg inheritance, polymorphism (sometimes) etc over those objects. It can be declarative or imperative.
Mind you, this “state management” thing and the fuss around it, which pops up for last ten years more actively, was never a concern that I found particularly useful to have a name for. 20+ years of a mediocre career and I still don’t get it, neither why, nor what the problem is. Maybe that’s why it is mediocre? Living in a bs country doesn’t help either. Otoh, I can make things work and ship mvps next week once there’s a plan and determination. (No, it’s not PHP.)
I believe that the fuss part comes from the fact that software becomes more and more low-level uncontrollably, so there’s a lot of self-imposed state that business isn’t even aware of and which becomes per-LoC routine that is easy to stumble upon but hard to document or explain to a person outside. State belongs to business and is not in your control, all other state is parasite. Mapping business state 1:1 in your program keeps everything simple to do, to change, to grow. It’s usually imperative, sometimes declarative (that’s where programming emerges) and never functional. Parasitic state’s place is under a rug. Library, syntactic sugar, framework, db/service, platform, whatever.
To conclude, well, I have nothing to say really. Still confusing.
There are quite a bunch of things that are _hard_ (IMO) and related to state management a non-exclusive list of examples:
- GUIs in general, the more interactive they are, the more state you need to manage.
- Caching (at any level) is a form of state. You need to be aware of how and when data changes and who changes it and which parts of the caching are affected, when you care about it etc.
- Memory and disk allocation are state. You need to be aware of what your resources are and when to free them up. You might use locks to make sure your data doesn't get corrupted. At a higher layer you might have authorization models to restrict access.
- TCP is state. What do you do when connections fail or get interrupted? Do you store/buffer messages to be processed at a later time? What does that mean for the receiver?
- SQL databases are stateful. Do you ever need to know what happened when? How do you restore previous state? How do you make that efficient? Are backups/snapshots good enough or can you leverage something more granular?
As others noted, the size of my projects may skew the perspective. But I’m not sure how big something should be (and tightly coupled) to start worrying about it, unless my primitives aren’t too great to use without a second thought. What bugs me even more us that popular libraries don’t even provide them out of box, suggesting to write code and to spread structures in a special convoluted way instead.
Controlling "state" amounts to trying to force the world to match the text of your program as closely as possible, so you don't go wrong.
Programming philosophies encompass much more than just state management, and narrowing the focus to state doesn't seem particularly enlightening to me, at least with these summaries. I'd love to be proved wrong, though.
However, I definitely agree that it's a stretch to say that architectural patterns like monolith vs microservices are about state. Those have far more to do with structuring deployments and organizing work.
This is not a deliberately reductive take, I just can't think of any other meaning.
It feels secret, because no one really talks directly about how all programming paradigms are about state. But once you realize it, you can start to see how a lot of high-level programmers reference it when they talk, all the time. Just something that "everybody knows", once you spend enough time working in code.
Personally, it wasn't the realization that it's all about state that was particularly exciting. It was using that new interpretation to understand how I could mix and match different types within a single project, to make each separable/modular piece of it, rather than dogmatically sticking to a single paradigm throughout. I think there's a definite mental breakthrough when a programmer can confidently use multiple different state paradigms to handle what would otherwise be a clunky or unwieldy implementation in a single paradigm.
It wasn't a large leap conceptually, but the mental model change came from a long lost hacker news comment along similar lines.
I don't think it is a reductive take. The second instance of the term here instead involves the more traditional concept
program: "a regular plan of action in any undertaking" https://www.dictionary.net/program
Programming (in the sense of software construction) paradigms, philosophies, indeed "languages" etc., are about regularizing plans of action for complex computational undertakings.. usually.
> Functional - Modifying state is hard to get correct; so let's focus on the rest of the problem (the part we can get right!)
Pushing state to the edges is actually just a consequence of this impulse.
In the end it isn't a satisfying solution, because you end up with every bit of low-level, inconsequential state percolating up to the top and polluting every single data structure along the way.
I feel there must be a better approach ... in which the "impertinent" state can be abstracted away and managed orthogonally to the functional description of the program.
Originally Riak shipped its data around as part of Erlang’s standard messaging mechanism, the process mailboxes. Over time that was recognized as a bottleneck and data started being handled differently (honestly it’s been such a long time I don’t remember the details, or how far down that road we went).
I have no conclusion to this ill-formed rumination, I’m afraid, just that your point about managing state independently reminded me of that conversation.
Also, it would make an epic t-shirt in the hands of someone with some actual artistic skills. Is there such as a thing as missing a cool t-shirt you haven't seen? :/
"Down with the State", "Shrink the State", "Less State -> More Good", "No State, No Problems", "Spread the State", "No State/Stay Pure"? Oh my kingdom for a programming-literate copywriter.
Hypothesis: All of software *is* about change management ----
It dawned on me that all the software design efforts - Design patterns, programming styles, management practices - are all geared towards one thing at its core - managing change. For example:
* Command pattern: Figure out all the things that can be called and instead of a giant if/switch, look them up by name and call them. That way when you need to *change* the list of things you want to call, nothing else is affected.
* Structured programming: Keep the common code in one place and call them from many places. That way when the common code *changes*, we can contain the change to one place
* Object Oriented Programming: Keep the data and behavior common to one actor in the system contained in an object/class so that when it *changes* we have to change only that thing.
* Functional programming: *Changing* data is bad. Instead create copies of data and change them.
* Scrum: It's hard to predict too far into the future because things *change*. So let's try to plan for just the next n weeks.