Modern Software Over-Engineering Mistakes
medium.com
medium.com
Simple, concrete, un-abstracted code is easy to get to right, easy to read, and easy to change.
I really think DRY is far more important for business logic than it is for infrastructure logic. If you calculate what taxes someone owes in two different ways that's terrible. If you serialize two different things in your application in two different ways, probably doesn't matter.
In my own niche, software test automation, this can be a huge problem because the meat of every test stands alone from all other tests, otherwise it wouldn't be a unique and interesting test. Applying DRY naively in that kind of situation often leads to a bunch of non-cohesive "do everything but this, and based on this flag do this one different thing" type code.
You really have to jump back a level and look at things more in context of their usage. This is one of the reasons that there's debate about even sharing things like setup methods, never mind test bodies.
Sounds like the evolution of different flows described has a lot in common with this. You have to look past the lexical.
Abstraction is possibly an art and few in the IT industry are good at it. Poor attempts at abstraction underly the common anectodal experience of 'failure' to consolidate software in context of business.
But as a native mobile dev I feel a deep affection for it :P
However, I bristle a bit at a blog that misdiagnoses the problem as "over engineering". The problem is bad engineering, not over engineering.
Sounds like a good reason to avoid it.
Most of the problematic abstractions I see in the real world don’t hide much complexity but still introduce extra complexity of their own (with the latter even becoming greater than the former in the worst cases) or often leak so we still have to drill down through the abstraction to understand what’s happening anyway. Arguably, these are just two sides of the same fundamental flaw.
We have wrappers around generic web service callers that rely on factories that create classes that convert between web service objects and domain objects, all wired together using interfaces for each service class and an IoC container, with its own XML configuration file.
The irony is that if the web service were to change its interface, you'd have to change like 10 files instead of like.. a single conversion function somewhere. And to begin with you had to create those 10 files in the first place. It's absolute fucking madness.
It’s frightening how often this happens at all scales, from little utility functions with names that are several times as long as their implementations right up to the kind of enterprise architecture that nightmares are made of.
Accepted! (Did I mention anything about complexity?)
> It takes a lot of skills and deep understanding of the problem domain. A “Service runner” library needs expertise of how daemons work, process management, I/O redirection, PID files and so on. A CMS is not just about rendering fields with a datatype — it has inter-field dependencies, validations, wizards, generic renderers and so on. Even a simple “retry” library is not so simple.
In fact, dependency injection and a layered software architecture are mostly orthogonal concepts.
Broad familiarity with your tools and their applicability (design patterns or otherwise), is a prerequisite to picking a reasonable tool for a given task.
Design patterns are not a suggestion, you shouldn't strive to use them. Devs shouldn't start a project and think 'what design patterns will I use here'. They exist so that you can identify what you are already doing and avoid past mistakes that others have already made (hell, the GoF book states this in the intro). Nobody should go into a project thinking 'I will use the singleton pattern for this', but if halfway in you realize that your system fits that pattern, it's there for you.
Agreed. I almost embarked on a huge PHP mysqli>PDO conversion, and was advised the opportunity costs were huge and the benefits minimal. Glad I took that advice.
Switching was as simple as:
1. Export all data to fixtures. 2. Change settings.py to use the Postgres drive. 3. Load all data into fixtures.
Granted, I was sticking to core Django ORM calls, so I wasn't hard coding any SQL anywhere. And the null ordering does change a little, but the tests caught that.
So I was definitely glad that worked out. And have been super happy with postgres.
I think that's what made it easy. That's the trade off when you try to build a generic DB access to support the trivial DBMS swap like the article take about -- you end up writing a lowest common denominator of functionality common to all your anticipated DBMSs. I assume Django's ORM let's one do DBMS specific stuff but you happened to not make use of that.
I agree with the article, 9/10, don't try writing wrappers just to support the "easy future swap out". Write them if they make the specific technology more palatable to work with. An example I'm my life: Rails' ActiveRecord is just a joy to work with but we would be hurting plenty if we tried to swap out to a different DBMS.