Can you elaborate?
@attr.s
class C:
x = attr.ib()
as its main api (with `attr.attrs` and `attr.attrib` as serious business aliases so you didn't have to use it).That API was always polarizing, some loved it, some hated it.
I will point out though, that it predates type hints and it was an effective way to declare classes with little "syntax noise" which made it easy to write but also easy to read, because you used the import name as part of the APIs.
Here is more context: https://www.attrs.org/en/stable/names.html
I REGRET NOTHING
i believe that design pressure sense is a form of taste, and like taste it needs to be cultivated, and that is can't be easily verbalized or measured. you just know that your architecture is going to have advantageous properties, but to sit down and explain why will take inordinate amount of effort. the goal is to be able to look at the architecture and be able to see its failure states as it evolves through other people working with it, external pressures, requirement changes, etc. over the course of 2, 3, ... 10, etc. years into the future. i stay in touch with former colleagues from projects where i was architect, just so that i can learn how the architecture evolved, what were the pain points, etc.
i've met other architects who have that sense, and it's a joy to work with them, because it is vibing. conversly "best practices or bust" sticklers are insufferable. i make sure that i don't have to contend with such people.
[0] https://www.cs.unc.edu/~stotts/COMP723-s13/patterns/forces.h...
[1] https://www.pmi.org/disciplined-agile/structure-of-pattern-p...
[2] Chapter 19 in “Pattern languages of program design 2”, ISBN 0201895277
Which is what the person I was replying to said with "Code is for communicating with humans primarily, even though it needs to be run on a machine.". If the primary purpose is communication with other humans we wouldn't choose such awkward languages. The primary purpose of code is to run and provide some kind of features supporting use cases. It's really nice however if humans can understand it well.
The code does also need to be understandable by other humans, but that is not its primary purpose.
The only thing that matter to the machine is opcodes and bits, But that's alien to human, so we map it to assembly. Any abstractions higher than that is mostly for reasoning about the code and share that with other people. And in the process we find some very good abstractions which we then embed into programming languages like procedure, namespacing, OOP, patterns matching, structs, traits/protocols,...
All these abstractions are good because they are useful when modeling a problem. The some are so good then it's worth writing a whole VM to get them (lisp homoiconicity, smalltalk's consistent world representation,...)
Also, it is good to remember what game is actually being played. When someone comes up with a popularizes a given "best practice", why are they doing so? In many cases, Uncle Bob types are doing this just as a form of self promotion. Most best practices are fundamentally indefensible with proponents resorting to ad-hominem attacks if their little church is threatened.
I find this topic difficult to navigate because of the many trade-offs. One aspect that wasn't mentioned is temporal. A lot of the time, it makes sense to start with a "database-oriented design" (in the pejorative sense), where your types are just whatever shape your data has in Postgres.
However, as time goes on and your understanding of the domain grows, you start to realize the limitations of that approach. At that point, it probably makes sense to introduce a separate domain model and use explicit mapping. But finding that point in time where you want to switch is not trivial.
Should you start with a domain model from the get-go? Maybe, but it's risky because you may end up with domain objects that don't actually do a better job of representing the domain than whatever you have in your SQL tables. It also feels awkward (and is hard to justify in a team) to map back and forth between domain model, sql SELECT row and JSON response body if they're pretty much the same, at least initially.
So it might very well be that, rather than starting with a domain model, the best approach is to refactor your way into it once you have a better feel for the domain. Err on the side of little or no abstraction, but don't hesitate to introduce abstraction when you feel the pain from too much "concretion". Again, it takes judgment so it's hard to teach (which the talk does an admirable job in pointing out).
By domain model do you mean something like what a scientist would call a theory? A description of your domain in terms of some fundamental concepts, how they relate to each other, their behaviour, etc? Something like a specification?
Which could of course have many possible concrete implementations (and many possible ways to represent it with data). Where I get confused with this is I'm not sure what it means to map data to and from your domain model (it's an actual code entity?), so I'm probably thinking about this wrong.
For context: https://fsharpforfunandprofit.com/posts/designing-with-types...
So both the storage and presentation layer are strings, but they differs. So to reconcile both, you need an intermediate layer, which will contains structures that are the domain models, and logic that manipulate them. To jump from one layer to another you map the data, in this example, string to structs then to string.
With MVC and CRUD apps, the layers often have similar models (or the same, especially with dynamic languages) so you don't bother with mapping. But when the use cases becomes more complex, they alter the domain layer and the models within. So then you need to add mapping code. Your storage layers may have many tables (if using sql), but then it's a single struct at the domain layer, which then becomes many models at the presentation layer with duplicate information.
NOTE
That's why a lot of people don't like most ORM libraries. They're great when the models are similar, but when they start to diverge, you always need to resort to raw SQL query, then it becomes a pain to refactor. The good ORM libraries relies on metaprogramming, then they're just weird SQL.
No wonder there are so many single-monitor, no-LSP savants out there.
1317•5h ago