Stop Recommending Clean Code

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

КОМЕНТАРІ • 1,3 тис.

  • @sealsharp
    @sealsharp Рік тому +365

    The biggest improvement to the code i write was starting to do unit tests. Because when the tests are annoying to write, it is a sign that there are structural issues.

    • @FlaggedStar
      @FlaggedStar Рік тому +53

      Unfortunately, this falls in to the trap of over-engineering your code. Making code testable forces practices like dependency injection and keeping classes/functions small on you. Those aren't necessarily bad things, but it radically changes the structure of your code.

    • @ivanjermakov
      @ivanjermakov Рік тому +40

      Also, tests are useful for those who want to know how the code should be used. If the unit test was difficult to write -- the unit will be difficult to use.

    • @recarsion
      @recarsion Рік тому +16

      I must have never written good code then because I've never found writing unit tests not annoying af lol

    • @aoeu256
      @aoeu256 Рік тому +7

      @@FlaggedStar you can have dependency injection with methods rather than needing full blown classes which is much shorter imo.

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

      @@aoeu256 That's not considered good practice unless you have a damn good reason to do it. Read some Mark Seesman.

  • @CamembertDave
    @CamembertDave Рік тому +974

    I feel like the point where clean code goes from being a positive to a negative is the point at which you start thinking of it as a set of rules which must be adhered to instead of just a sniff-test. If it looks messy, it needs cleaning; if it looks clean, it is clean.

    • @monkev1199
      @monkev1199 Рік тому +91

      Yeah fundamentally "is this code clean" is always going to be answered with "I'll know it when I see it"

    • @ivanjermakov
      @ivanjermakov Рік тому +33

      Love that analogy. After thousands of hours of looking through the code you can almost always immediately tell what smells and what not.

    • @AScribblingTurtle
      @AScribblingTurtle Рік тому +33

      "Clean Code" as a concept has the flaw that it tries to encapsulate understandability, readability, and easy maintainability, which are all subjective traits, that not only influence each other but also highly depend on the programmer's coding style. So what is positive and negative depens on who looks at it.
      In the Video, the only thing, that `private void includeSuiteSetupPage()` adds is the information of "Page", to make clear, that the `include` in the function is including a "Page"
      You could have easily done that with a comment or by properly naming the freaking module/file that is included.
      The function makes the line more readable, yes, but harder to understand and maintain because there is now an extra function, that could possibly be used somewhere else, that could have optional parameters, that could change the instance in different ways.

    • @jordixboy
      @jordixboy Рік тому +13

      Doesn't work. Everyone has a different understanding of what is clean.

    • @zeezor
      @zeezor Рік тому +4

      I totally agree, the moment you sanctify clean code is when you start veering off from the positive it's meant to bring to your code.

  • @steveg1961
    @steveg1961 Рік тому +389

    I write functions of two basic types. Most of them (the great majority) are relatively small and perform only a few (or one) specific operations. But I also write what I think of as "master" functions that can be quite lengthy, and which perform a series of oprations, which are using the smaller functions. I've done it this way for 40 years and it has served me well.

    • @Slashx92
      @Slashx92 Рік тому +22

      I write automations and that's how I make my functions too. If there is a important step in the automation that needs emphasis, or is the representation of a defined business logic (and not just moving data around) that's a separated function, so it can have a name, and be reviewed and maintained by itself. But it will be only called by the main function
      Once a function called inside the main function calls more functions that are not utilities, it starts to get messy and hard to follow

    • @MoguMasso
      @MoguMasso Рік тому +16

      I agree. Whether it's OOP or not, code written this way, in most of my cases, lead to clearly written routines which didn't need too much documentations to understand.

    • @dupersuper1000
      @dupersuper1000 Рік тому +12

      I tend to agree with this process. As a FP guy, I prefer to think of it as “data queries” -> “data transformations/aggregations” -> “command executions”.
      Most systems have that basic structure. You have some data, you need to transform that data into something more immediately useful, and then once you have the data you need in the format that you need, you use that data to execute some process that has some effect on the broader system (e.g. writing to the database or displaying a UI component). It’s all effectively a data pipeline where the end of the pipeline is where you “do the thing,” so to speak.

    • @explosiver
      @explosiver Рік тому +10

      That's basically how programs works as a whole. They have a main function that loops and runs everything else.

    • @steveg1961
      @steveg1961 Рік тому +7

      @@explosiver I often don't do much in main except use it to call into other functions.

  • @klaudyw3
    @klaudyw3 Рік тому +741

    +1 for the procedural code thing. To an extent it's the embodiment of "The code should read like a narrative".

    • @jespergustafsson7664
      @jespergustafsson7664 Рік тому +10

      True!

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

      sometimes you just want to read the synopsis

    • @publicalias8172
      @publicalias8172 Рік тому

      @@dickheadrecs ... so look at the summary

    • @GeneraluStelaru
      @GeneraluStelaru Рік тому +12

      @@dickheadrecs True but not on a paragraph level.

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

      @@GeneraluStelaru yeah good point.
      i’m going to make my code editor make the first letter of each paragraph 36pt

  • @vhaangol4785
    @vhaangol4785 Рік тому +939

    Based on experience, clean code oftentimes leads to unnecessary abstraction and indirection. There are times when it makes sense to apply the techniques for writing "clean code", but applying it to almost every code is insane. It makes me think, "Are we really trying to solve a problem here or are we simply abiding by these rules because we think this is the only right way to write code?"

    • @airman122469
      @airman122469 Рік тому +62

      I like clean code in the abstract sense. But yes, it almost always, in practice, leads to a bunch of abstractions that ultimately do not need to exist.
      But I can see starting with clean code, then reducing the abstractions to slim it down.

    • @khatdubell
      @khatdubell Рік тому +36

      Neither, its called catering to the lowest common denominator.
      When you let people use their "best judgement", you will frequently be disappointed.

    • @Flackon
      @Flackon Рік тому +14

      Sorry, too milquetoast. just STOP writing clean code

    • @orbatos
      @orbatos Рік тому +40

      Like many similar ideas, treating it as some kind of hard rule is just ridiculous.

    • @NoX-512
      @NoX-512 Рік тому +12

      ​@@orbatosNot at all. Clean Code is a horror show.

  • @jacobleslie8056
    @jacobleslie8056 Рік тому +108

    Function length is easy. Your function should be the correct length. Done.

    • @ThePrimeTimeagen
      @ThePrimeTimeagen  Рік тому +28

      Love it

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

      I do try to keep my functions to the "one screen" size but I don't treat it as an absolute or anything. If it can't fit on one screen, I look for ways to make it more more succinct. If I can find some, great. If not, no harm done.

    • @voskresenie-
      @voskresenie- 2 місяці тому +7

      ​@@chriswolf4715 no you buy a larger screen. it's a business expense. necessary and reasonable. tax deductible. I am not a lawyer and I don't pay taxes.

  • @reinoob
    @reinoob Рік тому +912

    "Right click -> format code" is clean enough

  • @wdavid3116
    @wdavid3116 Рік тому +270

    I was hugely surprised when I saw that clean code was published in 2008. I thought we knew better by then. A Philosophy of Software Design is a much much better book. My main concern with clean code is what that book terms shallow abstractions. You break down your problem to such a tiny tiny level that the code in each element (whether that's a function or procedure or method or whatever the language you're using calls it,) becomes super trivial but the sheer number of tiny basically worthless abstractions makes your code insanely complicated and hard to read or change. I remember the first time I heard someone say that a function should be no more than 4 lines of code and I couldn't understand how anyone could possibly think that was a good idea.

    • @theodorealenas3171
      @theodorealenas3171 Рік тому +17

      It is pretty crazy, but so are techniques of high level artists and people don't question that as much.
      I'm trying to learn to write tiny functions, like Martin, and it seems to be a separate skill set to both read and write these. The benefits are other things, like how you can more easily avoid reading code you're not interested in.

    • @wdavid3116
      @wdavid3116 Рік тому +47

      @@theodorealenas3171 I just straight up disagree with that. I think it's an anti-skill and if your code is well organized in properly sized functions (whatever size that ends up being,) that make sense you can more easily find the code you want because there will be a sensible number of abstractions to sort through when you're looking for it.

    • @madjesta
      @madjesta Рік тому +16

      I've seen code that is abstracted to methods of at most 4 lines. I felt it was utter and total baren trash code that would never make sense since it would take too long to read.

    • @jimmyjam-vc6rf
      @jimmyjam-vc6rf Рік тому +15

      Yeah some software devs try to be some purist holy man that walks in the light of the divine code quality and standards. These people usually have the worst turn around time for actual features and finished products. Most of their focus is delicately building a house of cards and obstracizing anyone they share a code base with that they must repent for their sins are many.

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

      I have never had a problem with changing sth that was tiny. Of course, reading it and wrapping your head around it is stupidly hard. For me, it is not about lines but about how many things that function (or whatever) does. If it is trivial, do not break it down. If even trivial things are useful because you use it many times, then make that small function. But breaking down code because it is too long is useless.

  • @dorinsuletea1928
    @dorinsuletea1928 Рік тому +169

    In Clean Architecture Uncle Bob had IMO a very insightful take on DRY :
    “But there are different kinds of duplication. There is true duplication, in which every change to one instance necessitates the same change to every duplicate of that instance. Then there is false or accidental duplication. If two apparently duplicated sections of code evolve along different paths-if they change at different rates, and for different reasons-then they are not true duplicates. Return to them in a few years, and you’ll find that they are very different from each other.”

    • @stunningride6073
      @stunningride6073 Рік тому +18

      Oh DRY is one of the most misunderstood principles in IT industry....

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

      It is safer to err on the side of DRY than on the side of duplication.
      If you have this common piece of code that you factor out and now you have to introduce a parameter to introduce a slight change for one invocation vs the other you can easily duplicate the function later and remove all the conditions. Many refactoring tools even automate that.
      The other way around you will see two similar functions that grow further apart while trying to do the exact same thing. You recognize it by always having to modify both pieces of code, often in separate commits because it is always forgotten. It is going to be very hard to unify them later on.

    • @Jabberwockybird
      @Jabberwockybird 10 місяців тому +2

      WET is better than DRY.

  • @TheChillBison
    @TheChillBison Рік тому +60

    I still say I found Clean Code to be incredibly helpful, as I think a lot of those "basics" (or even having a discussion about them) aren't taught in school or in online courses. They either focus on the syntax of the language, or on what you're trying to get done, but not on how to code well so that other humans don't want to beat you with their keyboards. Having seen plenty of examples where code was confusing as all get out due to violating these principles, I think the important thing is for teams to have the discussions, review the code, refactor as needed, and just have something to follow rather than everyone code according to their own opinions.

    • @heh_boaner
      @heh_boaner Місяць тому

      There are three types of programmers. Those who think everyone should read clean code, those who think no one should, and those who could end up contributing more than the equivalent of AI training data.
      Being unable to think critically about something as trivial as a book of rules makes you no better than the sum of all rules you were told to follow.

  • @froggy3496
    @froggy3496 Рік тому +20

    Wait this guy streams during working hours?? What a mad lad

  • @Kavukamari
    @Kavukamari Рік тому +23

    I'm going to start programming WET and DIRTY code and you can't stop me, in fact everyone is required to watch

  • @andrewallbright
    @andrewallbright Рік тому +328

    “Clean code” soon rebrands to “perfect code by perfect coders; you’re an awful programmer if you don’t do all of this and buy all the books.” Lol

    • @replikvltyoutube3727
      @replikvltyoutube3727 Рік тому +14

      Article author: Do this, buy this book
      Also book authors: article author

    • @paulojose7568
      @paulojose7568 Рік тому +13

      You guys can't even write a book and you're here hating the author who probably just wanted to help the industry in 2008 lol

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

      But it's not even perfect code. It's just perfect code from Martin's perspective

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

      @@crides0 Its not even that.
      Its imperfect code form Martin's perspective that he is refactoring.
      The original code seems to come from Ward Cunningham and Rick Mugridge.

    • @NoX-512
      @NoX-512 Рік тому

      ​@@paulojose7568No, he just wanted to line his pockets. Clean Code is a shit show.

  • @Tony-dp1rl
    @Tony-dp1rl Рік тому +8

    In some parallel universe somewhere , there is a reality where OOP never happened ... it rains donuts there.

  • @marcusaureliusfanboy
    @marcusaureliusfanboy Рік тому +17

    25:32 I feel this comes from the expectation that unit tests will target the public interfaces.
    Refactoring majorly would involve cleaning up the private methods used in these public-interfacing methods and thus strong unit tests can verify the correctness of the public interface after its internals are refactored.

  • @drno87
    @drno87 Рік тому +85

    George Orwell wrote an essay where he gave rules for clean English. The first five were simple guidelines. The sixth was "Break any of these rules sooner than say anything outright barbarous." That last one is missing from Clean Code.

    • @vasiliigulevich9202
      @vasiliigulevich9202 5 місяців тому +3

      It is not missing, Uncle Bob has introduced so many caveats over years, that no concrete thoughts from the book left.

    • @DoubleJumpPunch
      @DoubleJumpPunch 5 місяців тому +8

      ​@@vasiliigulevich9202Oh, so the book is"perfectly" abstracted now 😂

  • @leakyabstraction
    @leakyabstraction Рік тому +11

    7:20 Careful ordering inside source files is still a great advice. The concept is simply to have the actual public interface of your component at the top, and the implementation details below it. Or, generally, ordering it from large concepts to small concepts. It's easy to see how it is totally confusing when you open a file, which has some name that represents a concept, and what you see there first are some crazy abstract stuff which is hard to connect mentally to the function of the file/component... It's just a general sane advice for decreasing the friction of work.

  • @NotherPleb
    @NotherPleb Рік тому +15

    I think unit tests are helpful in refactoring for one reason: I want them to break so it reminds me of what use cases and code behaviour I need to take into consideration when refactoring.

  • @jgndev
    @jgndev Рік тому +22

    I worked in a “clean code” shop. The end result was you are writing very specific code that would only work in that code base.

    • @davethorn9423
      @davethorn9423 Місяць тому +1

      As long as it works what's the problem

    • @wesselbindt
      @wesselbindt Місяць тому

      I mean, that's what you're paid to do

  • @mfpears
    @mfpears Рік тому +52

    14:40 A better rule is to create an abstraction exactly when you have a clear name for it. Removing the implementation details and replacing it with a simple description actually _improves_ your ability to understand what's going on.

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

      When I don't have an otherwise strong opinion the rule of thumb I use is "does this make code shorter". If adding a function declaration ends up adding lines having the implementation copied verbatim is probably simpler.

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

      Yes. I worked with some developers that had said that they usually create a function when they see a repetition. I've never understood this. No, it's not the only purpose for creating a functions. If avoiding repetitions was the only reason for creating a function/method, they would have no name, just an id.

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

      @@Turalcar it shouldn't be, "does this make code shorter?" instead it should be, "does this make the code easier to understand?" Shorter is not always better with code (a common misunderstanding within the FP crowd).

    • @Turalcar
      @Turalcar Рік тому

      @@evancombs5159 Hence "when I don't have an otherwise strong opinion". Out of 2 similarly legible sources I'll pick a shorter one.

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

      One code smell I encounter is when a function is written that says "DoThingAAndAlsoThingB()"
      Generally that's a code smell and means your function is doing too much. That could certainly be broken down to smaller functions

  • @pilotashish
    @pilotashish Рік тому +63

    flip's doing a fantastic job

  • @datguy4104
    @datguy4104 Рік тому +77

    When I began learning to code DRY was by far the most annoying thing that held me back. Tutorials/courses ALWAYS apply DRY in the middle of explaining something which leads to piles of abstraction and refactoring right in the middle of explaining a concept, which makes learning the concept or seeing exactly what's going on very difficult when you barely understand anything as it is.

    • @CottidaeSEA
      @CottidaeSEA Рік тому +30

      Their lips become so DRY, they no longer KISS. They don't keep things simple and make things far too abstract, instead violating a different principle.

    • @Flackon
      @Flackon Рік тому +16

      Yeah it's especially egregious in the context of a tutorial because it muddles up the learning experience. Even when writing code yourself for some new problem, it helps immensely to just write it dirty and make it work first, and only when you understand what's involved, refactor it

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

      @@Flackon Not only that, but even when you refactor it, there are few reasons to split the code into so many parts. One of my primary reasons for splitting up code early is unit testing during development, but even that is kind of rare.

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

      It's dumb because Martin says you first write messy code and then clean it. So he disagrees with what the tutorials do there basically

    • @taragnor
      @taragnor Рік тому +7

      I think DRY is really important. I can't count the number of times I've got weird behavior because I have two different code blocks where I do the same thing and only changed one of them, while forgetting about the other one. More often than not, doing copy/pasta code instead of DRY ends up costing me time down the road, despite the former being considerably faster initially.

  • @andydavies6522
    @andydavies6522 Рік тому +204

    I had a developer on my team who used to follow clean code to the letter, and produced code that took an obscene amount of time to debug as it jumped around way too much and we couldn't keep the context in our heads. We dumped the entire codebase and re-wrote it from the ground up and was at least 10x more productive and produced fewer defects.

    • @blubblurb
      @blubblurb Рік тому +30

      Same experience. In my case, this programmer was in charge to set the coding rules, so we all had to refactor the code to smaller and smaller functions. Way more unreadable and also way harder to debug. Also with all those arbitrary rules we started to think more about how to structure the code then on how to solve the problem.

    • @nkazimulojudgement3583
      @nkazimulojudgement3583 Рік тому +4

      @@blubblurb damn

    • @kecher1
      @kecher1 Рік тому +22

      Obviously, that developer didn't follow it "to the letter", because if he had used TDD properly which is an integral part of Uncle Bob's method, there would be no need to "debug" that code.

    • @blubblurb
      @blubblurb Рік тому +29

      @@kecher1 TDD has nothing todo with no need to debug the code. If the code doesnt do what you think it should do your tests can't fix that.

    • @stunningride6073
      @stunningride6073 Рік тому

      @@blubblurb If you can't understand what the code is suppossed to be doing based on the tests then your tests are shitty.

  • @KarlOlofsson
    @KarlOlofsson Рік тому +28

    The golden rule is "Whatever you agree on in your team/project". If it works and everyone understands things it's good enough. Then you can discuss and improve from there. At least seniors and higher as junior devs can't really be expected to take responsibility for things like this, just be eager to learn.

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

      Queue never-ending discussions.

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

      There's a *lot* of companies that crashes doing this my friend...
      Agreeing on something doesn't mean it's true...

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

      @@RaMz00z you cant always save them

    • @KarlOlofsson
      @KarlOlofsson Рік тому

      @@etodemerzel2627 unless you work alone on a hobby project there will of course always be discussions about stuff and discontent people.

  • @sb_dunk
    @sb_dunk Рік тому +138

    The big problem is dogma and fundamentalism. Thinking that _this is the right way_ always ends badly.
    Coding principles are often good when they're treated as guidelines, and they don't always need to be adhered to.

    • @CaptainToadUK
      @CaptainToadUK Рік тому +8

      Worse is when the dogmatism insists it is the _only_ way or removes other ways to do things because of the path chosen. Because there's always more than way to skin a cat, except when you're forced into 'the one true path' and you find that your Cat object is incompatible with the IAnimalSkinner service and so you have to spend hours extending it for that one particular case because that is the _only_ way to skin a cat in that codebase...

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

      I code since ~8 years in C#. I improved myself all alone over time. I know the patterns that are most readable and workable with. I do not adhere to any rules aside from what I think is right. DRY is something I automatically adopted for example, but I'd make an exception when it's about something that is performance critical (avoid chained method calls). I do not adhere to at least half the programming patterns because I think they are redundant. I would if they turned out to be useful at some places. The factory pattern for example... there is no use-case for what I did and do.
      I write a lot of universally usable code that has no dependencies, but encapsulates more or less complex logic. I found a pattern in which every .cs file can be copied out and pasted into other projects, and it will run, but the original project could also be compiled into a DLL and referenced, and also both (just in case).
      For me well written code and well structured project structure is of high importance unlike to my colleagues. I take everything as guidelines and apply practices as I deem best.

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

      Worse than dogma is the resistance to experience just because an engineer/developer thinks he knows best but the rest of the team gets slowed down because of it.
      Met too many people using the word dogma without ever thinking twice what the right architecture for the project should be and why. More than experience with people using the word than actually understanding it fully. Not saying you are. Just saying everyone I met during my decade.

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

      @@carlsandsten11 I'm a little confused by your comment, what do you think dogma is?
      You say that you've met people that use the word dogma and then don't think twice about what the right architecture is, you mean they just go with "this one because it's the one we always use"? ...I would say that's dogmatic.
      I also don't know if I agree with your point about junior devs, if one always told me he/she was right and I was wrong, I'd get annoyed, but junior devs sure as hell can challenge my opinions and ideas, it's never slowed my team down significantly.

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

      ​@@brianviktor8212you know that you can have "function" that are compiled into the code, so that it don't need a function call? (At least in low level languages)

  • @davidlanda2324
    @davidlanda2324 Рік тому +13

    Always separate IO from logic. My test to prove that my program is well structured is: 1) Is it easy to write tests? 2) Are you able to easily implement a dry run or swap the CLI for the GUI? 3) Can you easily write to the console and at the same time redirect the output to another program (which makes sense only for the CLI)?

    • @JanMagnusson72
      @JanMagnusson72 Рік тому

      This is also my rule of thumb. If you follow this, the code is generally easy to understand, easy to debug, easy to change and modular. It very likely also works.
      But it is a rule of thumb, not the law.

  • @Bliss467
    @Bliss467 Рік тому +27

    A method SHOULD mutate or expose the state of the class. If it doesn’t, then why is the function inside the class in the first place!?

    • @davidlanda2324
      @davidlanda2324 Рік тому +8

      Because this book was written for langauges such as Java where one can't write a function outside a class. Anyway metod CAN change a state, but that does not mean that you have to mutate an object. You can return a new object. Mutation can be avoided and is must have in multithreaded environment.

    • @rogerdinhelm4671
      @rogerdinhelm4671 8 місяців тому +1

      Because in Java classes also act as kind-of like namespaces in C++, sometimes they are just a named scope of identifiers

    • @Brian-ro7st
      @Brian-ro7st 8 місяців тому +1

      Because you can’t write anything outside a class in Java. Your framing main function is in a class. You’d think Sun would’ve realized they were being too rigid the first time they wrote a main function, but no. Same reason every Java code base ends up with abominable util “classes” which are just a collection of methods that don’t fit anywhere else.

  • @chri5toph_k
    @chri5toph_k Рік тому +43

    It's a pity you didn't go through the crazy last example of this article. I read Clean Code around three months after I had my first programming job, because a senior dev coworker recommended it to me.
    I wasnt so critical towards the super small functions, even though I never followed it to such extent. But when I read, how he refactored the Unit Test, I instantly thought, that I would never would do that in such a way

    • @JamesSmith-cm7sg
      @JamesSmith-cm7sg Рік тому +8

      Months into your first programming job, and you already know better 😅

    • @ludovicmanga8241
      @ludovicmanga8241 Рік тому +4

      ​​@@JamesSmith-cm7sghahaa just though the same. Robert C Martin says at the beginning of the book that you may disagree, but respect the fact that these guys have been professional developers for so long, more than 40 years. So it is hard to match 40 years of experience with 3 months lol

    • @gristlelollygag
      @gristlelollygag 9 місяців тому

      Is it just me, or number of years does not equate credibility? It's the merit of ideas, not length of time you spent typing code in an office@@ludovicmanga8241

  • @leakyabstraction
    @leakyabstraction Рік тому +45

    One of the things we realized is that functions with procedural code of 100-200 lines is not that bad. It can be read linearly in a highly intuitive way, as long as it's well-structured. Yes, you can extract the chunks into small functions, but that often provides little benefit, at the cost of creating more indirections to follow, with the added risk that the function will be badly named because the developer wasn't able to find the right name for the subconcept. I think one golden rule for abstractions is that you MUST identify an actually good abstraction with an actually good name. In reasonable, non-bizarre scenarios it's always much easier and cheaper to extract/abstract later than to deal with a structure that is build on horribly unintuitive and badly selected concepts.

    • @g33xzi11a
      @g33xzi11a 9 місяців тому

      procedural is great if you diligently use guard clauses, are mindful of placement of intermediates, precalcs, and vars, and carefully use conditionals and nesting.

    • @vladimirljubopytnov5193
      @vladimirljubopytnov5193 6 місяців тому

      Function/method may have hundreds of lines and doing one thing (ie switch a mega enum) or be really small and do two, three things. My guide is to try to find a good, not overly general name for all what is done and if it feels wrong to read, then I split. Specifically, aAnbB(); is IMO inferior to a(); b();

  • @Sammysapphira
    @Sammysapphira Рік тому +42

    I hate passive speech like the title of this article. "Ok but can we talk about -" "Maybe it's time to stop - "

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

      I agree. It's never fails to make me cringe

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

      Oh man you’d fucking hate theo, then

    • @Gabriel-mf7wh
      @Gabriel-mf7wh Рік тому +1

      The better title would be "Stop recommending Clean Code"

    • @prism223
      @prism223 Рік тому

      It sounds like how women try to prompt sincere conversations with their virtue signaling, superficially judgmental fake friends.

  • @vd3598
    @vd3598 Рік тому +8

    It is interesting, that Martin explains Single Responsibility Principle not as "module should do only one thing", which almost everybdy speak of. This is separation of concerns. SRP is actually "module should change by same reason". Which is really not the same as the first definition. This means that even if several code blocks looks similar and the first impulse would be to extract this similarity into single external module, but they have eventually different clients, which may require these code parts to evolve differetly, we should leave them separate. So SRP is kinda opposit to DRY and good code is somewhere in between their contradiction.

    • @Zikuth
      @Zikuth 29 днів тому

      Almost looks like you are screaming to abstract properly the similarity because its a class on its own, making both principles equivalent

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

    13:00 Totally agree. I've always hated that example. It requires so much trust in the names of the functions, and even then you can't be 100% sure _how_ they're doing why they say they're doing.

  • @atrus3823
    @atrus3823 7 місяців тому +40

    I’ve always hated advice like a function should do “one thing”. A function ALWAYS does “one thing.” A that thing can be broken down into other single things, but that is always the case. If it can’t be broken down anymore, it’s pretty much useless. Encapsulating multiple “things” is the point of functions.

    • @markaurelius61
      @markaurelius61 3 місяці тому +3

      I don't think you get the advice. A function should be easy to understand at the call site. Having extra purposes makes it harder to understand.

    • @atrus3823
      @atrus3823 3 місяці тому +3

      @@markaurelius61 oh the irony. If the advice isn't easy to understand, it's not very good advice. That's exactly why I don't like it. I get the spirit of the advice, but it doesn't say anything actionable. It's pretty obvious things should be easy to understand, but "one thing" is too vague. It's not much better than saying, "you should always write good code". Not wrong, just useless.

    • @markaurelius61
      @markaurelius61 3 місяці тому +1

      @@atrus3823 Yeah, I get what you are saying, a little. I think I have internalised the idea of having functions do one thing, and to make the name say what it is. When I was a baby programmer there was the temptation to see that say 2 things were always done together so they could be put in a single function, but it was not easy to have a name or a concept that united them. But having a generic name like "InitializeData" would be unexpressive. Instead just have 2 functions called separately, say "ReadDefaults" and then "ConfigureUI".
      Does that make more sense?

    • @ShadowZero27
      @ShadowZero27 Місяць тому

      your functions only do one thing? smh

    • @sooja-pi9zd
      @sooja-pi9zd Місяць тому +1

      The 'one thing' advice means it should do 'one thing' at a given level of abstraction. E.g. if one thing at the lowest level of abstraction might be "check there is an @ symbol in a user's email address". One thing at a higher level would be "validate the user's credentials". And then at the highest level it might be "create a user record".
      It's ok for "create a user record" to have multiple sub-steps inside it, because they still collectively add up to one thing.
      What's not good is doing more than one thing at the same approximate level of abstraction.

  • @yoshi_mel
    @yoshi_mel Рік тому +4

    I've refactored that code listing to what I would do, mostly by inlining everything - it turns out it is all a single function render() that is not even 30 lines long. It's super straightforward logic, I never indented deeper than single ifs, it fits in a single scroll, and it is painfully obvious that all it does is add some test stuff around the page.
    The right abstraction is not a class, a method, a GoF concept, but a function.

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

    Flip just flipping off prime by leaving shit in haha 😂

  • @olafbaeyens8955
    @olafbaeyens8955 Рік тому +44

    Clean code only works when you wrote it yourself. But fails when you hand it over to another team and you think that the other team that inherited your clean code is stupid because they don't understand it.

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

      even then it dont work

    • @theodorealenas3171
      @theodorealenas3171 Рік тому

      Yes dammit. By the way I do wish one day the average skills will rise and we'll be able to write cleaner code without bothering people.

    • @ghosthunter0950
      @ghosthunter0950 Рік тому +7

      Really? I mean clean code was originally defined as readable and easy to understand code.
      So you would have been wrong by definition. But I think people have really shifted this to aesthetically pleasing code instead.

    • @theodorealenas3171
      @theodorealenas3171 Рік тому

      @@ghosthunter0950 it's easy to leave. You went to the wrong function and you quickly realize it's the wrong function. It's not aesthetically pleasing.

    • @olafbaeyens8955
      @olafbaeyens8955 Рік тому

      @@ghosthunter0950 It looks nice, it looks readable but that does not mean that the code works as expected.
      In a lot of cases is obscures bugs because you assume that it is too nice to have a bug in it.

  • @d-rex7043
    @d-rex7043 Рік тому +4

    I started getting into a procedural style, under my own steam, when doing a C course in uni... but after making all these beautiful atomic functions, I then had to pass about 5 or 6 of them in as arguments to the function that would utilise them to actually do the intended task and so the argument line would end up longer that the function body!
    When the coordinator's 'Solution' was released, it would generally be a few chunky functions that would get a whole task done (Parse args...Do the Program... Output/Terminate) and the odd helper, simply for carrying out a sort, or something, by wrapping a library function to suit this particular program.
    It probably too him less time to code the entire assignment than it too me to figure out how my 'simple' functions were going to interact, on a whiteboard.

    • @etodemerzel2627
      @etodemerzel2627 Рік тому +8

      Passing 5-6 functions as arguments? Are you sure you were doing procedural programming?

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

    So, here are some missing things, that both Pimeagen and the author missed:
    0. Problem: "I have a bunch of small functions, and then I have a big function that's a mess of all of the other ones"
    Answer: This isn't really something that's a problem; these things can be broken down into phases. The lower the level of the library, the tighter the function should be, and the less stateful it should be. There are bootstrapping phases, and there are compositing phases in architecture; regardless of whether you're talking about FP or OO or just Imperative Proc. In FP it's the I/O code, and everything else is stateless. In an OO server, it might be a "Controller", in proc, it's whatever is close to Main; the closer to the start of the callstack, the more messy and mutative you can be, as you tie the pieces together. But you don't want your math / i/o / string / date / etc libraries to be internally stateful, or you're stuck on one thread, and in one single function invocation at a time, period.
    1. Problem: "I pass in booleans when I shouldn't and something is wrong, and I don't know what"
    Answer: Bob actually talks about this, and the author didn't catch it? And it's good advice. A function might have a bunch of control structures to figure out what *should* be done, but then call out to another function to *do* them. That generally gets rid of the boolean passing, because the outer function decides what to do, and the correctly chosen inner function does them.
    2. Problem: "How can Bob say that a function should have 0 arguments, but also no side-effects"
    Answer: the book is about Java, not about any other language. His point was that an object instance should return a *new* object instance, rather than mutating the old, when possible. So technically, the function has access to all internal/external class properties of that instance... it just shouldn't mutate them, if performance considerations allow for it. For procedural languages and functional languages, this is just treating data as immutable (whether or not it is actually immutable); as for the number of arguments, it goes from 0 to 1, if there is no `this`. Simple as that. His point was "ideally, it should take 1 struct and return a new value of some kind". It's just that in Java, the struct is `this`.
    3. Problem: "Bob wants DRY everywhere"
    Answer: actually, Bob suggests pretty hard against DRY. Point being: if functions are tiny, and they do 1 thing, you can use them to do 1 thing on a bunch of stuff. Think `.map`; if it were a function called on an iterable, or a stream, or whatever, rather than a method, you could use it on a lot of things, in a lot of cases. That's his version of "DRY". In FP, that's called "Function Composition". Primagen called it "Legos". 100% same deal. He specifically warns against the typical DRY: that being big, gross kitchen-sink abstractions that need all kinds of special-case behaviors ... he already warned about how gross DRY can be when he suggested the Interface Segregation Principle and the Liskov Substitution Principle; he doesn't go back on it, here.
    There are others, but ehh. This is enough.
    I really think this author missed the crux of the book, entirely. Not to say all of it's gold... and a bunch of it isn't relevant, unless you're a Java / C# dev, specifically, and only using Java patterns that predate JDK 1.8... but a lot of the points in the book are either being intentionally misconstrued, or just obliviously missed (I presume due to lack of historical context of where the industry actually was, and what Bob is even talking about, and what problems the book was solving for).
    Now, none of this is to say that I'm 100% in Bob's camp. There's a bunch of good advice in the book; advice, not dogma; please don't start a religion of Bob (too late, I know).
    Personally, I hate the `IncludeX(); IncludeY()` nonsense. That feels like PHP to me. It also feels profoundly stateful (given they are not returns, but outputs). And thus, I find them antithetical to his point about functions. I wouldn't have a problem, however, if they were returns building properties of an object: `header = getHeader()` et cetera. When it's just i/o and no hidden state, there's no extra context to load, and no gotchas, it just does what's on the tin. That's not to say that all code can be that simple, but it is worth trying for, rather than having stateful code buried way down the callstack, and realizing that you can't have more than one network connection or thread or concurrent process at a time, because you start giving data to the wrong user.

  • @sburton84
    @sburton84 Рік тому +20

    I knew Uncle Bob could be a bit dogmatic with his rules but I at least thought his code would be alright, but I'm actually shocked how awful those examples are. That first example would be a good example to show someone to demonstrate the meaning of the phrase "spaghetti-code".

    • @itellyouforfree7238
      @itellyouforfree7238 Рік тому

      He is not a good programmer. He is not even a programmer, just a preacher. He's an incompetent wannabe going around preaching nonsense to misinformed coders.

  • @afayes
    @afayes Рік тому +11

    I have used the pattern of using very small methods for some time and can shed some light on what I think.
    One big disadvantage is that understanding the whole implementation is a lot harder.
    One advantage is that, you can quickly understand how a single function works at the current level of abstraction by reading through the well named method calls. The method implementation reads like natural english rather than code. It is easier to mentally process a single verb or phrase than to read multiple lines of code. This is at the heart of this style of coding. It is about quickly understanding, with little mental processing what the current method does, at the current level of abstraction without caring about the lower levels of details.
    A class in an OOP language like Java will typically have a few public methods. Using this style of code means that these pubic methods will be small and orchestrate their implementation calling private methods. A developer reading a public method can quickly grasp what it does at a high level without needing to process low level implementation details unless they need to i.e during debugging.
    Whilst I do find this style of coding elegant it can lead to lots of small methods and also figuring out the whole implementation and what the code is doing from A to Z is a lot harder than if everything was coded in a single method.

    • @minastaros
      @minastaros Рік тому

      The truth is probably in the middle. Both have pros and cons. Thinking about rather smaller functions is certainly better than rather larger ones. But making _tiny_ ones only because you can is exactly the evil you described: then they lay side by side in a class _without workflow cohesion_ , which the same code would express if it were together.
      As you say: quickly grasping the _overall_ functionality by only reading high-level concepts is one aspect.
      But sometimes you need to track down a feature (or just debug something) from top to bottom in foreign code, and that can get very very tedious with the number of levels. That's what the "as small as possible" advocates oversee: the more functions, the more levels on the call stack, which _increases_ noise on another level.
      The art is to balance that out: providing a level where the program structure can be understood on a high level, and likewise help those who need to dig deeper by avoiding fragmentation.
      (You notice that I always look from the reader's side - that's what the future writer-me will be on my own code, and all the others that might review, debug, maintain that code)

  • @redhawk3385
    @redhawk3385 Рік тому +14

    I had a teacher in college who took the clean code pill, and I was one of the few who thought it was bs the whole time.

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

    2:24 I love one comparison which our teacher taught us. You don't want whole bread or breadcrumbs but slices of it.

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

    I do a lot of mathematical calculations in the code I write, often statistical calculations. So I run into scenarios where it's "Validate you have all the data, if you have all the data, calculate the results of the data, then determine if the results of the data meet conditions." I COULD split that into three chunks of code, but there are a TON of variables that are getting set as part of validating the data, that then get used in calculating the results and/or in validating the conditions. That's a few hundred lines of code, but it does ONE thing, get the data into an overall result.
    I have other functions that are incredibly short (as little as 2 lines), but I cannot always make them short when the logic is somewhat involved.

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

    I really enjoy watching your videos! Being still in the beginning of my programming career and trying to learn from books, I often find myself wondering what experience has taught programmers before me since these books came out. You're down to earth and can easily call bullshit. That's very entertaining 😂

  • @segueoyuri
    @segueoyuri 9 місяців тому +1

    the thing about rules is that you should adhere strictly to them, until you know enough about the thing in question to know in which case it's best to break the rules

  • @zactron1997
    @zactron1997 Рік тому +16

    My rule of thumb is a function/method/class/variable/etc should exist in such a way that the intended maintainer can fully understand what it does and why.
    If my code needs to be maintained by less experienced devs, then I'll put more effort into atomizing concepts to move more of the code base into higher level abstractions. If my team is more experienced, then abstractions can be a little more complex.
    Overall, I really like the style you use and propose.

    • @g3ff01
      @g3ff01 Рік тому

      Thank you!

  • @JulianBG
    @JulianBG Місяць тому +1

    That "thing" with the boolean parameters is easy to describe - your function is indeed doing too much, for example it "updates" in one case OR "saves" in another place. Basically you've created one big function, doing two different things and that made sense in the moment you've build that way. Most likely you had only one place where you needed to call that function, but now you need to reuse that function and call it in a different place. Adding this boolean parameters "fixed" the *issue and now you have in one case do one thing in another case do another thing. But the *issue was that you have to refactor this method and split that functionality in reusable pieces of code. So adding boolean parameter means - refactor, split and simplify. Adding boolean in 99.999% of the cases will make you loose more time in long term, instead of refactoring is stright away.

  • @MrOnePieceRuffy
    @MrOnePieceRuffy Рік тому +7

    Abstraction itself is already the Compilers Nightmare, because it can't predict sh*t from it, but to abstract every few lines of code into interpreted functions (a compiler would optimize them away anyways) would be the Processors Nightmare aswell, so I can't take his advice other than "create the pure Hell for your Computers" and well, no need on that, thanks.
    If an C-Dev who creates branchless code on a daily bases, would give me "clean code" advices, I would start to listen,. WithJava I just start laughting.

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

      Wrong approach I think. The code should be optimized for humans to read, then the compiler or preprocessor can optimize it for the machine as much as it likes, IDGAF, just do not want to read code which was optimized for the compiler.

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

      But, that's my whole point on it... If you write branchless C-Code in embedded Systems on a daily basis you know THAT and WHY your code is ugly.
      If such a person would have advices how to write clean code, I would want to hear, what he have to say about it

  • @DinnerIsDelayed
    @DinnerIsDelayed 11 місяців тому +4

    Flip in fact, did not cut it out lmao

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

    I'm new to coding, since this is my third career) And it always seemed to me that I'm not a very good programmer, although I like it. Like it more than anything else I've ever done. But it turns out that I independently developed exactly the same approach to clean code as you have. It's cool to realize that good programmers think the same as me.

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

      The only "good" programmer is the one who gets the job done with acceptable tolerances, with bonus points for getting it done fast. Limits are OK as long as you're aware of them and not blindly jailing yourself into a paradigm.

  • @chetstriker
    @chetstriker Рік тому +17

    Debugging an issue becomes a nightmare when people create functions inside functions inside functions. It drives me crazy when I see that

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

      I bet Martin would say about needing to go into debug is a failure of clarity in code, or something like that.
      Funnily enough there are highly successful devs who when exploring new codebase NEVER start from reading the code instead immediately stepping through it with debugger.
      What tools you use definitely changes your perspective on what good structure looks like.
      Another example might be code completion and dependency injection not playing well together.

    • @Winnetou17
      @Winnetou17 Рік тому +4

      Hell yeah! When I have to raise my "max open files" to 100 in my IDE just to be able to have a normal, maybe a bit complex, flow opened and having 5 "Processor.php" files ... yeah, VERY clean, I can't tell which is which, where I started, where I went, so helpful, much productiveness wow!

    • @aoeu256
      @aoeu256 Рік тому

      Instead of debugging you could write tests.

    • @aoeu256
      @aoeu256 Рік тому

      @@AntiCookieMonster For a code base in a dynamic language you could write introspection tools that convert every function into a logging version of a function, and then get your editor to show the logs next to the function when your editing it while the program is still running.

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

      @@aoeu256 I'm talking about when I get hanging somebody else's code that I'm supposed to fix and then you have to figure out what they were doing, and how they organized stuff. Tests are usually written after somebody had it working if they even bothered. It's easy when a function encapsulates an full idea minus the parts that are going to be reused a lot, but it's a nightmare when you're trying to read code where the function just points to 30 other tiny functions with pointless descriptions or hundreds of tiny 2 lines of code functions where you have to jump everywhere to be able to read anything

  • @istovall2624
    @istovall2624 Рік тому +4

    I like the scene in saving private ryan where they assault the machine gun post and the sgt is saying how bout this how bout that, and the cpt says "how but you shut up"

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

    My preferred style involves using sequentially increasing numbers as variable names and raw pointer arithmetic instead of abstract algorithms or function names. I AM THE COMPILER!!!

  • @BiHMaverick
    @BiHMaverick Рік тому +9

    I love how flip doesn't listen 90% of the time.

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

      it ain’t much but it’s honest work

  • @pixelfingers
    @pixelfingers 2 місяці тому

    You don’t know how much I laughed when you inlined those functions and made the code easier to understand

  • @zxuiji
    @zxuiji Рік тому +8

    14:54, While I agree they went too far with their refactor I also think waiting until you've duplicated even once can be a bad thing, for example recently I was programming a custom preprocessor to run BEFORE a normal preprocessor, the loop for mapping characters to code sections grew fairly large and it became hard to keep in context what was being done where, so I created a couple of inline functions above the main function and shifted the relevant code there, with that I was more easily able to see what was being done where since I only needed to call one of them in a if statement and the other afterwards to add the actual section of code. A few re-thinks later and I had a brutally simple preprocessor that will be able to support loop, templates, types and the usual macros :) Still working on the library that will support it though as the code will be part of the library rather than the app itself, the reason for that is so I can use it on shader code also.

    • @Jason-xw2md
      @Jason-xw2md Рік тому +3

      I think that living fast and dying hard by any rule or guideline is just limiting yourself. Imo one should take the pragmatic approach, if it makes sense to abstract something right away then do it, if it doesn't, then don't. Everyone wants to apply things unilaterally and treat these guidelines like silver bullets instead of just using them as a tool

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

      That's the differenc betwen "This code is becoming overly complex, what are the functional units I can extract out to make it easier to reason about" vs th clean code "this if block has two statements thy must be made into a fun tion that als ocals a function that calls another function to set a single class variable".
      There's logical places to split up code but they never lead to anything near what "Clean Code" dictates (aka clean code =/= "Clean Code" in the slightest)

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

      I think the original idea was that if the only reason to refactor is because you want to avoid duplication THEN you should think that it should be used in 3 places and only then abstract it. Not that all abstractions should come from using duplications.

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

    The problem I have with dogmatic DRY is that sometimes the same (or nearly the same) code in two different places is two different conceptual ideas that happen to have a similar implementation, for now

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

    Clean code in my book is just ensuring things are properly named, the control flow is easy to read and swapping parts out if necessary is not a massive headache. I don't believe that's something which should change.
    Basically, overengineered solutions are not clean code and I will die defending that hill.

    • @ThePrimeTimeagen
      @ThePrimeTimeagen  Рік тому +4

      I get you have your own definition, but that's not the definition of clean code. Clean. Code is a methodology.

    • @CottidaeSEA
      @CottidaeSEA Рік тому

      ​@@ThePrimeTimeagen I am very aware of this. The article itself also mentions it in the beginning, that we all have our own definitions of what "good code" or "clean code" is. However, even if looking at the clean code principles, what I've said falls in line with those.
      The issue with what the examples given in the article is that they do not follow the KISS principle (keep it simple, stupid) that is also a clean code principle, they actively contradict the clean code principles. If you add loads of layers of abstraction through extracting functionality that doesn't need to be extracted, you're not keeping things simple.
      So I'd say I'm very much in line with this methodology.

    • @NoX-512
      @NoX-512 Рік тому

      ​@@CottidaeSEAThat is Clean Code in a nutshell. Some tried and tested rules of thumb, combined with rules that are outright ridiculous.
      You can't honestly tell me you are ok with that mess being recommended in CS classes.

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

      @@NoX-512 Once you take anything too far, it stops being useful. These people take the naming and small function stuff to the extreme, which is not useful at all. As the article also explains, the given code examples also go against the very principles the one who wrote the examples promotes. That's how bad the examples are.
      This garbage is just bad code that violates the very principles it is supposed to promote just for the sake of keeping functions small.

    • @NoX-512
      @NoX-512 Рік тому

      @@CottidaeSEA You are wrong about that. The examples are in line with Clean Code rules. Clean Code is taught in CS classes as rules to follow. I'm sure you would agree we shouldn't teach students bad habits, since bad habits can be very hard to get rid of.

  • @jackbarrett3599
    @jackbarrett3599 Місяць тому

    I agree with the “one concept” idea, personally. For the project I was just working on, I kept functions to one core responsibility, but some of the functions ended up being really large. One function, in particular, had a ton of if-statement branches, and in those branches, possibly more if-statement branches. But, there was a logical structure to things… And to keep that logical structure apparent, and make the code nicely readable, I threw #pragma regions all over the place, whose names corresponded to a brief description of what that segment of the function was doing. This is a c++ thing that allows you to collapse segments of your program down in your editor, so that all you see is the region name. Then, you can expand things as needed to look at their internals, but otherwise get a concise, easy to read idea of what a function is doing, even if the function is really hundreds of lines “under the hood”.

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

    I don’t think it’s procedural vs functional, it’s procedural vs declarative. Any worthwhile high level code is going to be declarative, because it allows the procedural implementation to optimize because it’s abstracted.
    SQL is a great example of declarative, because you don’t tell the system “how” to get the data. You just declare the data that you want and the DB will determine how best to meet that.

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

    Clean code would not be as widespread if it were not the laziest possible thing for reviewers to point out in reviews, along with whitespace nits, extra new lines whatever. Noobs and 'senior devs' alike love to pounce on this shit because they don't take the time to understand the actual point of your changes. I will sing the praises of the reviewer who finds a logic error in my code, which happens from time to time.

  • @PbPomper
    @PbPomper Рік тому +18

    I think most ideas and concepts from Clean Code are good general advice. Its mostly common sense. You still also need common sense to know where and when to apply them and when to "break these rules".

    • @khatdubell
      @khatdubell Рік тому

      This is true for programming in general.
      If you can recognize the benefits of advise and when to apply and it when not to apply it, regardless of your title you’ll always be a junior developer.

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

      Yes, Martin has a few demonstrations of himself coding for warm up and stuff, and he's just a good programmer who says philosophies. But I wouldn't call the concepts common sense, they're eye opening to me

    • @g3ff01
      @g3ff01 Рік тому

      It's common sense, because you already know this. For example washing hands after toilet or after an autopsy is common sense, but it was not before 19th century. Doctors even laughed at Ignác Semmelweis because of it.

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

    One of the things Bob Martin doesn't do in this example for some reason is split the thing into two classes, for suite and non-suite ones

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

    Doesn't all code start out as procedural code, at least in part? The very idea of the main function is just that, no? So you can have 99% OOP or 99% functional, but it always starts out with that very first procedural entry point.

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

      If I think about this too much I find myself in a philosophical crisis regarding the creation of the universe

    • @christiansurf1346
      @christiansurf1346 Місяць тому

      There is no procedural code. Everything is a function in OCAML, LISP F# etc. 😂

  • @AshtonSnapp
    @AshtonSnapp Рік тому

    A good litmus test to figure out if your code needs to be refactored, is if you can come back to the project, read the code, and figure out what is going on. If you can’t, your code has a readability problem and you need to refactor. How you refactor is up to you.

  • @khatdubell
    @khatdubell Рік тому +7

    18:34
    This guy either actually just skipped ahead to the listing and didn't read the book, or he's being purposefully disingenuous here.
    This is what the book says about that code.
    _"the method call render(true) is just plain confusing to a poor reader. Mousing over the call and seeing render(boolean isSuite) helps a little, but not that much."_
    The context of this code is BAD code that he is refactoring in the book.
    Its not his ideal, written from scratch, "this is how you should architect things" code example.
    More to the point *Its not even his code*
    Its publicly available java code HE IS REFACTORING.

  • @bill.j.pearce
    @bill.j.pearce 8 днів тому

    Gosh it's so nice to see people calling out this nonsense. I've had senior developers point to this guy's books as gospel and mandating short-as-possible functions, when it literally made the code so much harder to work with and reason about, and they themselves inexplicably couldn't follow the advice.
    When 80% of your code is just functions calling other functions calling other functions, it can be SO hard to track down where behaviour actually lives, and then so much more painful to change it when requirements inevitably change or behaviour needs to be added.

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

    I stopped reading the book after I read his advice on functions. And I am very glad I did not read this early in my programming career.

    • @airman122469
      @airman122469 Рік тому

      Yeah, the advice on functions is garbage. The architecture guidelines aren’t horrible though.

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

    Return values vs output parameters are mostly identical at the assembly level on x64. 1st register is used for the return value (class MEMORY in the x86-64 ABI) and whichever register or memory is used for a given argument index.
    EDIT: It's OK to use output parameters when they're write-once, and don't need initialization.

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

    Speaking to the deez nuts naming convention. I ran into an old var at work that was for Total Number of Assets for Beginning Of Year, and so now I gotta reference TotNumAssBOY for a full sprint.

  • @ebn__
    @ebn__ Рік тому +7

    17:45 You are not crazy sir, that's the only reason for OOP to exist.

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

      Wasnt "Clean" done in a world of newbie programmers doing OOP?

  • @ohmyv3gatron
    @ohmyv3gatron Рік тому

    I’m glad he said “Lego” because that’s exactly what I think of especially when using lisp. In lisp it’s nice because you can evaluate your small form right there and guarantee/see that that one little piece works right then and there.

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

    I never understood even the distinguishing between OOP and PROCEDURAL (to some extend). Yes oop has Abstractions, inheritance etc, but in the end the code is still called in some predefined sequences. So a lot of the time, it's just calling A.function() instead of function() itself

    • @MichaelPohoreski
      @MichaelPohoreski Рік тому +4

      You are essentially correct. Too many programmers don't understand you can write OOP in C or even Assembly Language (the game Robotron: 2084 written in 1982 did this!) There is a reason the original C++ compiler, CFront, would translate C++ into C.
      The difference is more about providing a *standard implementation to an API* automatically by the compiler. e.g. C++ the compiler automatically pass a hidden "this" pointer. In C you can get the exact same effect by manually passing a "self" pointer. The C++ compiler automatically generate virtual function slots. You can have virtual functions in C you just need to manually do it.
      C++: Bitmap.Draw( int x, int y );
      C: Bitmap_Draw( Bitmap *self, int x, int y);
      You can tell Dennis Ritchie didn't understand the importance of providing an standard API with fseek() and fread() having the argument FILE appear in a different order. :-/
      int fseek(FILE *stream, long int offset, int whence);
      size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream)
      fread() should of had the FILE be the first argument since you are doing something WITH a FILE object.

    • @etodemerzel2627
      @etodemerzel2627 Рік тому

      I see OOP as a toolset full of very advanced tools. You can use some of these tools when you need. Unfortunately, many of the modern programmers have never learned anything else, so they tend to overuse the advanced tools as if they were just primitive building blocks.

    • @roboterbasteln
      @roboterbasteln Рік тому

      C++ classes just provide the structure for stuff that belongs together and preserve object state. In C you'd have a struct (the data; POD) and some free functions to operate on the struct. In C++ you can put the data and those methods into one class. That makes it clear what belongs together and works together. Also, you can design a class in a way that it will always keep its invariants, i.e. it never produces an object in an invalid state. That's impossible to achieve with structs in C, since all fields are publicly accessible.
      So, most important aspect of OOP for me is encapsulation, not abstraction and certainly not inheritance. IMHO, inheritance is a much overused concept and FCoI (favor composition over inheritance) is the way to go.
      You ask, how is OOP different to procedural. Let me ask back, what is the difference between procedural and imperative? There is no difference. Procedural is imperative and OOP is procedural. They are contained in each other.

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

    About the function discussion, It's probably more effective trying to think to break functions not in how long it is, but about the properties of the function.
    Is the function extensible?
    Is the function testable?
    Is the function isolating a problem?
    Is the function easily readable?
    I think the decision if a function is long enough should come from the concept you are trying to implement, from it's purpose, or any other property related to it's use.

  • @digitalnorth
    @digitalnorth Рік тому +4

    Unrealistic Code beauty standards in 2023 ? Nahhh

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

    Your comment about integration tests being much more useful for refactoring than unit tests rings very true to me. Only recently I was working on refactoring a horrible data processing pipeline (...written by myself, previously, of course...) and the most useful test was a rather ugly integration test that stupidly diffed the state of a database populated by the results of the pipeline with a reference database.
    The unit tests constantly broke, since they explicitely tested the clunky functions I was working on pulling apart. Up to now I blamed my own incompetence for this. But I start to think that tests are only well-decoupled from implementation details if you already have decently factored code in the first place.
    It's the opposite when adding new functionality. There, such a test is obviously useless, while the unit tests can check the influence of changes to other parts of the code on the behaviour of the unchanged code under test.

    • @FlaggedStar
      @FlaggedStar Рік тому

      I frequently find this problem. How am I supposed to unit test code that was never written to be testable?

    • @buzz1ebee
      @buzz1ebee Рік тому

      We mostly write integration/API level tests at our place. We'll write unit tests is something is particularly complex, but most of the things we want to test are "if the app is in this state, and this endpoint gets hit with these arguments, the app returns/changes this stuff". It's incredible for refactoring as you can touch huge portions of the code base, once you understand which abstractions will be beneficial, and if all your tests pass you know everything is working.
      Writing tests for individual functions is a bit of a waste of time most of the time. We don't care about implementation as much as we care about functionality and results of the app.

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

    The alternative to DRY is worse...
    Having to change code thats duplicated somewhere else, and you don't remember where or even know anymore that it is somewhere else (the norm when working with multiple people). The result is you change functionality only in one place, fix a bug only in one place.
    Now image you have duplicated code that again contains duplicated code -> problem gets twice as big.
    If you find that you dryed something wrongly, it's easy to tear it apart again (and this will happen less with time, because you will learn if something is just accidental duplication or not). The other way is less trivial.
    Repeating yourself three times:
    You repeat something -> have I already repeated this before? You need to search the code base if you repeated something AND you rely on it hasn't been refactored locally (e.g. Better variable name) and that you need to search a small enough subset of the code you are duplicating, because you don't know how muchbof the code may have already been duplicated.

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

      well, no
      if it's a common method which can be factored out -- it will be factored out
      if it's not -- probably it's a different thing, and you shouldn't group that in the first place

    • @khatdubell
      @khatdubell Рік тому

      @@Inf1e such an idealistic view.
      Take any significantly large codebase and you find find chunks of repeated code.
      I’ve personally been bitten by this bug enough times that before I change something I do a search on the codebase for identical code.
      The problem with that is that it might be identical, but not 100% identical.
      So a place that needs updating doesn’t get it.
      If you find yourself copying a block of code, you should ask yourself if you aren’t better off making it reusable.
      If the answer is no, you should probably notate that it’s a copy of similar code

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

      ​@@Inf1e my team recently spent about 6 weeks refactoring some code which had chunks copy pasted at least 3 times in different areas, I think the record was same chunk 9 times in different files. it was a bloody mess to untangle. This is what happens when you don't follow the DRY principle.

    • @Yay295
      @Yay295 Рік тому +4

      @@darylphuah We had a collection of 16 applications all using the same common code, and all of it was duplicated. Except sometimes it had been changed to fix a problem in one of the applications, but not the others. It took me a few months to untangle that, making sure to keep all of the bug fixes from each of the applications, without breaking one of the other applications by adding that fix.

    • @marcusrehn6915
      @marcusrehn6915 Рік тому

      It makes sense to have a few set ways to communicate with another service, but I see so many cases where module X is used by A, B and C, in the name of DRY. Then something changes in B, and then someone adds some more parameters and if statements to X. Let this repeat for a while and you got yourself a ball of mud.
      In so many cases, copy pasta makes more sense.

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

    11:58 a function isn’t too long when it’s over a line limit, it’s too long when the code inside is getting away from the purpose of the function

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

    The functions in the example are not there to prevent repetition, they are there to hide the implementation of the different concepts behind an english word description of what is happening. The idea is that you do not need to know the details about how you include the setup page, you just need to know that at that point, that portion is being handled. The whole point of clean code is to write for the next developer who has to work on the code you wrote. The private, only used once private functions will be inlined by the compiler, there will not be jumps, calls or returns made.

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

      But then you have the situation that the English description is faulty, it does not encompas exactly what the function does. It's worse than a comment. And you have broken up flow instead of through flow, so when the code does something that isn't quite what you expect it to, it takes too much extra effort to understand.

  • @fernandor4617
    @fernandor4617 5 місяців тому +1

    Most devs are completely dogmatic about Clean Code. It seems you can't criticize anything about it. Its REALLY good to see some criticism. Thank you! I agree on most things.

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

    Tell me you've never worked on a codebase with a single, thousand lined function without telling me you've never worked on a codebase with a thousand line function.
    The problem with saying "be reasonable" instead of following dogmatic rules is that everyone has a different version of what is and isn't reasonable.
    The villain in the story never thinks they are the bad guy.
    When you give someone a rule to follow, they don't have to think about it.

    • @HrHaakon
      @HrHaakon Рік тому +4

      That's a great argument for code reviews, standards, having the tough conversations and agreeing and sticking to conventions.
      Which is the hard part of being tech lead. But that's your job.

    • @NoX-512
      @NoX-512 Рік тому

      If the rule is good, great. If the rule is garbage, you are in for a shit show.

    • @channel_channelson
      @channel_channelson Місяць тому

      Listen to this guy, only extremes exist!

  • @saunved
    @saunved Рік тому

    I have found unit tests to be incredibly useful during refactors. They offer solid proof that your code works as intended and can help avoid obvious mistakes by forcing you to think about potential edge cases better. As long as you don't overdo it, they're a nifty tool.
    Whenever I'm refactoring a function (read: changing HOW it does something and not WHAT it is doing), I add unit tests before just to ensure that the overall input->output is stable. It acts as concrete proof for the refactor.
    If someone's refactor is changing the behaviour of a function - then it's not a refactor. It's basically a feature or patch and those are only truly verifiable via integration tests.

  • @MrShnaiderTV
    @MrShnaiderTV Рік тому +4

    9:17 - It's so funny when he says "I find all of this incorrect" and then switches to his code, which follows exactly the rules from the highlighted paragraph. The difference between the thinking of Martin and the author of the article with the author of the video is that they believe that the class is read all at once. In reality, while reading, you do not fall below one or two redirects, because you want to understand "what" the method does, and not "how" it does it in all the details. Such a division into functions allows the programmer who reads the code not to waste time on pieces that he does not need and it is polite on the part of the author of the code to give him/her the opportunity to stop at the level of abstraction at which he/she needs it.

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

    I like to have this "orchestrator " function that uses the smaller ones to build the narrative - this allows for smaller pure functions that do not alter any state and leave the orchestrator with that job. Although I can see this only working for "service" classes and such, not if your class actually represents an entity, for example PushNotificationService & UserModel.

    • @roboterbasteln
      @roboterbasteln Рік тому

      Yay! Maybe someone who knows Mark Seemann and not only has the narrow R.C. Martin point of view.

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

    Clear Code > Clean Code

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

    I agree 100% with not mixing levels of abstraction in same function. You absolutely should not do high level business logic and low level socket initiation in same function.

  • @poseiso
    @poseiso Рік тому +4

    I used to code like that...
    then i worked on this moderately size project
    and made the functions *atomic* and holy shit it was hell
    and yes there was a lot of unnecessary indirection and abstraction
    thankfully i've learned now

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

    Dry is only good when you are 100% sure that the code does not have to change independently of each other

  • @elimgarak3597
    @elimgarak3597 Рік тому +13

    Clean code and, in general, most software architectural concepts, are pre-science, which is sad. With this I mean there is absolutely zero reproducible experimental evidence backing up their claim that clean code or whatever other architectural advice they give leads to goal X (be it maintainability, lower dev time, etc.) with higher probability than other ways of doing things. In other words, it is almost speculative philosophy (which is fine to do in domains where you cannot do better than that, but this isn't the case so it is absolute BS).
    Instead of wasting time with platonic metaphysics we could be trying to make these hypotheses testable, and submit them to rigorous experiments. We could learn a thing or two.

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

      But are they even testable to encompass why people want clean code? I think that we will find such tests to be very uncertain and as such not that useful simply because when we describe something as maintainability, we may well describe 20-30 different types of maintenance actions, which we have to order in important for a calculation of a score. All testing of Clean Code will likely rely on non-scientific decisions as fundamental axioms. The results will vary wildly.
      In such a case, it is more useful to make it a conversation of style about advantages and disadvantages that are speculative, because at least then people are encouraged to have practical experience with the subject matter to find out what works where.

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

      People nowadays are so desperate to apply "scientific" approaches, so desperate for the "objectivity" that it's really unsettling
      Really shows how traumatizing the death of God actually is

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

      ​@Airo Signi, Karna Duvi ha. My mind went there as well.

    • @elimgarak3597
      @elimgarak3597 Рік тому

      @@ZealForSouls by all means, practice whatever subjective pre-scientific approach you want to. Leave God and all of the other "absolutes" stay dead if you wish to. Just don't present it as something objective and impose it as an industry standard.

    • @tacsmith
      @tacsmith Рік тому

      @@elimgarak3597 Objective vs subjective cannot be applied to all things. And that is his point.
      As an example, objectively, it would be better to kill 10k children to save 100k others. But should I present you with that choice, are you going to make the decision scientifically, putting 10k kids to death because its objectively better in the name of science?
      Too many people think science is the new God of reality, but
      1. Its not always clear that science is actually objective) and
      2. When it comes to questions of "should you ought to" science often comes up short.
      3. Lastly, the scientific approach has been wrong as often as its been right.
      All hes saying is often times the answer doesnt require science.
      The two approaches arent mutually exclusive.

  • @alexs591
    @alexs591 11 місяців тому

    Depth is more important than length.
    A function with a simple clear signature that does a bunch of complicated stuff for you is a good function.
    ReassignTablets, MergeSettings, read, write, fork.
    Clear functions that do complicated things.

  • @Yuri-bt4wl
    @Yuri-bt4wl Рік тому +2

    Function calls take time (those precious little microseconds add up) and stack space.
    Too short functions means too many function calls.

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

      A good compiler will automatically inline function calls.

  • @sovahc
    @sovahc 7 місяців тому

    There are goals in programming: compact code, fast code, easy-to-understand code, reliable code. You have to balance it out. When you look at your code and say: I can't improve this according to my goals - you have the best code. That's all.

  • @BosonCollider
    @BosonCollider Рік тому +8

    I feel that a big cause of this is that many languages in 2008 did not let you define nested functions.
    Many classes that were written could be replaced with a big function, that defines some variables and some inner functions that are helpers or which are procedures that do work on those variables, but never escape the function body.

    • @NoX-512
      @NoX-512 Рік тому +4

      That’s not a big cause of it.

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

      just include a nested scope, C has that, so does C++, Java, Rust, Go, D, Odin, Zig and pretty much any real language

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

      That's just another way of producing unnecessary abstraction.
      Many classes can be written in a simple, procedural manner. You don't have to create these functions that return a function (e.g. in JS where it produces a lot of memory). It's just that people often become obsessed with these patterns or principles that they apply it to almost EVERY code without understanding when they are supposed to be used.
      In the pursuit of mastering these programming techniques, we sometimes forget that code can be written in a simpler manner.

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

      @@vhaangol4785 No no no, I didn't mean you return them. I just meant you declare the functions and use them only there. Since sometimes you do want the same block of code to be applied several times in the same function, but it will still not ever escape the scope of that function

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

      Note that in most languages nested function defenitions will cause performance overhead

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

    This doesn't need to even be a philosophical debate: code should be whatever it needs to be for it to be as easy as possible to keep working on it.

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

    23:44, I agree, with procedural you can see WHERE things start and end (with the exception of threading but going to have that problem with OOP too). Furthermore in procedural you can have your cake and eat it too, you want objects? Just make 'em and pass them as parameters, you want virtual functions? Just add callbacks to your objects or as parameters, or both even! There is 0 excuse for like OOP more than procedural, liking OOP more just screams you're incompetent at programming, pea brained or both.

  • @VideoViewer33512
    @VideoViewer33512 Місяць тому +1

    If you name your functions as verb phrases, you have a better chance of having a function name that describes what the function does. Example: helper() does not say how it helps, names like formatParagraph() or format() do at least give you a clue.

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

    I worked in a company where functions 1000+ lines were almost the norm, and I gotta say, it actually makes sense for them to be that big, the business rules involved are just that complex.

    • @Kavukamari
      @Kavukamari Рік тому +4

      When you have a very complicated concept, sometimes it can't just be expressed in like 5 lines

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

      I currently work at a company where there are functions that are 1k+ lines.
      They aren't "just that complex", people just suck at writing quality code.
      Trust me, if i ever have to do work in that part of the codebase, they will be broken down into smaller, testable functions.

    • @channel_channelson
      @channel_channelson Місяць тому

      You are lying

  • @jager0724
    @jager0724 Рік тому

    This is how I write clean code:
    1. As few curly braces as possible - luckily one-liners don't require braces, so if you have a one-liner if/while/for statement, no braces needed. Arrow functions can also sometimes be reduced to a single line with no need for the return keyword
    2. Functions are verbs, non-booleans are nouns, booleans are verb in 3rd person Sg. + description (e.g. hasItems, isAdult, didWin etc)
    3. Declarative with state
    4. Extractions are labelled deliberately such as utils & constants dir/file
    5. Pick one date type (Date or timestamp) and stick with it

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

    As a Haskell programmer: Functions should take an input and MUST return an output or other functions.
    Edit: And HAVE NO SIDE EFFECTS.

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

      No side effects

    • @BlackDragon-tf6rv
      @BlackDragon-tf6rv Рік тому

      I admire you guys

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

      Hmmm what do you think MVars and the C FFI introduce for performance critical code?
      SIDE EFFECTS!

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

      ​@@SimGuntherGo away 🙉🙉

    • @windows99
      @windows99 Рік тому

      What are side effects of a function?

  • @radiusbecka1799
    @radiusbecka1799 Місяць тому

    I don't understand anything but I'm beginning to obsess and do franticly do research just because it's fun. Thanks for infecting me with enthusiasm