Live data from Hacker News

Hang your code out to DRY

johan.hal.se

41–50 of 82 posts

Re: Hang your code out to DRY

#41

Earlier quoted context omitted.

To me, inheritance and polymorphism are two different things. Polymorphism is about different units implementing an interface or equivalent protocol and that rocks. Inheritance is, essentially, dumping a bunch of code into your new class, and most of the time just imposes constraints and breaks API boundaries for no good reason. After studying and doing OOP for about 5 years, I don't see the advantages of inheritance…

Yeah; "favor composition over inheritance" remains good advice. "Classical" OO inheritance is brittle and often harmful.

Well, this is one of those "yes and no" situations.

The biggest argument that I hear against OO, is that "someone may misuse or misunderstand it."

I feel that this reflects the tech industry's obsession with hiring armies of relatively inexperienced developers, and then cycling through them, because we don't do what it takes to retain people.

I like composition. I use it often. It is not a "one size fits all" solution to anything; just like OO isn't.

"Reduce state" is another big rallying cry. Good advice, for algorithms, multithreaded service providers, and engines. Not so good, for UI, and, in many cases, device control.

I have spent the last couple of days, working on the login screen for the app I'm developing. It's loaded with state. That can't be avoided, and negotiating the several different states that this -seemingly- innocuous screen can have, is not for the faint of heart, but it needs to be done right, because it's the first screen our users see. It also optionally implements Sign In With Apple, which brings its own baggage. The users' experience must be absolutely frictionless, while also being very secure. The work has involved the server (PHP), the SDK (Swift), and the app, itself (also Swift). I'm not done. I keep uncovering corner cases.

I'm just not a fan of "Don't use X, because X is bad, and you're a bad programmer, if you use X." The tech industry has been dealing with this, since the GOTO wars.

Most of my projects are a hideous chimera of decades-old techniques, mixed with cutting edge stuff.

If someone wants to work on it, then they need to have their stuff together. I'm not going to "dumb it down," but I need to do a lot of documentation (I write about how I document, here: https://littlegreenviper.com/miscellany/leaving-a-legacy/).

Here's an interesting thing that happened to me, some time ago, and I decided to write about it: https://littlegreenviper.com/miscellany/swiftwater/the-curio...

Re: Hang your code out to DRY

#42

> On re-reading Sandi’s original article it says kind of what I remember it saying, but it also… kinda doesn’t? There’s a lot more talk about programmers honoring the abstractions of elders who came before them That's because the original article is so clearly about tearing down bad abstractions, but a large majority of programmers - based upon discussion about the article - seem to never get past the first part of i…

> Given a long enough time horizon, all abstractions turn bad. The solution isn't to not abstract. The solution is to tear them down when they go bad.

I disagree with this analysis. Abstractions certainly go bad, but I don't think it's correct to say all abstractions go bad.

The solution I took from Sandi's post was two-fold.

* Don't prematurely abstract, it's better to live with a little duplication vs aggressively eliminating it.

* Don't hold abstractions sacred, when you start seeing an abstraction with too many conditionals, consider breaking apart the use-cases to see if there are actually 2 distinct abstractions happening.

Re: Hang your code out to DRY

#43

> On re-reading Sandi’s original article it says kind of what I remember it saying, but it also… kinda doesn’t? There’s a lot more talk about programmers honoring the abstractions of elders who came before them That's because the original article is so clearly about tearing down bad abstractions, but a large majority of programmers - based upon discussion about the article - seem to never get past the first part of i…

That may be projection on my part, but I feel like lots of programmers (me included, of course) have a hard time accepting code as a living thing, and would rather build something that "lasts forever". I feel like this is the kind of thinking that pushes us to try to make abstractions that cover all of the cases, spend lots of time on things with little value (in a business context) to "make it right", flaws like that.

Reading the "original SOLID paper" [1] was enlightning to me. The initial assumption is that software rots, or gets less flexible with time. The best way to prevent that is to identify the part that is the least flexible/most rotten and replace it. But for that you need two things: being able to clearly identify parts of the software, and being able to replace them. This is where modularity and abstractions comes in. But this is also where the good old delete key comes in. This is where modularity and abstractions comes in.

Building software from parts, expecting to replace them does leads to abstractions, but different ones from building software expecting it to never be replaced. And, in my opinion, the first kind is easier to deal with.

[1]: https://web.archive.org/web/20150906155800/http://www.object...

Re: Hang your code out to DRY

#44

Earlier quoted context omitted.

Exactly. I find it helps to also state that it doesn't mean "Don't Repeat Characters"

I've pointed out in the past that if the characters you're deduplicating don't actually have the same meaning, you're just compressing your code; I've been trying to popularize labelling that kind of aggressive misapplication of DRY "Huffman coding".

It's because you are using the wrong term that it's not caught on. Obviously this is run length coding or maybe LZ coding ;).

Re: Hang your code out to DRY

#45
post #6

My first heuristic is: If I change the code in block A, is it assured that I will need to change the code in block B? My second heuristic is: Can I name the method I wish to de-duplicate in a way that is honest for all cases I wish to cover, yet explains its business purpose? The more it deviates from these heuristics, the more likely I am to duplicate the code in object oriented programming.

My slightly different heuristic:

If fact X changes, how many places in the code do we have to change it?

If the number is > 1, relying on humans to realize that will, on average, always fail. I know of two ways to fix that.

[1]: DRY it up.

