Domain-driven design is all about this.
31,993 karma · joined July 21, 2008
Domain-driven design is all about this.
What exactly makes it more discoverable than, say, pointing the AI to an OpenAPI spec?
True, when focusing only on the schemas as code. But good tooling could provide links and similar.
> do you have something public to show
Just a very early PoC [0]. I'm slowly working my way through a very long to-do list of improvements, but I'm lacking time and resources to do it more efficiently.
People tend to underestimate how cold it gets in the interior of countries generally seen as the "sunny Mediterranean" - from Croatia, Montenegro, Albania and even Greece.
Knowing how this industry works, good luck making something like this a reality, especially in a single country. Even if the EU tried enforcing something like that (with the UK piggybacking on it), it is still a small portion of the market.
Sadly, this is not a technical problem, but a political one. That said, I agree with you, and we can always dream.
There are two options:
1. A dongle with GPS, mobile connectivity and some other features would be installed to all vehicles. This makes it easy to implement the system, but would be a logistical nightmare.
2. The government could receive information directly from the manufacturers, but that a) can be a privacy nightmare, b) would work only on cars manufactured after 2016 or so, and c) is insanely complex to implement, due to differences and incompleteness of various manufacturer's API implementations (source: I worked on one such system).
One solution that comes to mind is to use the same technology that already exists for traffic violations: when a vehicle enters or leaves the motorway it would get its licence plate scanned, and a fee would be applied to that vehicle's account. The owner can then be charged in a number of different ways - immediately, or periodically, or after a certain threshold was reached - whichever is the most practical.
The new versions 7 and 8 are really a must these days, especially v7.
[0] https://en.wikipedia.org/wiki/Jamie_Zawinski#Zawinski's_Law
1. The domain entities, which are normally represented as native objects in our codebase. They have no idea whether they need to be persisted and how.
2. The database entities, which are - in RDBs at least - represented by tables.
It is not uncommon that our entities of the first type can easily be mapped 1:1 to our entities of the second type - but that is far from guaranteed. Even if this is the case, the entities will be different because of the differences between the two "worlds": for example, Python's integer type doesn't have a direct equivalent in, say, PostgreSQL (it has to be converted into smallint, integer, bigint or numeric).
In my "correction" above I was talking about the domain entities, and my phrasing that they "need database access" is not fully correct; it should have been "need to be persisted", to be pedantic.
Let me correct you: for each entity that needs database access. This is why I'm talking about layers here: sometimes entities are never persisted directly, but only as "parts" or "relations" of other entities; in other cases you might have a very complex persistence implementation (e.g. some entities are stored in a RDB, while others in a filesystem) and there is no clear mapping.
I recommend you to approach this from the perspective of each domain entity individually; "persistability" is essentially just another property which might or might not apply in each case.
What we are talking about is a "transformation" or "mapper" layer isolating your domain entities from the persistence. If this is what we call "Repository" then yes, I absolutely agree with you -- this is the right approach to this problem. But if the "Repository pattern" means a complex structure of abstract and concrete classes and inheritance trees -- as I have usually seen it implemented -- then it is usually an overkill and rarely a good idea.
That being said, I have a number issues with other parts of it, and I have seen how dangerous it can be when inexperienced developers take it as a gospel and try to implement everything at once (which is a common problem with any collection of design patterns like this.
For example, repository is a helpful pattern in general; but in many cases, including the examples in the book itself, it is a huge overkill that adds complexity with very little benefit. Even more so as they're using SQLAlchemy, which is a "repository" in its own right (or, more precisely, a relational database abstraction layer with an ORM added on top).
Similarly, service layers and unit of work are useful when you have complex applications that cover multiple complex use cases; but in a system consisting of small services with narrow responsibilities they quickly become overly bloated using this pattern. And don't even get me started with dependency injection in Python.
The essential thing about design patterns is that they're tools like any other, and the developers should understand when to use them, and even more importantly when not to use them. This book has some advice in that direction, but in my opinion it should be more prominent and placed upfront rather at the end of each chapter.
You might like this: https://martinfowler.com/bliki/TestDouble.html
I would go even further:
All programming essentially consists of two things only:
1. data structures (often, but not necessarily, formalised as "types")
2. mechanisms to transform that data (functions, methods, algorithms, tasks, whatever)
Programming paradigms essentially describe different ways to organise these two: functional programming, for example, keeps the two strictly separate; in OOP the mechanisms are "attached" to the data they operate on. Of course, in practice there are many combinations and variations, with more and less flexibility (from strictly closed objects to mixins and similar), but this is the foundation.Most design patterns were invented as workarounds to specifics and limitations of certain languages/paradigms, and work great in that case -- but are much more limited, or even downright dangerous, when used in other contexts. As a clear example, the GoF patterns focus on strongly typed OOP languages like Java or C++, and will result in difficult to maintain bloatware if copied directly to dynamic languages like Python, Javascript or PHP (source: been there, done that, got the t-shirt).
We build all kinds of frameworks with routing and request/response validation, and then extract that into OpenAPI format, ofteng having to jump through hoops to adapt our internal data types and structures into those supported by JSON Schema. Instead, we could be doing the opposite: writing the OpenAPI spec first, and use tooling to make routing and validation based on it in an automated way. That has been done before [0] [1], but we're still just scratching the surface of what is possible.
Yes, I am aware that it's not easy to manually write the specs using JSON or even YAML, but we need a better focus on tooling around it; currently only Stoplight [2] gives a solid level of support in that area.
[0] https://connexion.readthedocs.io