3 ms·
I think it's fair to say that abstractions should have to prove themselves as a necessity and that we make things abstract way too early. Most really good abstr
by foobiekr 6y ago
I think it's fair to say that abstractions should have to prove themselves as a necessity and that we make things abstract way too early. Most really good abstractions in an app fall out of well-written code to solve a specific problem.
In day to day life as an engineer, I find that we have very few _enduring_ abstractions - there are very deep ones, like the concept of streams, things like filesystems and related ideas, the concept of a virtual machine in the process sense, and so on - and a lot of faddish abstractions that have a pretty wide blast radius when they start to go wrong. A lot of the good ones (networking has a _lot_ of these, such as the abstractions above and below the model of an interface in professionally-written network device code) are focused on layering.
- Tainnor 6y agoI disagree, and this is one of the things where it's really hard to get to a shared understanding because I don't know what kind of problems you've worked on and what kind of code you've seen and vice versa. But in my daily work, I routinely see abstractions just come up very naturally all the time. Sometimes they turn out to be slightly wrong, but often also not. I need to perform some calculation (e.g. for billing)? That can be abstracted away. I need to parse some unstructured user request into something structured? That's an abstraction. And so on. A lot of these things are clear to me even before I start writing code. I also tend to use (at least some amount of) DDD, to write small, composable functions with few side effects and to be as declarative as possible. All of this might help with coming up with lasting abstractions. But I'm not denying that I'm running into lots of situations in my daily work where it turns out some abstraction was wrong. Just that I find that many more of them actually turn out to be correct or at least correct for the most part (it might be that something needs to receive an additional parameter or to returns some slightly different structure to account for error conditions or so, but it's still basically the same abstraction).
- barrkel 6y agoI sometimes review PRs where people are encouraged (by other reviewers) to create new methods because there's a single line of code duplicated between two other methods. I don't think that rate of abstraction construction - and every method is another abstraction - is helpful for the health of the code, or its readability.
- Tainnor 6y agoI can't judge that without more context. If this is just accidental duplication, it's pointless to abstract it away. But if it's a line of code that is necessary to deal with some gotcha of a particular library etc., it's probably good to extract and add an explanatory comment.
- dave_sid 6y ago“Accidental duplication” well said. Not enough people even consider this before deciding that they must remove the duplicate code. Will each duplicate section change for the same reason? If not then it’s not really duplicate code, it just looks the same.
- jiofih 6y agoIf that line of code deals with a particular piece of business logic, that should be consistent within the application, it’s a good thing.
- betenoire 6y agoWhy are your two examples in the second paragraph necessarily "abstractions"?
- Tainnor 6y agoBecause "calculate_vat" is more abstract than the exact sequence of calculations performed?
- waheoo 6y agoAre we talking about that kind of general function labelling abstraction? I was under the impression this was about generalizing the abstraction to something reusable. I.e. calculate_vat will always be used by the same thing and there will only ever be one of them. The generalization would be: interface SalesTaxCalculator { func calculate_sales_tax } This kind of abstraction is more uncommon. What im guessing the article is struggling with is that making abstractions like salestax calculation os usually kind of useless, there is only 1-3 types of sales tax calculation and its best defined inline next to the proce calculation or put in a function like calculate_vat. A lot of developers use abstractions to remove code duplication. Its more fun using this kind of code than code where devs dont try to remove duplicstion but i just wish instead of seeing duplication as evil, they instead saw it a sign that their design is wrong. If youre seeing duplication, there is an abstraction there, whether it is worth it to implement is usually more to do with if its just hiding code duplication or if it is creating a new concept that hides implementation details.
- Tainnor 6y agoYes, if you restrict your definition of abstraction to "polymorphism", then it becomes a different discussion (Go developers would like to have a word). But I think there are lots of abstractions often missing from code that I have seen that don't need any sort of polymorphism. A common example is performing input validation all over the place instead of at the boundary with some sort of form object that only accepts valid params.
- Chris_Newton 6y agoDoes it make sense to characterise abstractions as “right” and “wrong” in the first place? This feels too absolute to me. Abstraction is just hiding some complexity in implementation details behind a simpler interface. It offers benefits from reducing the need to deal with the full complexity everywhere else. It also has costs. The interface establishes a new concept, albeit a simpler one, that must also be understood and maintained wherever client code uses the abstraction. Moreover, if you need to understand or modify the detailed implementation later, there is now a barrier to doing so. When we define an abstraction, hopefully we do so because the benefits outweigh the costs at that time. The simpler the interface relative to the complexity of the implementation it hides, the more likely this is to be true. However, that balance is inevitably subject to change as a program evolves and the relevance of the hidden details to different parts of the system changes. So it feels like abstractions might be better characterised by whether they represent good value under the current circumstances. It is perfectly reasonable for an abstraction to be cost-effective at the time it is added, but to become more or less so as the context evolves. If it reaches a point where it is no longer cost-effective, it should be removed. Either the relevant parts of its implementation can then be inlined at each place that previously used it, or some new abstraction(s) can be defined that better reflect the relevance of different implementation details at that time.