6 ms·
I disagree with you. Introducing a database too early is overengineering. My first principle is KISS. I have encountered code that was similar to the example: i
by webreac 6y ago
I disagree with you. Introducing a database too early is overengineering. My first principle is KISS. I have encountered code that was similar to the example: it was the handling of messages received from automatas in a nuclear plant. I have done some refactoring so that the code had a structure closer to the specification (we had very good specifications). It was quite similar to the third example with recipes.
- edejong 6y agoI tend to think people underestimate the hidden complexity of sequential programming. Each statement has a potential, opaque effect on the complete state. To prove anything in the OP solution would be extremely complex. To extract new knowledge and abstract the solution in the future would be nearly impossible without a complete rewrite. For example: what if we need logging? Timing of the steps taken? A list of dish washing tasks generated? Parallelism in the tasks, given an extra cook? Exception control? Unit testing of the dough? Adding an extra recipe is not the only possible new requirement you can have. Anticipating and preparing the right abstractions, that’s what good software engineering is about.
- cjfd 6y ago"Anticipating and preparing the right abstractions, that’s what good software engineering is about." I find this a rather surprising statement. It sounds almost like something from some weird parallel universe. In my universe I generally take for granted that anticipating abstractions is not something that actually works. Let me give an example. Some years ago I was working on some code that was writing and reading data from a database. A colleague said that we need validation so every field that can be written to the database needs to have the ability to have a validation. So, optionally a validate function can be attached to each and every database field. I was against it at the time because as I stated I do not believe in anticipated abstractions. But the colleague was convinced that it was necessary and wrote this. A few years later indeed validations had been added but literally all validations where about properties that a set of fields together should have and literally none of them were about single fields. At some point I just deleted the single field validator. It had been there for years but it never was anything besides completely useless. To me anticipating abstractions is a recipe for all kinds of over-engineering. The need for abstractions arises as more requirements need to be fulfilled and when writing those one should probably think about what is likely going to be desired in the future but anticipating them before it is needed is something I have given up a long time ago.
- AlphaSite 6y agoIf your familiar enough with the problem, you can usually predict fundamental requirements and design in anticipation of them.
- edejong 6y agoI think there is an important difference between anticipating abstractions and actually abstracting. In your example, you were actually implementing an abstraction and anticipating a future use. That is something completely different. What I am trying to bring across is: there are multiple 'simplest' solutions. It helps to know how, in the future, you are expecting to abstract away from that solution to newer 'simplest' solutions. For example, one might want to use a FP-ish approach, because simplest solutions within that space tend to abstract better than an OOP approach. Or in the recipe example, we could have modeled the steps as objects with dependencies. Given the right programming language, that solution might be as simple as the OP, but provide many more extension points.
- quietbritishjim 6y agoI absolutely agree with this. I always like to say, the best way to make code extensible in future is to make it do its current job as simply and clearly as possible. If you leave a hook in for some feature you "know" is coming you'll only screw it up - either that feature won't be needed or it'll look different than you expect. Your field validator is a great specific example, I think I'll use that one in future. (A corollary of this though is that you have to be happy to ruthlessly refactor existing code when a new requirement actually does enter the scene, because of course that requirement was deliberately not prepared for in the existing code.)
- 978e4721a 6y agoI completely agree. One thing I would add that you shouldn't anticipate abstractions, but find them through business domain analysis. Exactly like OP missed that there's ingredients, recipe and equipment.
- edejong 6y agoThanks. I intentionally stayed outside of the business domain, since I believe it is a subset of the problem domain. But, then again, I agree the orientation should be around the added value and as such, most likely, the business domain.
- krzepah 6y agoProgrammers write code. Good programmers think about data movement
- sbergot 6y agoGood programmers know how to "grow" software. Starting with the right level of simplicity, and adding complexity when needed.
- krzepah 6y agoHonestly in the real world you would generally already know if the need expressed is meant to be a web service (for instance) and if it requires a database - and in those cases, most framework already propose an sqlite / fully-fleged database in the same code. If we already know that a database might be required later then using something like sqlite straight is smart move that would allow you to write code that is instantly going to work when you actually need something fully fledged instead of re-writing it. Knowing if you need a database or not is simply one of the first things you know, and writing code before setting that up is a waste of time or a learning process.
- sbergot 6y agoIt is not whether you need a database or not. It is "how configurable/dynamic things should be". More configurability usually means more power to your users and more pain to maintain the software. So I usually go to the least amount of configurability and then add things when required. The same goes for abstractions (you often need more of them when things becomes more configurable)