[2]: Write a test asserting that all the places use the same value.

Sadly, most people rely on this:

[3]: We "just have to remember" to do these changes in all places, despite the fact that human memory is unreliable, and the future person working on this code isn't even in the room when we decided this.

Any time I hear a "we just have to remember" variation, either from coworkers or in my thoughts, an alarm goes off.

Re: Hang your code out to DRY

#46
I once read a comment I wish I'd saved.

It goes along the lines of: W beats X, X beats Y, Y beats Z; in terms of what principle you'd like to apply to your code. One of these letters was essentially representing DRY. I summed things up pretty nicely. Does someone happens to remember?

Re: Hang your code out to DRY

#47

Earlier quoted context omitted.

Yeah; "favor composition over inheritance" remains good advice. "Classical" OO inheritance is brittle and often harmful.

Well, this is one of those "yes and no" situations. The biggest argument that I hear against OO, is that "someone may misuse or misunderstand it." I feel that this reflects the tech industry's obsession with hiring armies of relatively inexperienced developers, and then cycling through them, because we don't do what it takes to retain people. I like composition. I use it often. It is not a "one size fits all" solutio…

While inheritance can certainly work, especially in terms of UI development, the issue is when you are talking more abstract concepts. At that point, it can become really hard to figure out the right lines for what should be inherited vs composed.

In my experience, poorly composed code is simply easier to understand than code which poorly applies inheritance.

For me, inheritance is best used lightly. The obvious smell is when you end up with methods that don't apply to all the base classes. Or, said another way, when a super class it has a superset of capabilities for a base class.

A good example of this is Java's collections, which, for the most part, are quite good with their inheritance. However, because the base classes have mutable methods, it makes it a pain to deal with unmodifiable collections. Java's mistake is they should have had the default collection be unmodifiable and had sub classes which added mutation capabilities. List and MutableList, for example.

Re: Hang your code out to DRY

#48
post #26

If there is one single article about programming that I positively hate it is 'duplication is better than the wrong abstraction'. As the Jason Swett article points out the article seems to install a sort of fear of refactoring. If there is a 'wrong abstraction' nobody will every change it and now we are doomed to live with this wrong abstraction for all of eternity. The wrong abstraction can be turned into the right…

Bad abstractions tie together components that shouldn't have been tied together. Too many bad abstractions are how you quickly end up with that "Bad code base" that you believe is difficult to change - Things are wrong because they're tied together in ways that don't actually make sense, and changing code to support refactoring one use-case creates a wave of cascading changes to other places those abstractions are to…

Agree completely.

I've dealt with too many code bases that didn't follow this advice. It's extremely expensive to cut down capabilities from code because they are overly coupled.

DRY tends to create things like utility classes and deep dependency trees. For example, I saw a non-ui code base that pulled in JavaFX to use their pair class.

Re: Hang your code out to DRY

#49
post #17

I find it fascinating that people are so against inheritance/polymorphism, these days. That's one of the absolute best ways to DRY. factoring out common base classes is a classic OO exercise. It's possible to drastically reduce the size of a codebase, and the potential error exposure, by doing some simple extractions.

I came to conclusion that very few people actually understand what a good OO design is and ever fewer have skills to implement it. All this talk about SOLID patterns and what is more likely to result in overengineered monstrosity than in something elegant and easy to maintain.

One way to understand OO, is to write OO code in a non-OO language (like C). When you need to basically write your own vtables, you really understand how things work.

I had to do that, in the early '90s, because I was writing an SDK that had to be implemented in C, but used object abstraction. It ended up being used for over 25 years.

Re: Hang your code out to DRY

#50

I really like WET (write everything twice). It also fits nicely with the rule of 3.

The problem I’ve seen with the “rule of 3” in real life is that by the time someone is writing a similar implementation by the third time, 5 years have passed and the entire team has rotated, so the programmer doesn’t have enough context to DRY anymore, and then the failed “big refactor that breaks corner cases” happens. I find a mentality of _striving_ for DRY by default — even if end up choosing to duplicate for pr…

That's not a problem with "rule of 3", it's a more general problem: Misunderstanding these "rules" and "principles". Specifically, trying to treat them as absolutes. "We must repeat ourselves three times to comply with 'rule of three'." Well, no, that's silly. It's a heuristic, a guideline, not a law that can never be broken. If you spot a clear case of real duplication even before creating the duplication (easier with experience, either total or with the system under development), then you can clean it up earlier. If you can't see the duplication or are uncertain about the duplication ("Is this real duplication, or just coincidence? Am I going to change 90% of the code after all the modifications are done or just one value which could become a parameter?"), then go ahead and repeat yourself.

The same issue arises with YAGNI. People often jump too quickly to shouting YAGNI when the reality may be, and again this comes from experience-enabled judgment, that you are going to need it. "Don't make it a parameter, we aren't using it yet and don't know that we will." "But we do know, it's in the customer requirements that we don't hardcode the database server name everywhere, also it's just sensible."

These rules, principles, guidelines, laws, or whatever term gets assigned to them are there to help. They are not there to be excuses to stop thinking, but to provide a structure around thinking and a way to discuss with other people. But that structure is not absolute, experience and judgement can lead to breaking any of these rules at any time based on the present situation. That present situation that only you (and your team) know, but not the people who discovered, created, or coined the rules. They can only offer advice and guidance and not absolute instruction.

Post reply on HN