You can have the most beautiful perfect design that leverages the greatest abstractions in the world, and then have it all entirely destroyed by a single requirement shift that totally kills your abstractions.
You can have the most beautiful perfect design that leverages the greatest abstractions in the world, and then have it all entirely destroyed by a single requirement shift that totally kills your abstractions.
To the second point, I'd say I'm in violent agreement with you. In fact, my whole thesis is that because software mutates all the time, it is observed that successful software mutates successfully.
Obnoxiously quoting self:
> Unlike all other machines, it is pure concept, and as such it is infinitely malleable and mutable. And mutate it does, all the time.
and several paragraphs below that...
> Not only does all software mutate, we also end up performing all kinds of deep surgery on the organisation that produces it. The whole thing—product and org—is simultaneously flexed, reconfigured, and even totally redesigned in-place with rapidity that is very uncommon in other industries. Why? Because software fundamentally is peoples' thoughts being played on repeat.
There are likely a lot of safe bets, but even choices that once made sense can become an issue later.
One of my own quality metrics that almost everyone rejects is a "a good design is a design where a change that seems like a small change to management is... a small change"
It plays out like this. To get to product-market fit you are going to have to zig and zag 20 times. Everybody optimizes for the first step of this journey and then on the second step they optimize for that... and by step 5 or so the archiecture is exhausted and you have no hope of getting to step 20. The rare team that is looking ahead 20 steps is the one that survives.
Make step 1 as simple as possible, step 1 is small and changes are cheap, you can even rewrite everything with little effort, no need to prepare for anything at this point.
Step 2-4 will inevitably break something, no big deal, rewrite the parts that need to be rewritten, it is still cheap.
At step 5 rewrites are starting to get costly, but now you have a better idea of what is here to stay, so it is now time to invest in things like regression testing, style guides, etc...
At step 10, you have quite a history, rewrites become a really bad idea, no turning back after that. So now it is time to think about the future. The difference from doing that in step 1 is that you now have 10 steps of experience and only need to look ahead 10 steps.
It not being "exhausted" is just what distinguishes a good programmer from a bad one. If you're good you can keep a lid on tech debt in the face of rapidly changing requirements. If you suck at it, well... you can't.
>The rare team that is looking ahead 20 steps is the one that survives.
lol no good software engineering means assuming that you don't have a crystal ball (because you never will) and building accordingly.
This usually means YAGNI, minimizing up front design and refactoring aggressively. These are the things that keep you agile enough to move in many different potential directions in response to different potential futures.
The time when this really got rammed home for me was working on a startup where a political black swan event ended up changing key requirements of our software overnight. This pulled the optimal architecture in a wildly different direction to where we anticipated it was going in the previous week.
Every drop of tech debt (aside from AI slop) I have ever been a part of has manifested simply because some manager or executive made the decision to sacrifice quality for short-term speed. Sometimes this looks like an unskilled developers producing something that management won't let you fix. Sometimes it's a completely unrealistic deadline that requires extreme measures to meet. If you are able to keep a lid on tech debug in the face of rapidly changing requirements, it likely means that you have enough slack in your job to do so.
Half of my job as a lead is to cajole, threaten and convince juniors into spending 5 days on a ticket to do it properly rather than spending 2 in order to get brownie points for "looking" productive.
Ive had more than one call where the junior says "we don't have time for that" and I have to call in the PM to let them know that it's OK, we do.
There are environments where management put so much pressure on you that you can't help but deliver crap but not everywhere has to be like that.
The whole point of being agile is to design your software architecture to be agile. That's what I do. And it works.
So the real question is what exactly do you mean by "immediately"? There are many answers with different pros/cons and cost. And I bet the solution won't impact 99% of the software Facebook has already written.
If that's the case, then your example doesn't really address what we're discussing: whether software can be designed to remain flexible under realistic requirement changes.
A stronger argument would be to give an example of a realistic requirement change that would force all possible software architecture to be rewritten from scratch. Do you have an example like that?
No, read my comment again. They could do it but it would absolutely destroy the responsiveness of the app.
It's also a requirement programmers often overemphasise due to the McNamara fallacy.
Ive seen many a programmer gagging to rearchitect to speed up an app 2x or 3x when there are 9 other things a customer genuinely wants first and the programmer refuses to believe it.
Most recently it was on a RAG system where an extra 500ms would surely have been appreciated but the right answer mattered 100x more.
I've spent 30+ years building large-scale software, and it has never happened to me. Good software design lets you accommodate even major requirement changes with minimal changes to the code.
So are you saying Lisp somehow makes software flexible enough to handle any requirement change, no matter how badly it's written?
Really?
Lisp doesn't have any unique feature that makes this possible. Macros, meta programming, and single type systems all exist in other languages too.
> If you're using C++, then chances are you're going to have to heavily overengineer the thing to cover all possible requirement changes.
I disagree. My experience has been the opposite.
I maintain a large C++ codebase used by companies around the world. I spend almost all my time adding features and almost none fixing production bugs. The code is flexible because it's well designed and well tested.
The language isn't what's important. Good design and good testing make software flexible. Poor design doesn't, no matter what language you use.