IME whether you rewrite or refactor, the lesson is the same: You have to grind your way into the good architecture. It doesn't become good because the code is fresh, but because you have battle scars to show.
And a success story in that case comes from having a complete learning loop. In a lot of orgs the learning itself is argued against for one reason or another - development proceeds with as little feedback on quality as can be gotten away with.
Here's a nice quote from Jony Ive to support your point
Much of the design process is a conversation, a back-and-forth as we walk around the tables and play with the models. [Steve Jobs] doesn't like to read complex drawings. He wants to see and feel a model. He's right. I get surprised when we make a model and then realize it's rubbish, even though based on CAD renderings it looked great.
He loves coming in here because it's calm and gentle. It's a paradise if you're a visual person. There are no formal design reviews, so there are no huge decision points. Instead, we can make the decisions fluid. Since we iterate every day and never have dumb-ass presentations, we don't run into major disagreements.
>IME whether you rewrite or refactor, the lesson is the same: You have to grind your way into the good architecture.
I think that only applies to things nobody on the team's built before. From my domain, HFT, if we hire a senior dev who's built blazing-fast futures arbitrage systems working for other companies, chances are if he rewrote our system it'd have a very nice architecture from the get-go, because he's already solved a similar problem multiple times before (and learned from the mistakes in those architectures).
And then, that senior dev will pick a newer, better CPU, on-device bus, network topology, or your setup simply has a different scale, and hard-learned heuristic “don’t use more than x foo’s for y” or “the network is the bottleneck; use huge machines” become obsolete, and your dev will get some new battle scars.
I guess that will happen in HFT all the time, as you don’t want that blazing-fast setup, you want something even faster.
"Grind" your way into good architecture? Good architecture is designing, not trial-and-errored. The only grinding I do is mental before I type a single letter of code.
No good plan survives first contact with the enemy...
Less pithily, the good architecture will almost certainly end up with arbitrary patches and madness after 2 years of active use, if anyone cares about it at all... And then somebody will join and say 'This is a mess, we should refactor and/or burn it to the ground.'
I don't doubt that this could accurately reflect your experience in the industry, but it is not a universal truth. I've worked on sustaining engineering of systems that were years old, the stewardship of which involved refactoring only, and which are still in production today. There are lots of systems that are more or less right in version 1.
> There are lots of systems that are more or less right in version 1.
While true, in my experience this usually happened when at least one - if not all three - of these conditions were true:
1. The problem domain is relatively static, unmoving, and self contained
2. The systems in question is relatively small
3. The developers in question have written substantially similar systems before, or ground locally, or used version 0.x version numbers first (in any of these cases, is it really "version 1" per se?)
...game development is admittedly weak in all 3 categories, and high on time pressure. Oh sure, there's some solid code that will probably last decades in many codebases, but even the best programmers will occasionally make a system that - while good in isolation - needs reworking when combined with other systems - to say nothing of the content and rendering pipelines that vary wildly by decade.
That's certainly true in my experience. I've seen some great, readable, codebases written by solo developers that had lots of previous experience writing code in larger teams.
Caveat: it's never something that's too large or complex, of course.
> the stewardship of which involved refactoring only
I've known several such systems, and the reason they stuck with the original architecture is they wrote it in C, and it's very hard to iterate architecture in C programs. The programmers will just keep bashing the C code so it works well enough.
Yes, I know this is a provocative statement.
The reason behind it is that C's ability to encapsulate behavior is just not very good. Even simple things, like "is it an array or a linked list" leak out all over the place.
Even simpler, "is it a value or a reference type" means one has to swap "." and "->" everywhere. C++ half-fixed it by introducing reference types, D fixes it all the way by noting that "." can be unambiguously used for both operations.
To some degree that's matter of luck. Sometimes all your assumptions are correct from the start and the requirements don't change much. But often a lot of things change over time until the first architecture doesn't fit anymore. I would agree there are better and worse architects but luck definitely plays a role.
Yeah it is always important in such discussions to remember how vastly different development can be. Developing embedded software for an appliance have vastly different constraints compared to a web app startup which pivot every three months.
It's funny to say, but I can't agree. I've designed and implemented many custom systems for which there was never a predecessor, and not only did it work splendidly at first release, but have been extended and enhanced many times over the years with no refactoring. Many of these systems have been extended enough to start taking over other systems that were never intended.
Design a system to be modular from the very beginning with only the most fundamental of API signatures and you win. Many of these signatures may even no-op for years, but because they're fundamental to the problem, you know there could be a case where they're needed.
I've never had a failed or late project and most of my projects are ones that were assigned to me because no other team would touch them due to all of the attention and required SLAs.
Nonsense. Competent designers with 8 or 10 years experience should absolutely be capable of architecting a solid system that is cleanly extensible for forseeable business requirements.
Probably one huge confounding factor, however, is the continual drive by juniors (or supposed seniors who think like juniors) to use the latest & shiniest technologies. These of course these are unknown to the team, of questionable long-term suitability and introduced without knowledge of the "right" way to use them.
In the article the OP describes using Elixir without A) needing it or B) being able to handle its downsides. Plus many random versions of Angular and React. Plus the overheads of an excessive focus on SOA.
My emphasis in architecture is on using simple & strong tools, and delivering great architecture in the problem space. Configurability, extensibility and DSLs are my forte. I don't need a new language -- I know how to use the ones I've got.
Certainly possible to make a good one on the first try. A great one? Probably not, unless you are doing something absolutely trivial and done several times before, like a CRUD app.
>It's so much easier to build things incrementally.
I would say its much easier if you know what you are building in advance. Building incrementally is usually more about exploring ambiguous ideas and not having a clear vision in my experience.
And a success story in that case comes from having a complete learning loop. In a lot of orgs the learning itself is argued against for one reason or another - development proceeds with as little feedback on quality as can be gotten away with.