Join the discussion
Write your take first — we'll ask for email only when you're ready to publish.
- Hacker News
- As relates to Systems Engineering: Software architecture is like plumbing architecture. It's certainly very important, but you don't live in plumbing pipes, you live in a house with plumbing. If your plumbing doesn't take the rest of the house into account, it could be a very expensive fix.by 0xbadcafebee
- Nice read. “ Learning Software Architecture” means understanding that there is no single good answer. It is art and science.
Read tip: Simplify IT - The art and science towards simpler IT solution https://nocomplexity.com/documents/reports/SimplifyIT.pdf
by runningmike - The Gary Bernhardt talk is truly special. Lots of concepts which will lead you to other interesting placesby abhik24
- I think this really down plays the value of mental model or strategies for organizing code. Take a compiler: often described as a sequence of transformations on an AST, taken to the extreme in the nanopass framework. That's a really useful mental model, and you can extract that model and apply it in other contexts. For example, many business applications are a sequence of transformations on JSON. So they're basically compilers. That can be good architecture in the right situation.
You don't have to call a sequence of transformations a compiler. You can say your AST is an algebraic data type, and your transformations are folds (or structural recursions; same thing). Now you have an abstract model that isn't tied to a particular application, and you can more easily find uses for it.
If you know a bit of maths you might wonder about duals. You will find codata---objects---are the dual of algebraic data. Ok, now we're programming to interfaces. That's also useful in the right context. What's the dual of a fold? An unfold! So now we have another way of looking at transformations, from the point of view of what they produce instead of what they consume. At this point we've basically reinvented reactive programming. And on and on it goes.
You can find most of this in the literature, just not usually presented in a compact and easy to understand form.
(Note, the above description is very quick sketch and I'm not expecting anyone to understand all the details from it alone.)
Shameless self promotion: the book I'm writing is about all these concepts. You can find it here: https://functionalprogrammingstrategies.com/
by noelwelsh - I’m not sure what part of the article this is attempting to critique.
But I would say that just because your preferred mental model is an abstract algebraic one where you build an abstract model that can apply to multiple situations doesn’t mean that such an architecture is best for every situation.
The article talks very clearly about the system and social constraints that it is optimizing for architecturally and ‘turning everything into a fold’ doesn’t immediately strike me as helping to meet the fast-build-feedback needs of the deep contributors and easy-and-safe-to-hack-in-modules needs of the weekend warrriors, which is what are described as the goals of the architecture.
But it also doesn’t strike me as very clearly not the case that the architecture has some of the features you’re describing.
It feels rather like you have a pet mental model which you think all architecture should subscribe to, and… I’m sorry but that seems naive.
by jameshart - I would like to spend my time more on gaining a mental model of the projects I work on, but I get very demotivated if I start disliking things like the programming language, certain arch. Choices or anything that gets too complex that doesn't seem like its worth my time
It's heavily dependent on the project, but I feel like working as a "fullstack dev" kind of removes the fun of programming. I'm already spending 40 hrs a week looking at the most dull project I can imagine
by ramon156 - Sounds like you need better emotional regulation.by ambicapter
- Analysis paralysis is a danger always - don't aim for perfect, but aim for flexible. Make sure the decisions you're spending the most time on are the most important.
A well designed data structure is far more impactful on performance and maintainability than framework, language or platform.
Personally, I work alongside ADHD every day so I need to constantly push to make sure that progress is happening which means picking unimportant decisions and resolving them to focus the remaining open problem space on the decisions that require a lot of careful thought.
by munk-a - > I would like to spend my time more on gaining a mental model of the projects I work on, but I get very demotivated if I start disliking things like the programming language, certain arch. Choices or anything that gets too complex that doesn't seem like its worth my time
Let it go...
Not one single project is free of warts. Not a one. And honestly, if the programming language is that big a deal, you're better off jumping ship. We should all be polyglots, but that's up to you.
by HumblyTossed - I'm surprised that it seems no-one has brought up Residuality (see https://www.architecture-weekly.com/p/residuality-theory-a-r...) which is a very interesting take on architecture (as opposed to design) which aligns with my own experiences.
As well as the book (https://leanpub.com/residuality) the author has one on the philosophy of architecture (https://leanpub.com/architectsparadox).
by finnnk - Residuality is very interesting. Have you used it in practice?by 4b11b4
- Wanted to say thanks for posting this. I found the NDC talk interesting and well presented. Will try to read more about it and, as an exercise, try applying it to my own solutions to see what insights I could gain.by grusgrus
- I think there is huge space for architecture case studies that help a non coder learn how to critique llm architecture decisions.
I’m a NP - lots of learning came in clinical rotations where you see real life situations and how they are addressed. I want something like this for software architecture.
The closest I’ve seen is the open source case study books referenced previously but these are older.
I’d like to be able to see explanations at various layers of abstraction about why certain decisions are made or not.
by npl - Nurse Practitioner? I would say SOLID [1] is a good start, but then I watched this [2] and now I'm in crisis and can't code anymore.
[1]: https://en.wikipedia.org/wiki/SOLID [2]: https://www.youtube.com/watch?v=wo84LFzx5nI
by theteapot - I think that words like "clean code" or "beautiful code" does help juniors to learn best practices of software architecture.
I prefer when people are able to define a clear list of objectives:- Junior asks to senior: what did you we use an ORM ? - senior answers: because it's cleaner. - junior: ???
Each criteria balance the others, and the more we add criteria the more it helps to make good choice when we hesitate. It is also meaningful for people outside of the dev team, we can reach an agreement with the customer so he knows what he pays for.- maintenable; - performant, scalable; - efficient; - resilient; - observable; - testable (and tested); - secured; - readable for new devs that come on board."maintenable" can be also defined, since a project is mostly in maintenance mode during its lifetime (which means the project is successful, which is good !). The ability to incorporate new features without breaking architecture or even without breaking a single method signature is a good starting point.
Being super careful with abstractions. Here someone wrote something like that: "abstraction often hides how what you want is simple". True, ORM I am looking at you. In most case data should be threaten as first class citizen, it also fosters good collaboration with the DBA.
Thinking beyond "the happy path" without falling in premature optimization is also a challenge. A nice one, once again to it avoids to go head first in implementing a good idea without considering drawbacks.
I also tend to imagine that the one that will work on my code had a very bad day so it must be pleasant to read what I wrote. Comments here and there, locale variable here and there even if they can be avoided, variable naming, etc...
Being selective about frameworks. They are good servant but bad leaders. "Be an engineer, not a frameworker" says an article.
by ah1508 - Modular frameworks are worth their weight in gold when compared to "highly opinionated frameworks". I don't mind something that's highly opinionated - and highly opinionated is an excellent trait for a library or tool. That lib/tool likely has a large amount of domain expertise in the particular area it operates in.
When it comes to frameworks - highly opinionated tends to get corrupted into "We have this hammer and suddenly everything looks like a nail" - it doesn't always happen and it doesn't always bite you but when orthodoxies are taken from one domain and applied broadly you run the risk of some of the justifications for that orthodoxy being domain specific and being violated in the wider context.
So, when it comes to frameworks, I like modularity where I have options to plug in a different ORM or persistence integration layer - where I can swap out the router - or the validator - or any other component that proves a poor fit for our problem. It is especially valuable if there are multiple paradigms expressed in alternatives within the framework's ecosystem since you may find a pre-baked tool that mostly works where you can choose an option with shortcomings that are clear and addressable if ever the need arises.
To support maintainability it's very important to fight against NIH-ism, that is a constant danger that can soak up resources at an alarming pace - but it's also important to realize that there are some components that you will greatly benefit from tweaking or taking full ownership of with the most difficult problem being trying to figure out which is which.
I appreciate deeply that your list put maintainability first - that's my opinion as well!
by munk-a - In this vein, I really recommend "Architecture of Open Source Applications."[1] It's a book series where you learn architecture by example, with each chapter written by a maintainer of the project in question. This lets you learn not only what the architecture is, but what are the constraints that shaped it, usually history and changing project visions.
Not all chapters are equally good or equally interesting, that's the curse of a multi-author book, and all of them are dated, but I think the book is worth reading nonetheless.
by miki123211 - The best way to learn architecture is to:
1. Maintain a large enough project. Not create, but support.
2. Do it for at least couple or few projects.
If project is too small, any architecture works fine. "Large" can be in terms of lines of code, but better in terms of people who ever worked on it, or even better -- teams.
At least two different projects is to have something to compare. I've seen people stuck for decades on one project and not knowing any modern ways to solve a problem.
But often the architects who get promoted because they created, not maintained a project. Especially visible in Google, as you don't get promoted for maintaining anything, only for shipping something new (and better jumping off as soon as possible afterwards).
Counterintuitively, people in the best position to be architects are actually side contractors from head shops, who get invited to maintain an existing project no one from a company is willing to (as they all jumped off where promotions go). First, they have to maintain an architecture, and second they did it on several projects, so can compare. The downside though, is if they bill by the hour, the tend to over-complicate architecture to bill more hours.
by deepsun - The recommendations are often very good, for example Ousterhouts A Philosophy of Software Design, but seem to be on software development in general, not actually software architecture in particular.
For that, I would recommend the classic texts, such as Software Architecture: Perspectives on an Emerging Discipline (Shaw/Garlan) and really anything you can find by Mary Shaw. Including more recent papers that explore why the field of software architecture did not go the way they foresaw, for example Myths and Mythconceptions: What Does It Mean to Be a Programming Language, Anyhow? or Revisiting Abstractions for Software Architecture and Tools to Support Them
More practically: look at why Unix pipes and filters and REST are successful, and where they fall down and why. Hexagonal architecture is also key.
And a plug for my own contribution, linking software architecture with metaobject protocols as a new foundation for programming languages and programming: Beyond Procedure Calls as Component Glue: Connectors Deserve Metaclass Status. An answer to Mary Shaw's Procedure Calls Are the Assembly Language of Software Interconnection: Connectors Deserve First-Class Status.
Answering the question: if procedure calls are the assembly language, what might a high level language look like? And also maybe that software architecture might have a brighter and more practical future ahead of itself.
by mpweiher - What is hexagonal architecture?by sroerick
- > if procedure calls are the assembly language, what might a high level language look like?
I’m not well versed in PLT and SWE tooling, but isn’t that the base concept around lambda calculus, LISP, APL, clojure, TCL,…? You only need a few data structures and types, a small collection of fundamental functions, then you compose them.
If there’s one thing that I like about Lisp is that more complex type are always opaque (especially the ones from FFI). I would love to see CLOS implementation for a C-like language, where when you define a struct, what you get is a standard collection of functions.
by skydhash - I'll give you the cheat sheet:
- Good design is a single idea pervaded throughout.
- More generally, your goal should be to minimize surprise.
- If your system allows it, people will do it.
- Everyone will not just. If your solution starts with "if everyone will just..." then you don't have a solution.
- Isolate the parts of your system that transform data from the ones that use it. Data models outlive code.
- Coupling is the root of most evil.
- Versioning is inevitable.
- Make state explicit.
- Every piece of information should have a single source of truth.
- You should spend more time thinking about naming things correctly.
- If testing is difficult, the design is wrong.
- You will regret every undocumented decision.
- Communication is a tax that you should justify before paying it.
Remember that the job of an engineer at any level is to use rules of thumb to solve problems for which there is incomplete information.
by CSMastermind - I don't actually think this has much to do with software architecture. Except maybe the "Isolate parts of your system..."
In fact the article itself didn't really seem to be too coherent on software architecture. I think the 4+1 view of software architecture is a good conceptual way to think about things (minus all the UML). It's not a complete picture but it addresses the bigger picture. The book series Pattern-Oriented Software Architecture is pretty good and outlines a number of architectures people tend to land on. One stage Grady Booch was working on a handbook of software architecture, but seems to be kind of dead ish, but he did have a mailing list where he'd go to companies or look at large open source projects and look document big system architectures (and some smaller scale), not sure where you can see this anymore. All of these things are worth diving into if you want to learn about software architecture. You can see these architectures are built for different focuses, things like scale, safety, performance, interoperability, failsafe, etc. i.e. there are very specific goals of an architecture with very real tradeoffs.
by keithnz - I work in this space as well - I know that my particular work is much less abstract (we're modeling the healthcare industry) than some others.
But as a designer of the system you must understand the industry and while you don't need to embrace their terminology and modeling habits fully, you must understand their rationale and how they view the data set. There are some places where we've intentionally simplified complications of the healthcare market to eliminate needless (to us) over definitions and provide a more unified modeling. But these changes took significant comprehension of the problem area to make with confidence.
> You should spend more time thinking about naming things correctly.
On this point in particular. Names never die - that's a lie, occasionally they do, but it takes an extreme amount of effort to enforce a renaming. It really is worth spending a big bulk of time letting SMEs stew with naming proposals to make sure you bases are covered. You can force through a few concepts but your business wing (sales, marketing) will constantly put pressure on you towards industry terminology and force your model to adhere to the current view of the industry. If you decide to break with that that break must be decisive and obvious in intent.
Oh, the single biggest attribute of software to emphasize is maintainability. How much will this cost to build is one question - how much will this cost to run (not just infra but compounding feature requests and code refactoring and maintaining third party software versions etc...) is the far more impactful.
by munk-a - Missing the single most important thing, that people seemingly are purposefully trying to avoid nowadays for some reason:
- It depends
No solution I've come across, is a solution for everything, everywhere. It's almost always context dependent, and something that is right in one place, can be utterly wrong in another, and there is no universal truths regarding design and architecture.
The more flexible you can be with "right tool for the right job", the easier time you'll have designing, because you're no longer trying to shoehorn in things that are "right" and "correct".
> - You should spend more time thinking about naming things correctly.
This should almost be on the list twice too, the amount of people who couldn't care less about naming, is so damn high, but if people just cared a tiny bit, it'd solve so much future confusion. Whenever I get pulled into helping a "legacy project" or whatever, establishing a "true vocabulary" based on what people actually call things, is the very first thing to do, because it always uncovers that people been talking about different things the entire time.
- As a corollary to
> Communication is a tax that you should justify before paying it.
> Every piece of information should have a single source of truth.
- Do as much as possible on a single system and minimize sharing state.
- Recognize that every system is distributed, it's just a question of how and where.
One of the biggest ills I observe with most modern software systems is that we've gone full tilt towards things like microservices which require synchronizing state across multiple interdependent parts. Regardless of how clean the abstractions or how well contracted the APIs, doing all of that copying and state synchronization is going to result in problems: performance problems, cost problems, and synchronicity problems.
by tristor - Good architecture is not about the patterns you pick. It’s about having a team dev cohesively on any pattern(s)
- programmatically enforce your style with in-house linters and scaffolders. Be highly opinionated
- if you # ignore anything, leave a comment explaining why
- use bdd so your cases are human readable and must update with the code (unlike a stale comment)
- follow the same pattern in all your services (I love hexagonal design for backend). If you break from the design have a good reason for it
- COMPOSE your code. It’s almost always the case that two endpoints or jobs or whatever happen to have a few things in common, but differ wildly. Don’t get DRY, just import those things in each spot and don’t entangle them with each other, it’s too confusing
- scope your interfaces tightly. No optional params unless the domain is actually optional. Make separate jobs or endpoints for different configs. I can’t figure out wtf all your configs were from 4 years ago and neither can you
- code is default testable with DI/DIP
- always run tests running real infra like testcontainers - cement ci/cd as your guardian. Employ every linter you can.
- hammer workarounds with comments in the code
- break all systems into small problems and nothing is challenging technically (though the domain might be!)
- work with less people on your code. It’s easier to stay aligned and follow the same patterns
- don’t expect anyone to figure it out. You need to champion your changes. Do code reviews, hold their hand, show them the way
- clear out mundane items like installfests, local auth, server reloads. Slow dev pisses people off
- finally, and most important, employ an org policy for review. Don’t let shit fall through the cracks unknowingly. It compounds. You have skills now as a quick and dirty to eval and enforce. Use them!
by dirtbag__dad - I wish I could buy you a beer, as this is very validating. I have been building a video game for over a year. But more importantly I have been building a sustainable engine with a distinct data pipeline, resource rendering/management layer fully decoupled, explicit catalogueing of viable state transformation modes, and honestly, most of your list is absolutely applicable. Even tho it is solo, the constraints of my engine guides forgetful me to 'this is the way to add this weird new feature that arose from testing because reasons' without having to have a tome of 'if you want to build a new sound effect that executes at a particular state transformation multiple times, here is how you do it'
Cheers
by RobRivera - I'd add
- data migrations are inevitable and should be planned for (corollary of versioning)
- planning is good, sometimes you just have to try things out
- everything costs money. Designing without costs in mind will force hard choices down the line
by laszlojamf - I don't agree with all of these, but I'll add a couple of my own:
- The ultimate goal of software is to solve the immediate problem at hand. The secondary goal of software is to solve likely future problems with as little work as possible. Any bad design which is better on those goals than a good design is actually a good design.
- Make your interfaces easy to use correctly and hard to misuse. Think of how people unfamiliar to the project will interact with them, make the obvious way be the correct way.
- Correct code should be easy to write; suspicious code should stand out.
- Shift bugs left.
- Fixing a bug class is better than fixing a bug.
- Interfaces are harder to change than implementations. An ugly implementation is ok if it has the correct interface.
- Use comments and documentation to explain why the code is the way it is. If it feels like there's a simpler way to do it, but that simpler way wouldn't actually work due to a constraint some people may be unaware of, document that.
- Don't repeat yourself; when it comes to data. If you store a single fact in multiple places; those places will inevitably get out of sync, and that causes bugs.
- There's a cost to straying off the well-trodden path. Don't be afraid to do so when it's truly worth it, but don't underestimate that cost. Worse (boring) technology is often better technology.
- Think in terms of expected value. Think not "Is this thing worth doing?", but "Is this thing worth doing, compared to the other things we could be doing instead?"
- Even if you think you're smarter than everybody else, intelligence isn't always enough, some problems can't be discovered until they happen. Other people have worked longer on this problem than you have. Learn from their mistakes.
- Friction is the silent killer.
by miki123211