The whole things kinda read as an idealistic and very wrong view of software engineering.
If you take a look at "real" code out there and it's evolution, you'll find that the main thing that drives it is the set of requirements. On the other side you have the platform (standard and 3rd party libraries as well as frameworks). Add to that is the set of algorithmic techniques (including design patterns).
By analyzing the requirements, you will discern that often they're composed of sub-problems that are generic (which is where you algorithms techniques comes in). And some are already solved (libraries). Often there's a common shape to the requirements (or some of them) that can be extracted into "frameworks".
So what's left then is the assembly. But often requirements are evolving concepts. So you don't want your structure (architecture) to be that rigid. You can't really know the direction of evolution, so you try to predict it in some way and add flexibility in a few places. This is more an art, but there are general techniques that works well enough.
The assembly itself is a matter of data and process. How each module is initialized, its lifecycle, which data it consumes, which data it produces. A program is always part of an information system. Means data come in, got processed, and go out. And here is the majority of development type is consumed, ensuring that the data is correctly processed.
Programming concepts like type checking, memory safety, paradigms (oop, functional, relational,...), formal verification,... are all about data. Code always come in second place. So think hard about your data and its transformation.
> The whole things kinda read as an idealistic and very wrong view of software engineering.
You have not correctly understood what i wrote.
The above is a battle-tested methodology based on experience/studies/trial-and-error and now being adapted to AI with extra tweaks. Labour which was the main bottleneck earlier is now cheap and hence we can afford to be "idealistic" since the tool is immensely powerful.
You need to expand and iterate each stage above (both individually and as a group with previous stages) in stepwise-refinement to get to what you want.
The rest of your comment is just generic platitudes and some common red herrings which i often see on HN, viz.
> main thing that drives it is the set of requirements...By analyzing the requirements,..But often requirements are evolving concepts.
Everybody just keeps parroting this without understanding. Requirements change but always in a staged manner and not willy-nilly. Hence there is always a window of time when your "Requirements Document" is frozen and you can implement a PoC/Prototype against it. The is the "naive" MVP i mention above. Later when requirements change you reiterate and regenerate your prototype and continue.
Note that the gp already had his UML design and only wanted a way to convert it to code. Hence i did not discuss requirements gathering and analysis here. Nonetheless, i had discussed this earlier in some previous comments - https://news.ycombinator.com/item?id=48274873 https://news.ycombinator.com/item?id=48264680
> Platform...libraries...frameworks...design patterns...
These are all covered under (1.c) above where you explicitly list out what to use and what not to use. These are all part of the "architectural constraints".
> So what's left then is the assembly...So you don't want your structure (architecture) to be that rigid. You can't really know the direction of evolution, so you try to predict it in some way and add flexibility in a few places. This is more an art, but there are general techniques that works well enough.
This is covered under (1) above where i enforce rigid adherence to "modularity" and "separation of concerns" by making each module's public interface narrow and extensible (eg. ioctl like) and its parameters future-proof by using versioned struct/class inheritance (eg. sockaddr). These are all well-known code patterns used in OS implementations/libraries.
> The assembly itself is a matter of data and process. How each module is initialized, its lifecycle, which data it consumes, which data it produces.
This is taken care of by having modules follow the LKM model with ioctl interface as explained above.
> Programming concepts like type checking, memory safety, paradigms (oop, functional, relational,...), formal verification,... are all about data. Code always come in second place. So think hard about your data and its transformation.
DbC methodology is the quintessential "data-driven" programming since the pre/post/inv are predicates to establish sets of data values on which the subsequent code can operate safely i.e. DbC establishes the data path for the code.