13 ms·
Forget monoliths vs. microservices: cognitive load is what matters
- ryanmarsh 7y agoThis is the issue at the heart of most architecture and language/idiom arguments. We're meat bags selected for avoiding predators, telling stories around a campfire, and poking things with a stick and we're trying to reason about and craft functioning complex systems. Until the machines take over, the optimal language or architecture will be the one your team can both make sense of and employ with relative ease, full stop.
- telesilla 7y agoYour reply is exactly what I needed as ammunition to people who don't see how machines can really help us in the future - if you don't mind, I'll paraphrase this comment! Too many people I talk to who aren't computer programmers but maybe, designers or architects who have been to a few conferences, don't believe there is revolution yet to come.
- pmarreck 7y agoI'm a 47 year old programmer who doesn't think a revolution is yet to come because I actually think programming is far more creative in nature than we can ever give to a machine. Not that there won't be tools to assist the human programmers, but the robot uprising will never occur until we can at least answer the very basic question of why will the robots care, and how exactly, in some non-hand-wavey fashion, will they get creative about solving novel problems? Consider this: You can write a genetic algorithm maker which will randomly iterate through all possible abstract syntax tree morphs and then run a test that evaluates whether the code "performs better" as a solution to some given need, and eventually you might strike upon some novel way of solving a problem through pure randomness. But here's the thing: The ultimate arbitrator of "what is better" will always be a human and the ultimate agent of "need" is a human as well. Machines just don't "need" things, like a faster way to ray-trace so your videogame open-world simulation is more immersive, or even a nicer GUI, much less a better way to make money... People need all these things, and people evaluate whether the machine reduces those needs. Machines DNGAF.
- quickthrower2 7y agoWhen people say to me eventually computers will program themselves and I’ll be out of a job, I think that’ll be the least of our worries, as humans will become redundant.
- firethief 7y agoI like to say that programming is the last job that will be automated. To normal people it's a turn of phrase; tech people understand that I'm literally referring to the impending end of life as we know it.
- ryanmarsh 7y agoPlease do. I’ve used it in conference talks.
- orbital-decay 7y agoThis is a fundamental operation in most engineering disciplines related to human interaction: reducing the system (the designer's PoV) to a particular path through that system (the user's PoV), constrained by cognitive capabilities of the user. The designer sees a graph of entities and relationships, the user only needs to navigate it with the least effort. This is applicable to everything, from the structural design of a rocket (a structural engineer only needs the specs and the load profile for the specific part, not the entire rocket internals) to videogame level design (different paths taken by players through a location).
- cableshaft 7y agoOooff, that one hit home. Maybe I'm in the wrong line of work.
- Rabidgremlin 7y agoAnother way of rephrasing Conway's law?
- goodroot 7y agoIn my experience, communication skills are always the bottleneck. > But with the coming-of-age of IoT and ubiquitous connected services, we call them "stream-aligned" because "product" loses its meaning when you're talking about many-to-many interactions among physical devices, online services, and others. ("Product" is often a physical thing in these cases.) Foreboding over IoT is not a strong argument against product teams. Whether it is product teams, streams, microservices, or monoliths: people have limitations on how they can maintain equilibrium and the current set of processes and tools overwhelm it at the cost of productivity. I agree with the spirit of the argument, but I think it's counter intuitive to suggest "yet another" thought construct based on a premise of under-loading cognitive faculties.
- flying_sheep 7y agoI think it is more than communication skills. Communication is effective when something is "speakable". This implies both parties has good abstraction over the same thing. But when the system is overly complex (no matter monoliths or micro-services), it is impossible to build a good abstraction. Just considering a n parameters boolean function. You can build a simple formula around it and communicate well if there is simple pattern. For example, f(x1, x2, ...) = x1 When there is some exception? Fine, we can still talk about general pattern, while communicate particularly about the exception. But when the mapping gets more random, at some point no one can describe it without going through each value one by one. The complexity will become O(2^n). You will spend whole day to communicate only tiny part of the function
- atoav 7y agoAs somebody who worked quite a bit on various smaller film sets it always shocka me just how bad people in IT often are when it comes to communicating either within their teams, with their code or with non-IT people. It certainly got better in some ways, but nowhere near the military precision of a well tuned and experienced film crew.
- slowmovintarget 7y agoBut film crews don't have to invent a vocabulary for each film. The special terms used are all the same. Developer teams juggle multiple special-purpose vocabularies specific to the technology stack they use, the techniques they employ within the technology stack, the language of the domain they are encoding in software, and the language of the software solution itself. The set of vocabularies gets expanded or swapped every time you add a person, a technology, or a new project. Of course we're "bad" at communicating! It's a harder cognitive problem space to convey meaning in.
- crimsonalucard 7y agoThis paradigm will be inn-effective in my humble opinion. It will be because it involves prediction. Cognitive load is unknown. If predicting when a project will complete is hard, predicting how large and where the most cognitive load will be is going to be just as hard if not harder.
- quickthrower2 7y agoI think it requires reaction rather than prediction.
- jerf 7y agoI have found myself tending more and more towards a style where I break even some relatively small modules up into fairly small pieces, and I have very, very clearly specified definitions for "what this module consumes" and "what this module provides". (I have not quite reached "very, very clearly". At the moment I'm still resisting the sheer amount of keyboard typing it takes to be clear. But I can see I'm trending this way.) In essence, take the idea of a dependency-injected function that uses no globals, and bring the same organization up to the module level. Nominally, languages support this, but a lot of it is still implicit. For instance, do you have a command you can point at a module of your code and get a complete report of A: what libraries this code uses and B: exactly which subset of calls from those libraries this code uses? There's so many languages and environments and IDEs and such out there I imagine the answer may be yes for a few of you, but probably not that many, and even fewer of you use it. The primary reason I find myself moving this way is to try to make it so you can read a piece of code and the cognitive overhead is minimized, because there's a clear flow: 1. Here are my assumptions. 2. Here is my environment. 3. Here is what I do in that environment. 4. Here are the test cases that show that the thing I wanted to do is in fact done. In current languages, these things are not exactly "all mixed up", but they are not exactly cleanly separated, either. I realize this may sound vacuous and obvious, but, err, if that's so, a lot more of us could stand to actually do it, to put it in politic terms. I think the languages and environments work against us in a lot of ways by making it very easy to add dependencies without much thought and weave all those concerns together into one big undifferentiated mass. In the last few weeks, I've had a language coalescing in my head, which I'm not particularly happy about since I have no chance of being able to implement it, and one of the things it does is to encourage this sort of thing by making it easy. Basically, whenever importing a library, it would automatically add a layer of abstraction between your code and that library that allows you to override that library wholesale for testing purposes or something. I do this manually in a lot of languages I work in, but it involves writing a tedious layer that just takes calls to "A" in one side and routes calls to "A" out another. There's an idea of a "context" that you can pass to a module that would do this override. Basically it would be a statically-typed ability to monkeypatch, safely, and in a way where by and large, the compiler could optimize access to the "default" implementation such that you should generally not be paying an abstraction penalty. Then there would be a report that you could use the runtime tooling to generate that would tell you exactly what external functionality you're using, and you could use that to guide you in your override so you only implement what you need. (I have a mental image of a cell, which being biologic, doesn't really do anything cleanly, but taking it metaphorically, you can see cell walls declaring the things they will allow to pass through, and with only a bit more work we can clearly declare what comes out.) There are, of course, bits and pieces of this scattered all over the language landscape, but I'm not aware of anything that quite has everything I want in one place. (Perhaps surprisingly, Perl's "local" keyword is the closest single thing I know, albeit not written in a way that can support threading well which I'd want to fix. You can use local to override arbitrary function/method symbols, and it will be scoped within that local only, giving you that "dynamic language" monkeypatching while preventing it from being global state.) Part of the idea of that report too is that it would be part of the documentation for a module, further increasing the ability to pick up any arbitrary module in a program, and cleanly cut away "look, this is exactly what this particular module does. You may not necessarily know what the other modules this communicates with is doing with that stuff, but at least you know what this module is doing." Again, that may sound like it's a thing that all languages already do when you bring up simplified mental model of a codebase, but think about this next time you're hip deep in code you've never seen before and you hit the thirtieth line of code and suddenly, oh crap, it just referenced another module I've never heard of.... this is when your cognitive load goes through the roof.
- thomasmeeks 7y agoSenior leaders and people that want to get there take note: cognitive load is the base problem one solves for when scaling development organizations. This article is a pretty good introduction -- especially building with empathy and emphasizing "what" over "how". But one can also look to any tech company that provides an API devs like (my fav: Stripe) as an example of what low cognitive load relative to the problem looks like. Truly talented leaders tend to realize that high cognitive load comes from lots of places besides technical considerations too. It can be hard to think about a problem when you're also dealing with a toxic team member, untrustworthy leadership, lack of organizational focus, shitty HR policies, feeling unsafe at work, etc. Unfortunately, fighting against those elements is a never-ending battle. Leaders that mix low cognitive load with clear direction and an interesting problem start to approach that highly-sought-after "early startup productivity" that so many companies can't seem to figure out. At least until a re-org, acquisition, or change in the c-suite comes along and blows it all up.
- frequentnapper 7y agoJust also wanted to add a big factor can be personal problems as well. Many of them can't be helped, but things like transportation, commute time, local real estate prices, health insurance, etc. can be helped and should not be overlooked.
- alexpetralia 7y agoThis is super useful. I've summarized this in my head as: minimize cognitive load for stakeholders (e.g. customers, employees, investors, etc.)
- crimsonalucard 7y agoThis is why people who can't handle too much cognitive load end up being better leaders. Or in other words... less intelligent people make better leaders. On a side note, less intelligent people also write more readable code. The principle, Keep it simple stupid, aka kiss is indeed better followed by people who are described by the acronym. So in other words... A simple and stupid person is better at keeping their code and designs simple and stupid than a smart and complicated individual.
- vast 7y agoThis article was initially inspiring and interesting, but eventually I think it is a mud of "sound lies". I like the idea that human cognition has a huge impact on our lives and it certainly has. But trying to pull off a new pradigm shift on the congnition hype train is annoying. What is true for me is that even average software and systems we build can get insanely complex. To fix it, it is just suggested to reduce the product size, train / hire people. It is absolutely not wrong, but the narrative is. If we talk about congnitive load we should look at formalism. Yes it sounds awful. But having clear rules of yay's and nay's is when designing and evolving systems can clearly reduce cognitive load, because I cannot remember all the stuff people failed at in history. PS: Please don't mix up fomalisms with principles.
- bobm_kite9 7y agoThis sounds about right. Also it feels like as a paradigm shift it’s not so far from Conway’s Law already
- onemoresoop 7y agoConway's law. organizations which design systems ... are constrained to produce designs which are copies of the communication structures of these organizations. The law is based on the reasoning that in order for a software module to function, multiple authors must communicate frequently with each other. [0] https://en.wikipedia.org/wiki/Conway%27s_law https://en.wikipedia.org/wiki/Conway%27s_law
- iteriteratedone 7y agoMicroservices and monoliths have never been about cog load. Its an implementatiom detail that solves scaling, deployment and team managment problems. The cog load should be fairly similar weather you jave micro or monolith. There are good and bad abstractions but in the end the cog load is a sum of the leaves and this never changes in the tree. In fact the cog load is better with bad abstraction , or no abstraction. Hard coding is no cog load. Its in that file that function for that feature.
- stcredzero 7y agoBroadly speaking, you should attempt to minimize the intrinsic cognitive load (through training, good choice of technologies, hiring, pair programming, etc.) and eliminate extraneous cognitive load (boring or superfluous tasks or commands that add little value to retain in working memory). This will leave more space for germane cognitive load (where "value-added" thinking lies). The whole point of design is reducing cognitive load. Whenever you are looking at a given thing, you shouldn't need to keep more than about 10 things in your head to understand it completely, preferably less. Programming hardly ever blows up your brain with one fantastical concept. Instead, you're worn down with a hundred thousand cuts.
- ChrisCinelli 7y agoBeing able to keep the system you are working on in your mind with sufficient but excessive detail is key. Keeping the system in all is parts "as simple as possible and as complex as necessary" (that is my engineering philosophy) is what make se all the difference. I used to think: since I am smart I am going to write something more complex because I can manage that. Wrong. For the smart and dumb engineer a simpler system is faster to build and moreover easier to maintain. Managing dependencies (briefly mention in the article) is even more important. In a large organization what show you down the most is having to wait for somebody else. Having autonomous teams as much as possible is part of the equation to keep a growing organization able to move fast. That said everything else being equal (you are writing a good code, you have good engineers, etc), a monolithic system tends to be easier to debug (one stack trace is easier to debug than a trail of logs), the code base is usually easier to refactor. Where a monolithic system makes things harder is asynchronously deploy different parts of the system and scaling different parts of the system at a different pace. As a rule of thumb, trying to keep things in one system until it is evident where the cut should be and it is clear it is time to do it help to keep both infrastructure overhead and cognitive overload under control. But there is no silver bullet. Check also: http://www.codingthearchitecture.com/2014/07/06/distributed_big_balls_of_mud.html http://www.codingthearchitecture.com/2014/07/06/distributed_...
- draw_down 7y agoUnless you have a concrete way of measuring something as abstract as "cognitive load", the situation is as it ever was: the stuff liked by me is low cognitive load; the stuff liked by people who disagree with me is high cognitive load. (Feel free to sub in "complexity", "cohesiveness", et cetera, for "cognitive load")
- AlexCoventry 7y ago> Feel free to sub in "complexity", "cohesiveness", et cetera, for "cognitive load" "...the situation is as it ever was: the stuff liked by me is rationally oriented by reasonable goals; the stuff liked by people who disagree with me is nothing but a post-hoc rationalization of their arbitrary preferences."
- draw_down 7y agoIndeed.
- redact207 7y agoSplitting your app up based on "cognitive load" is just as bad a boundary as 100 LOC per microservice. It's an arbitrary measure and varies widely per developer. The most "correct" way I've ever seen applications divided is based on knowledge domains ala domain driven design (DDD). Drawing boundaries around the domain functionality of your business or operations means that the domain can be ignorant of other parts of your system.
- karmakaze 7y ago> Intrinsic cognitive load, which relates to aspects of the task fundamental to the problem space. Example: How is a class defined in Java? Article gets this wrong immediately. Intrinsic should be to the characteristics of the feature being developed not about the mechanics of your tools. They are secondary brought in your solution space. It bothers me when core terms are misused making it seem not worthwhile to read on.
- achou 7y agoI think the best single observation about cognitive load is in Ousterhout's book A Philosophy of Software Design[1]. In the book he promotes the idea that classes should be "deep", such that their top-level surface API is small relative to the complexity they hide underneath. This applies to the microservice/monolith debate as well. And it basically boils down to the observation that having lots of shallow services doesn't really reduce complexity. Each service may be simple unto itself, but the proliferation of many such services creates complexity at the next level of abstraction. Having well designed services with a simple API, but hide large amounts of complexity beneath, really reduces cognitive load for the system as a whole. And by "simple API" I think it's important to realize that this includes capturing as much of the complexity of error handling and exceptional cases as much as possible, so the user of the services has less to worry about when calling it. [1]: https://www.amazon.com/Philosophy-Software-Design-John-Ousterhout/dp/1732102201 https://www.amazon.com/Philosophy-Software-Design-John-Ouste...
- save_ferris 7y agoI've noticed this as well. It's much easier to find the logic I'm looking for when I can easily remember where the domain of one class ends and another begins.
- deleted 7y ago[deleted]
- averros 7y agoEvery generation of new coder kids rediscovers what their parents already knew pretty well. It's just arrogance and desire to hack away without actually being bothered to learn the craft.
- jillesvangurp 7y agoYes, Ousterhout's work is still a great read decades after he published. What people forget when doing microservices, server-less, or other 'modern' ways of breaking up software into more or less independent things is that these are just variations of decades old ways of breaking stuff up. Whether you are doing OO, modules, DCOM components, or microservices, you always end up dealing with cohesiveness and coupling. Changing how you break stuff up does not change that. Breaking stuff up is a good thing but it also introduces cost depending on how you break things up. In the case of microservices, the cost is automation overhead, deployment overhead, and runtime overhead. If your microservice is a simple thing, it might be vastly cheaper to build and run it as part of something else. I've actually gotten rid of most of the microservices and lambdas we used to have to get a grip on our deployment cost and complexity. We weren't getting a lot of value out of them being microservices. The work to get rid of this stuff was extremely straightforward.
- c3534l 7y agoMicroservices are designed differently than monoliths. The architecture enables you to easily do something. Cognitive load isn't what matters, it's the engineering. You can spin microservices up and down to meet demand. You can put them in containers to build an anti-fragile system. You can load balance them. That's much more difficult and more expensive to do with monoliths. The author is thinking of the distinction like an ivory-tower CS professor who thinks he's talking about abstractions, when you're actually talking about design and engineering.
- deleted 7y ago[deleted]
- owens99 7y agoThis should be the motto for almost everything. Forget X vs. Y. Cognitive load is what matters.
- bayesian_horse 7y agoI believe one of the main reasons for ending up with a microservice is that you just don't want to implement certain functionality yourself. If you are running things like sentry, wordpress, mediawiki, keycloak, forums etc and interconnect them in meaningful ways, that is essentially a microservices architecture.