▲ | usernamed7 6 days ago | |||||||
One thing i would add, is that a well designed system is often one that is optimized for change. It is rare that a service remains static and unchanging; browsers and libraries are regularly updated, after all. Thus if/when a developer takes on a feature ticket to add or change XYZ, it should be easy to reason about and have predictable side-effects of how that change will impact the system, and ideally be easy to change as well. | ||||||||
▲ | bbkane 5 days ago | parent | next [-] | |||||||
"optimized for change" really only works well if you can predict the incoming changes. Common tools used for this "optimization" often raise the complexity and lower the performance of the system. For example, a db with a single table with just a key and a value is very flexible and "optimized for change" but it offers lower performance (in most cases) and is harder to reason about. I also frequently see people (me too) prematurely make abstractions (interfaces, extra tables, etc) because they're "optimizing for change". Then that part never changes OR it changes in a way that their abstraction doesn't abstract over OR they figure out a better abstraction later on when the app has matured a bit. Then that part of the code is at best wasted space (usually it needs to be rewritten yet no one gets time to do that). Of course, it's also foolish to say "never abstract". I almost always find it worth it to abstract over I/O, just so I can easily add logging, dual writes, or mock it. And when a change is obviously coming down the line it makes sense to plan for it. But usually I'm served best by trying to keep most of my computation pure functions (easy to test), doing as little as possible in the I/O path (it should just persist or print stuff so I can mock it) and otherwise write obvious "deletable" code that does one thing so I can debug it and, only if necessary, replace with a better abstraction if I need to. | ||||||||
| ||||||||
▲ | mrkeen 5 days ago | parent | prev | next [-] | |||||||
And you get this part somewhat for free if you're actually testing as you're going. When my service wants to store and retrieve as part of its behaviour, of course I'm going to back it with a hashmap first. Once I know it fulfills its business logic I'll start fiddling with hard-to-change stuff like DB schemas and migrations. And having finished and tested the logic, I'll have a much better idea of the actual access patterns so I can design good tables & indexes. | ||||||||
▲ | paintistjksgf 5 days ago | parent | prev | next [-] | |||||||
While I think one shouldn't paint themselves into a complete corner, but optimizing for changeability signals a lot of abstract complexity to me, which takes time, which in turn takes money. We can usually have many more cheaper dedicated services for doing a thing that accounts for more good than a single service that grows to become more and more omnipotent. It also means you're much likely to win contracts because you can price yourself competitively | ||||||||
▲ | setnone 5 days ago | parent | prev [-] | |||||||
Some systems are designed to last vs. designed to adapt |