Dan Abramov The wet codebase

Поділитися
Вставка
  • Опубліковано 11 жов 2024

КОМЕНТАРІ • 16

  • @jalvrus
    @jalvrus Рік тому +31

    The guiding principle I try to use when deciding whether to create an abstraction from similar code is to determine whether the code is *intrinsically* the same or *coincidentally* the same. If it is *intrinsically* the same, then it must always do the same thing in all places. If it is *coincidentally* the same, then it may do the same thing now, but could diverge in the future. Only code that is *intrinsically* the same should be combined. It's a similar thought process to what makes a good class, the "one reason to change" maxim.

  • @riolly
    @riolly Рік тому +1

    Code coverage is a curse! Feature coverage is a blessing!

  • @fabienbroquard7690
    @fabienbroquard7690 Рік тому +19

    Just sharing my thoughts: If an abstraction has to be modified (to solve a bug) and it affects negatively/breaks much of the code that depends on it, then the abstraction is not well made. Abstraction is not actually a good thing when badly done; however to be well done it often has to be refactored (very cleanly!) when new cases arise, (and as he said multiple times, no one has time to refactor..), that's one of the problems. Because if it's done well, then it's not and Abstraction anymore, it becomes an Abstract generalization, which makes a big difference, because it's a generalization, everything is a general case, there are no special cases in an abstract generalization.
    Usually the best way is not to try to change the abstraction directly, it's to copy paste, do the alternate code, make it work well and then refactor later when everythign works very well to merge the alternat cases as general cases; but it takes time.
    The problem is trying to abstract as soon as there are two 'more or less' identical codes. Just wait, if it's two times, it can stay like that, it's not much overhead, if it goes to 3, 4, 5, 6 ;) Then it's time to figrue out the common behvaiour between all those copies and generalize those away. As such the abstraction won't be started too early when other use cases are not well known (and might never exist!).
    He didn't say it, but abstracting too early (when only two use cases are known) is also a big culprit of bad abstractions, the general/commo behaviour is not fully known at such an early stage.
    In Dan Abramovs example, had they waited a bit more, they would have come to a point where, ok, we have three times the same code, sometimes it's async, sometimes not. That already changes how one will decide to start abstracting (they started too early, clearly, only with two use cases). Then also leave the rest that's not fully understood (how to become abstracted in a neat way) as inlined code, so that the specific cases would have remained specific cases until there were enough of them to see the common pattern and abstract it away correctly again (or not.. if the cases are too divergent).
    I personally usually wait to see at least 3-4 times the same repeated code, to tell myself, ok, something is clearly common here :) We shouldn't start too early, it's software, it can be modified later, unlike hardware where there's really a problem if it's not done right at the beginning ;)

  • @mwildam
    @mwildam Рік тому +2

    Although implicitely shown, it would be worth mentioning the dependency hell problem explicitely. It is one of the biggest problems I see in all recent projects, where I joined into.

  • @rumble1925
    @rumble1925 Рік тому +6

    It's impossible to get devs to stop doing this in my experience. However much I push back on useless abstractions, our code base gets littered with unreadable code that has a bunch of arguments and props that make no sense. But I work in frontend... clean code is non-existent most of the time.

  • @benbowers3613
    @benbowers3613 Рік тому +5

    Absolute gold

  • @igrb
    @igrb Рік тому +2

    Common dan W

  • @drxyd
    @drxyd Рік тому +6

    Good abstractions are well encapsulated, pure and couple loosely to the rest of the program, ergo they are easy to swap out. Data types/objects are the major bottleneck when it comes to changing the code I write because everything that consumes that data needs to be informed about those changes. Getting the data model right from the jump is hard AF and if you don't pay careful attention to it, the result is spaghettification and/or lasagna as additional features are added. In lining is just a band aid solution, the core problem is a fragile data model.

  • @DimaSirotnikov
    @DimaSirotnikov Рік тому +3

    I don't know if inlining all 3 uses of the original abstraction was deserved.
    I think that good abstractions should have a good fit to the problem space, so that you don't need effort to use them correctly.
    If adding functionality / API surface starts to make the abstraction hairy, it's a sign that the new use case should have a different abstraction *even if it's very similar*. I mean, hey, an array and a linked list are very similar except for this 1 small thing, that we could parametrize, right?

  • @0xpatrakar
    @0xpatrakar Рік тому +1

    Testing?

  • @adriankal
    @adriankal Рік тому +2

    I don't understand what kind of abstraction he it talking about. Real world example would be great.
    Im hard core dry practicioner and I've never had a problem with abstractions.
    The most powerful strategy in programming is to write functions, classes, modules etc that do one thing only. If you use ifs inside abstraction it becomes place to dump anything you couldn't find place anywhere else. Good abstraction doesn't have conditions or exceptions. They're specialized and serve as simple interface to complex things.

    • @JollyGiant19
      @JollyGiant19 Рік тому +3

      It’s pretty common, I’m surprised you haven’t run into it.
      I often see it with sending emails or slack messages from an application. There are two or more things that need to send messages but since they’re both using email to do it someone will DRY it to be one send email thing and eventually it’s littered with many switches or if/elses to support the various things it needs to do. All because having duplicate email code wouldn’t be DRY.

    • @ivanyonkov3164
      @ivanyonkov3164 5 місяців тому

      @@JollyGiant19 Never hit on it either. In my career I was having multiple projects having the exact same abstraction you are talking about - either by a library or a microservice. And never ever needed to add conditionals in the abstraction. It needs to send emails - simple as that. I can clearly remember the latest such abstraction. The class, let's name it, `MailSender` is configured with SMTP credentials. The function `send(...)` accepts recipient and message (or any abstraction over message like template or smth like that).
      The Library of course can be extended adding several adapters, like the default implementation could be SMTPMailSender, but you may have ExternalServiceMailSender which is let's say subclassed to SendGridMailSender, MailChimpMailSender and so on. But I don't see this subclassing as conditionals, even if it is introduced later in the library, when some consumer incepted the need. It just makes the library more feature-rich.