5 ms·
Decoupled code is much harder to follow. I see people thinking decoupling is always good, but it's not. It can be good when things are actually de-coupled... bu
by brabel 3y ago
Decoupled code is much harder to follow. I see people thinking decoupling is always good, but it's not. It can be good when things are actually de-coupled... but I've seen coworkers decouple logic from HTTP handlers for example where that made no sense because the whole purpose of the logic was to do stuff for HTTP... so if you want to ensure that if certain conditions are met, a HTTP header has a certain value... well you can't anymore unless you abstract away even the concept of HTTP headers! The whole thing becomes a mess out of the good intentions of the developer. Do not ever decouple things that are intrinsically coupled.
- withinboredom 3y agoMost people decouple code for the sake of decoupling (cargo cult) vs. actually knowing when to do so. For example, I was reviewing a software project written by a bunch of junior/mid-level devs. They had decoupled the clock from the physical clock (good for unit testing time-based workflows), but when asked about why they did it, they didn't know or understand why it was done and there were no unit tests using it. When I asked the dev who implemented it, he explained that he decoupled it and so it was good. (to be clear, I was only seeking to understand, and not asking these questions in an accusatory way.) There also existed many interfaces with exactly one implementation, which just increases the cognitive load when writing code because you see an 'IDoX' interface only to discover it is ALWAYS an 'XAdapater' that if you had known, would have saved mountains of logic (ie, getting a new 'XAdapater' from the container while copying some stuff from the 'IDoX' interface). It was a mess. Are they going to be glad that all these abstractions exist at some point? Probably not. This is a pretty simple, but mature project. There's no real reason to refactor it at this point. The business owners just wanted to know what was going on and why simple changes took months to implement.
- MoreQARespect 3y agoFrankly I think even decoupling for the purposes of unit testing is another example of cargo culting. It emerged as a best practice when CPUs were much slower, containerization didn't exist and mock service tooling was far inferior - writing integration tests was an exercise in flaky futility in 2001. The technology has since moved on but the culture of best practices hasn't. It still can make sense if you've got a very complex bundle of isolated stateless business logic but in practice I find that most dependency inversion I see these days isn't for that. It increases the SLOC by 30% and reduces code coherence just so that a test can run in 20 milliseconds instead of 2.1 seconds. In many cases those unit tests check to see if you put a number in one end of a class that the same number comes out the other end. What bug is that going to catch? Meanwhile all of the actual bugs are probably hiding in the database queries or the interaction layers created as a sacrifice to bob the bearded god of unit testing. The most fascinating instantiation of this idea is, I think, the notion that because unit tests are horrible to work with that unit tests can therefore "drive" design because it'll make you fight to make the unit test less horrible. It's like advocating an abusive relationship to help fix your life because the abuser won't be afraid to point out all of your flaws which you can then fix. The two corollaries that never seems to permeate are A) maybe when unit tests become horrible to work it's means they were also the bad code that coupled too tightly? and B) maybe it's cheaper to spot bad design by learning what to look for rather than building a unit test that will punch you in the face for it?
- speed_spread 3y agoClock decoupling is one of the few patterns that's actually required for reproducible tests. Using the real clock makes test run in realtime (slow) and puts them at the mercy of the OS timing and other exterior factors.
- MoreQARespect 3y agoNot necessarily. This is exactly the kind of thing I mean, in fact. I once had a bug scenario I wanted to reproduce with a test where the time was grabbed from datetime.now() in the first half of the scenario and indirectly via a postgres query in the second half (with a time delimited query). With libfaketime I injected a new running service time and postgres service via the test runner. It let me do TDD to create a reproducible test - what you thought was impossible. I could have jumped straight to dependency injection on that mess of a code base but that would have meant a risky architectural change that I would have to have done without tests. That is bad practice. This sort of thing was not really possible in 2001 but it's possible now.
- norir 3y ago> It increases the SLOC by 30% and reduces code coherence just so that a test can run in 20 milliseconds instead of 2.1 seconds. There are people who cargo cult and people who do things for a reason. It may not always be obvious which category a developer was in just by talking to them or looking at their work. Imagine the following scenario: you have two projects each having the same functionality and the same level of test coverage. Project A is 30% longer than project B but project A's test suite runs in 1 second while project B's runs in 2 minutes. Personally, I am taking project A every time (but I'm also probably trying to figure out how to get that 30% down to 0.1-2%). The path to project B is paved with 50 decisions to do the thing that took 2.1 seconds rather than 20ms.
- MoreQARespect 3y ago>Imagine the following scenario: you have two projects each having the same functionality and the same level of test coverage. Project A is 30% longer than project B but project A's test suite runs in 1 second while project B's runs in 2 minutes. Personally, I am taking project A every time. Project A's tests will usually be sacrificing realism in favor of speed. The practical upshot of that is entire classes of bug won't get caught. To take some recent practical examples off the top of my head: I have some tests that do 404 checks on all web pages. I have another that checks if sent emails are outlook compliant. These checks necessitate that the tests be slower but somebody still needs to do this. I know there are plenty of people out there who think like you do. That was kind of my point. Realism in testing is an underappreciated quality.
- sleiben 3y agoEncountered this too often in my career and had a lot of wtf moments debugging that «de-coupled» stuff others (and sometimes me) have left. I decided to follow the «Wrong abstraction is worse than duplication» approach. Doing this for 5+ years now and did never regret it. Sure, copy-pasta sucks but in comparison to over engineering it’s an acceptable price to pay.