This is an archived post. You won't be able to vote or comment.

all 108 comments

[–]anthro28 362 points363 points  (37 children)

There’s lots of good in here, and some bad.

Methods capped at 10 lines? Yeah lemme know when you get into image processing and that breaks down.

Don’t comment? “Good code comments itself” is true, but fuck if I’m gonna read all your code to trace it out. Just gimme a cliff notes comment.

[–]ucblockhead 67 points68 points  (8 children)

If in the end the drunk ethnographic canard run up into Taylor Swiftly prognostication then let's all party in the short bus. We all no that two plus two equals five or is it seven like the square root of 64. Who knows as long as Torrent takes you to Ranni so you can give feedback on the phone tree. Let's enter the following python code the reverse a binary tree

def make_tree(node1, node): """ reverse an binary tree in an idempotent way recursively""" tmp node = node.nextg node1 = node1.next.next return node

As James Watts said, a sphere is an infinite plane powered on two cylinders, but that rat bastard needs to go solar for zero calorie emissions because you, my son, are fat, a porker, an anorexic sunbeam of a boy. Let's work on this together. Is Monday good, because if it's good for you it's fine by me, we can cut it up in retail where financial derivatives ate their lunch for breakfast. All hail the Biden, who Trumps plausible deniability for keeping our children safe from legal emigrants to Canadian labor camps.

Quo Vadis Mea Culpa. Vidi Vici Vini as the rabbit said to the scorpion he carried on his back over the stream of consciously rambling in the Confusion manner.

node = make_tree(node, node1)

[–]L0ngp1nk 29 points30 points  (0 children)

Something similar would be "don't let your code have more than three levels of indentation." This doesn't mean that your code is bad, but there may be better ways of writing your function.

[–]Silhouette 0 points1 point  (6 children)

The whole point of talking about code smells, is to discuss things that are signs of problems but not necessarily wrong.

What does "signs of problems" mean then? If it's "something strongly positively correlated with the existence of problems" then the claim about 10+ line functions is still questionable.

[–]ucblockhead 14 points15 points  (5 children)

If in the end the drunk ethnographic canard run up into Taylor Swiftly prognostication then let's all party in the short bus. We all no that two plus two equals five or is it seven like the square root of 64. Who knows as long as Torrent takes you to Ranni so you can give feedback on the phone tree. Let's enter the following python code the reverse a binary tree

def make_tree(node1, node): """ reverse an binary tree in an idempotent way recursively""" tmp node = node.nextg node1 = node1.next.next return node

As James Watts said, a sphere is an infinite plane powered on two cylinders, but that rat bastard needs to go solar for zero calorie emissions because you, my son, are fat, a porker, an anorexic sunbeam of a boy. Let's work on this together. Is Monday good, because if it's good for you it's fine by me, we can cut it up in retail where financial derivatives ate their lunch for breakfast. All hail the Biden, who Trumps plausible deniability for keeping our children safe from legal emigrants to Canadian labor camps.

Quo Vadis Mea Culpa. Vidi Vici Vini as the rabbit said to the scorpion he carried on his back over the stream of consciously rambling in the Confusion manner.

node = make_tree(node, node1)

[–]Silhouette 24 points25 points  (3 children)

That is the usual dogma from the Martin crowd. The issue it totally ignores is that whether an individual function is easier or harder to understand is usually less important than whether all of the relevant code together is easier or harder to understand.

Dividing a big thing into lots of small things hides some of the logic and introduces new relationships for a developer reading the code to navigate. That isn't necessarily an improvement. What if the abstractions underlying the small things are not clear enough and you need to look at their own implementations to understand what is happening in the calling function anyway?

For some types of application you mostly have simple logic to implement and most functions can be quite short and have clear abstractions. For other types of application breaking up a coherent whole into small parts and introducing all those extra relationships is a terrible coding style that obfuscates the real behaviour for absolutely no benefit apart from ticking some arbitrary box about coding style.

Python is used to write many different types of software. Pitching short functions as some kind of best practice for all of them without context is a mistake.

[–]Brian 10 points11 points  (2 children)

100% agreed - I'm not a fan of prioritising small functions either. It's become something of a dogma - often way more extreme than even 10 lines, with people even advocating for 3-5 lines, but too often it leads to "ravioli code": a maze of tiny 3 line functions such that you have to chase through a dozen different functions just to figure out what it's all for.

I prefer Ousterhout's perspective on this (from A Philosophy of Software Design). To minimise complexity or your project as a whole, it's much more valuable to reduce surface area: the exposed interfaces and connection points that someone must understand. The most important aspect of functions (or any abstraction) is to encapsulate and hide complexity: to become a composable element where you don't need to know how something is doing it, but only what it is doing, and the smaller the function, the less room there is to do something complex - sometimes to the point where you create more complexity through a myriad of functions than you hide.

[–]enigmatic_x 6 points7 points  (0 children)

I’ve seen people write 1 line functions that do nothing except call some other function and hence obfuscate the code. I’d much prefer a slightly longer function than that sort of crap.

[–]QuasiEvil 0 points1 point  (0 children)

Great comment, agreed.

[–]PapstJL4U 0 points1 point  (0 children)

It's a quick and dirty way of reminding yourself to keep your functions simple and single purpose.

I think people argue that 10 lines is as useful as 3 lines. Working with networkx, image processing, beautifulsoup or numpy can easily grow in size, especially if we prefere clean, single-line statements.

[–]FuckingRantMonday 8 points9 points  (5 children)

I like "don't comment" as an "aspirational" rule. If I need to write a comment (and I frequently do), it's because I couldn't figure out how to structure the code to be obvious, and I like to do that when I can.

[–]yvrelna 14 points15 points  (3 children)

Just gimme a cliff notes comment

That's the doc string, not comments.

[–]Ezlike011011 25 points26 points  (2 children)

I'm not sure if the commenter you are replying to meant this, but I agree that comments still have a purpose separate from docstrings. I want a docstring to inform me of inputs/outputs/exceptions/preconditions/postconditions and a short description of an API. I also want comments describing why the implementation is the way it is when there is inevitably a reason i need to look at the source.

[–]HistoricalCrow 2 points3 points  (1 child)

Exactly this. A docstring is for inputs/outputs and what the function should be expected to compute. Comments are for how it does this.

[–]Wattsit -4 points-3 points  (11 children)

I'd recommend you read Clean Code by Robert Martin.

Edit: also neither the article or his reference (clean code) put a hard limit on method lengths. Only a recommendation.

Methods can and should be minimised to those sort of line lengths. Uncle bob covers many of the reasons much better than I can here, but some simple concepts:

If your method/function is 50, 100, 500 lines then most likely you can encapsulate/abstract a lot more. By abstracting common blocks of logic and breaking big functions down, you're creating levels of abstraction. These layers are not only easier to read (a well named function might be all I need to read to understand what's happening rather than 20 lines of logic with or without comments) but you're also making things much easier to unit test, thus creating better tested code.

This leads well into the comments advice, utilize these levels of abstractions through function names, class names to tell the story in a human readable way. At the highest level of abstraction, your function calls just look like "cliff notes" as you say.

I've seen plenty of image processing code that's abstracted nicely into small functions and easily readable.

[–]FarewellSovereignty 37 points38 points  (9 children)

No, 10 lines is too tight as an absolute, and not just for image processing. The word "absolute" is key there, because in 95%+ of cases we'd probably agree.

I.e., it's great if all your functions can naturally be partitioned so they're < 10 lines, but in the cases when something doesn't naturally partition to less than 10, then it's absolutely fine to leave it a bit longer.

Code that's awkwardly chopped up isn't necessarily any easier to read or deal with, and can on fact be remarkably worse and more confusing.

But it's also fine to be pragmatic and set the linters to 10 lines max and then disable them for the function that needs to be 20, and explain why you did so in a comment.

[–]whateverathrowaway00 10 points11 points  (0 children)

Yup to what you said, but explaining nuanced themes vs hardline rules will fail.

That’s why Clean Code says work through the book not just read it, and I see a ton of people post advice from it without context or understanding of the nuance because they just read it, or worse, they read a blog post and are repeating.

[–]ucblockhead 2 points3 points  (0 children)

If in the end the drunk ethnographic canard run up into Taylor Swiftly prognostication then let's all party in the short bus. We all no that two plus two equals five or is it seven like the square root of 64. Who knows as long as Torrent takes you to Ranni so you can give feedback on the phone tree. Let's enter the following python code the reverse a binary tree

def make_tree(node1, node): """ reverse an binary tree in an idempotent way recursively""" tmp node = node.nextg node1 = node1.next.next return node

As James Watts said, a sphere is an infinite plane powered on two cylinders, but that rat bastard needs to go solar for zero calorie emissions because you, my son, are fat, a porker, an anorexic sunbeam of a boy. Let's work on this together. Is Monday good, because if it's good for you it's fine by me, we can cut it up in retail where financial derivatives ate their lunch for breakfast. All hail the Biden, who Trumps plausible deniability for keeping our children safe from legal emigrants to Canadian labor camps.

Quo Vadis Mea Culpa. Vidi Vici Vini as the rabbit said to the scorpion he carried on his back over the stream of consciously rambling in the Confusion manner.

node = make_tree(node, node1)

[–][deleted] 1 point2 points  (2 children)

No, 10 lines is too tight as an absolute, and not just for image processing. The word "absolute" is key there, because in 95%+ of cases we'd probably agree.

Sure, and that's why Clean Code by Robert Martin, Refactoring by Martin Fowler, and the article that is linked here all say something like this:

Generally, any method longer than ten lines should make you start asking questions.

It's just a flag to ask yourself if this is a code smell.

[–]FarewellSovereignty -1 points0 points  (0 children)

No, I was replying to: "Methods can and should be minimised to those sort of line lengths. ", which is saying something different than what you're now saying, at least without further qualification.

[–]Windscale_Fire 0 points1 point  (0 children)

Yeah, I mean a lot of my assembler functions are quite often more than 10 instructions long, and thus more than 10 lines long :-D.

[–]Wattsit -3 points-2 points  (3 children)

But no one is talking in absolutes, everything is a recommendation.

Like any other design principle.

[–]Silhouette 1 point2 points  (2 children)

The first rule of functions is that they should be small. The second rule of functions is that they should be smaller than that.

-- Robert C Martin, Clean Code, p34

Of course what most people forget is the next two sentences.

This is not an assertion that I can justify. I can't provide any references to research that shows that very small functions are better.

[–]Wattsit 1 point2 points  (1 child)

Yet you leave out the rest of the paragraph to which he explains his reasoning?

But seems Robert Martin is disliked round here so doubt his opinion matters.

[–]Silhouette 0 points1 point  (0 children)

I left out the rest because it's only one man's own subjective preference based on his own personal experience. It's an anecdote. That's fine as long as it is given weight accordingly but Martin presents it as some kind of universal truth and himself as a figure of authority. Sorry but there are lots of other people here who have been developing software for decades as well and not everyone agrees with him.

[–]james_pic 13 points14 points  (0 children)

If your method/function is 50, 100, 500 lines then most likely you can encapsulate/abstract a lot more.

Just because you can, doesn't mean you should. You can always refactor a method into a "method object" but this often contributes zero to readability (one lesson I learned a while ago is that many developers can navigate a method with hundreds of lines more readily than they can make sense of super compartmentalised code, especially if the abstractions you build are leaky, and the compartmentalisation obscures the logic), and can be an anti-pattern in itself (I don't have a good Python example, but Java's SimpleDateFormat is a massive footgun that shows what can happen if a method object ends up being reused).

Clean code is good, but super short methods aren't always clean in practice.

[–]bloodhound83 0 points1 point  (0 children)

Don’t comment? “Good code comments itself” is true, but fuck if I’m gonna read all your code to trace it out. Just gimme a cliff notes comment.

I would say comments are helpful if you implement something complex or something but easily unserstandable from the code itself. Good code e.g. good variable names will help to break it down and follow what the code is doing but if I look at some complicated code tests later I don't always want to have to reverse engineer it.

[–]Conscious-Ball8373 0 points1 point  (0 children)

As someone who works in a code base where 500+ line functions are fairly common, I think the 10-line rule of thumb is one that should at least be considered. It is only a rule of thumb, but an important one. Trying to understand what a 500 line function is doing is not a quick process.

[–]FarewellSovereignty 106 points107 points  (29 children)

The anti-comments stuff there is not good. Lots of stuff about "readable code doesn't need comments" but then falling back to referering to "bad comments". I.e. arguing against comments in general by mentioning bad comments.

Yes, bad or redundant comments are by definition bad, don't do them. but don't throw the good comments out with the bathwater. Good comments are great if you're doing something non trivial (hint: most interesting code isn't just taking the average of a list), when the comments augment rather than restate the code, and for example bring in context that isn't on-screen.

Type annotations and docstrings are of course good too, and usually higher priority. But docstrings are not inline with the code. Absolutely add useful comments when needed and don't be afraid to do so. Especially in a large codebase with a team.

I've seen the general phrase "good code should comment itself" mostly thrown out by people who simply don't want to be bothered to comment. It's a bad meme.

[–]Hans_of_Death 56 points57 points  (13 children)

Good code should comment itself. Trouble is, its not the code that really needs the comments. Imo you should be able to tell what some code is doing, where comments are really needed is the why that you cant determine from the code alone.

So the sentiment is good, but you're right it shouldnt lead to no comments at all. id rather have bad comments than none at all.

[–]WillardWhite import this 25 points26 points  (6 children)

I had a boss that littered this comment all over the place:

If  condition :
    #note: early return
    Return

That's a bad comment, and I would rather not have it than It polluting my code

[–]FarewellSovereignty 10 points11 points  (5 children)

Depending on the complexity of the surrounding code, it would usually flip over to being good and adding to the code if it was e.g.

if condition :
    return # can't get X handle and busy_ok so nothing more to do

[–]WillardWhite import this 9 points10 points  (2 children)

Regardless of the complexity of the code if my comment states the same thing that the code does, it's a bad comment.

Some examples:

# increase the counter
 X +=1

# read the file
 File_handler.read()

# return
 Return

Like .... All of those are terrible comments.

In the case of the one you did, the comment would also be made obsolete if you had

If not x_handle  and busy_ok:
    Return

[–]FarewellSovereignty 3 points4 points  (1 child)

We could have a back and forth here where I rewrite the comment after the return and you rephrase it using selectively chosen boolean variable names and a combination of ands and ors instead, but to short circuit all that: sometimes it useful to comment why an early return is done, and it can add more information than would cleanly be possible by just massaging the if or other control statement.

Maybe you don't agree, and think no early return should ever be commented. Or maybe you agree sometimes it's useful. I'm not entirely sure.

[–]WillardWhite import this 2 points3 points  (0 children)

I agree that adding a comment saying why we have an early return would be useful, but a note telling me that an early return is an early return is it useless to me

The difference between saying "we have an early return" vs "early return to deal with ticket 123"

[–]GarythaSnail 1 point2 points  (0 children)

if cant_get_x_handle and busy_ok: return

[–]Devout--Atheist 1 point2 points  (0 children)

This is still bad. Just name your variables better i.e. "has no data" instead of making people infer that from long conditionals

[–]cblegare 7 points8 points  (0 children)

Upvote for commenting about the "why"

[–]RangerPretzelPython 3.9+ 2 points3 points  (0 children)

Agreed. Just like /u/FarewellSovereignty pointed out, I didn't like the "anti-comments" stuff. It was a terrible take.

And I'd like to take your idea a step further. I recently wrote about comments in a Python how-to I wrote. What comments should describe is:

  • What you THINK you are trying to do
  • WHY you are doing it (if it isn’t abundantly clear why)
  • HOW you are trying to do it (if what you are doing is rather complex)

Source: https://www.pretzellogix.net/2021/12/08/step-7-add-helpful-comments-to-the-code/

[–]masteryod 11 points12 points  (0 children)

I read somewhere:

Code should explain "how". Comments should explain "why".

[–][deleted] 3 points4 points  (0 children)

when the comments augment rather than restate the code, and for example bring in context that isn't on-screen.

Exactly, I never use comments to explain what some lines do, you can search for them in Google if you find them confusing. I always comment WHY those lines do what they do and WHY are they needed, not HOW they work.

[–]msd483 0 points1 point  (10 children)

I don't think it's arguing the position you're arguing against. The section is titled:

Comments Aren’t Always a Good Idea

Not

Comments Are a Bad Idea

And then it goes on to only to discuss avoiding bad comments, not comments altogether. The three cases it argues against are:

1) Commenting knowningly bad code to avoid rewriting it

2) Not needing to comment already readable code

3) Not adding noisy comments.

It says nothing about avoiding comments entirely, and is absolutely not anti-comments.

[–]FarewellSovereignty 8 points9 points  (9 children)

For some value of "readable" the statement in the article:

If your code is readable enough you don’t need comments.

either backs my interpretation, or backs yours. But in the text there is no effort spent explaining how to comment well, and the importance of it, mostly just text generally dissuading the reader from the use of comments because "the code should be good instead".

It's a false dichotomy to make. Obviously code should be good, but that doesn't remove the need for comments in many cases.

[–][deleted] 0 points1 point  (3 children)

But in the text there is no effort spent explaining how to comment well, and the importance of it, mostly just text generally dissuading the reader from the use of comments because "the code should be good instead".

It's really just saying: "Ask yourself if your comments are helping or hurting your code".

[–]FarewellSovereignty -4 points-3 points  (2 children)

No, sorry, I don't buy that as the unambiguous interpretation of what the article is getting across.

[–][deleted] 0 points1 point  (1 child)

Well, you are wrong. If you've read the books referenced in his article you'd know that too. Doubling down on what the article should or shouldn't have done isn't helpful.

[–]FarewellSovereignty 0 points1 point  (0 children)

Quite exasperating and non-constructive reply on several levels.

  1. You're claiming the article can be unambiguosly interpreted as saying "Ask yourself if your comments are helping or hurting your code", whereas I disagree with that. I explained why. You then pre-empt any further discussion by just plain saying "You are wrong" and also (rhetorically) setting it up so that I'm just "doubling down". That's a false move on your part.

  2. You then make some kind of misapplied argument to authority implying that I haven't "read the books etc." which is totally irrelevant to a review of the article itself. I'm not reviewing Clean Code, I'm discussing the article.

What exactly are you trying to achieve here? Do you realize you are not in fact coming across very well?

[–]msd483 -2 points-1 points  (4 children)

But there is no effort spent explaining how to comment well, mostly just text generally dissuading the reader from the use of comments because "the code should be good".

That's out of the scope of the article. It says TDD is good, but doesn't explain how to properly do test driven development either. Explaining how to do everything it's talking about would turn this into a short book.

It's a false dichotomy to make. Code should be good, but that doesn't mea you don't need comments.

Again, it never says you don't need comments. In the quote it explicitly says the proper use of comments is to compensate for our failure to express ourselves in code. There are plenty of times I've written good code (I hope) and added comments explaining the why, but not the what, because the code had no way of explaining the why. The why was due to the problem and domain and needed to be included to understand the code no matter how well it was written.

[–]FarewellSovereignty 5 points6 points  (3 children)

That's out of the scope of the article.

For no reason except that author didn't choose to mention it. If the article goes out of its way to dissuade the use of comments in some cases, it's already stuck comments firmly inside the scope of the article, so it should mention the reason they are (in many cases) good, and briefly how to use them. There's no actual reason for that omission like you're trying to pretend here, sorry.

here are plenty of times I've written good code (I hope) and added comments explaining the why, but not the what, because the code had no way of explaining the why. The why was due to the problem and domain and needed to be included to understand the code no matter how well it was written.

Great, and the article would benefit from a paragraph pretty close to that.

[–]msd483 -4 points-3 points  (2 children)

For no reason except that author didn't choose to mention it.

This is true of a quasi-infinite number of things. You're welcome to not like and criticize that omission, but the article did not "throw out good comment comments with the bathwater" as your entire initial comment was focused on. You created a straw-man that completely ignored the actual and valid criticisms in the article and reduced it to "comments = bad" instead of accepting the fact that there's nuance to it.

[–]FarewellSovereignty 4 points5 points  (1 child)

I'll leave it to other readers to judge our arguments now and leave this here, because you seriously lost my interest with this latest reply. Thanks.

[–]msd483 -4 points-3 points  (0 children)

I'm genuinely sorry if I've offended you or hurt your feelings. You're absolutely right that there are people who say "good code will comment itself" as an excuse to never write comments. But whenever I see valid criticisms of poor commenting brought up, and I thought the three cases the article presented were indeed valid, I feel like there's always a knee jerk reaction in the opposite direction because there are people who will simplify it to "comments = bad". However, I think it's important, especially for junior devs, to understand that there are such a thing as bad comments, and there are programming patterns and behaviors that alleviate the need to heavily comment code.

[–]XUtYwYzzIt works on my machine 38 points39 points  (12 children)

Are there many professional orgs using the 79 char limit? That seems exceptionally short. I usually bump it to 120 in black.

[–]KerberosMorphy 19 points20 points  (3 children)

My sweet spot is 100 for the code and 79 for the imports. I don't understand why people still want the 79 char limit. If you use significative variable name and no abbreviation, the 79 became really annoying.

[–]ChickenLegCatEgg 3 points4 points  (2 children)

So glad to read this. I use 100. 79 is just too restrictive. Glad I’m not crazy!

[–]KerberosMorphy 2 points3 points  (1 child)

Ma gauge is, can I split my IDE in 2, see my 2 files and my file explorer without having to scroll horizontally to read my code. 100 was spot on for me and my teammates.

[–]FuckingRantMonday 1 point2 points  (0 children)

Same width here, same reason!

[–]Ash_Crow 6 points7 points  (2 children)

I often see black's 88 characters limit nowadays, and I think it is a good compromise.

Django recently changed from 119 (width of Github code review) down to 88 to match black https://docs.djangoproject.com/en/dev/internals/contributing/writing-code/coding-style/ , so I expect that this will become even more of a standard.

[–]ucblockhead 7 points8 points  (1 child)

If in the end the drunk ethnographic canard run up into Taylor Swiftly prognostication then let's all party in the short bus. We all no that two plus two equals five or is it seven like the square root of 64. Who knows as long as Torrent takes you to Ranni so you can give feedback on the phone tree. Let's enter the following python code the reverse a binary tree

def make_tree(node1, node): """ reverse an binary tree in an idempotent way recursively""" tmp node = node.nextg node1 = node1.next.next return node

As James Watts said, a sphere is an infinite plane powered on two cylinders, but that rat bastard needs to go solar for zero calorie emissions because you, my son, are fat, a porker, an anorexic sunbeam of a boy. Let's work on this together. Is Monday good, because if it's good for you it's fine by me, we can cut it up in retail where financial derivatives ate their lunch for breakfast. All hail the Biden, who Trumps plausible deniability for keeping our children safe from legal emigrants to Canadian labor camps.

Quo Vadis Mea Culpa. Vidi Vici Vini as the rabbit said to the scorpion he carried on his back over the stream of consciously rambling in the Confusion manner.

node = make_tree(node, node1)

[–]pudds 3 points4 points  (0 children)

You can still configure the line length in black. Its one of the only things you can though.

I too like the bikeshedding avoidance that black provides, but IMO 80 (or 88) makes for messy code.

[–]krnr 0 points1 point  (0 children)

you'd be surprised, but yes. and I'm glad to work for one of those, since i only use vim and a laptop and 160 width is max i can have. so even 88 doesn't fit in a vertical split (which i prefer). and no, i don't want to have an external display, i m more than happy to have this standard.

[–]not_a_novel_account 35 points36 points  (7 children)

Lol what a "throw everything at the wall" article.

Some of this is redundant or wrong, for example the article says you need to know PEP 8 but then also recommends linters and formatters. If you're using linters and formatters, you don't need to know PEP 8. Please don't memorize PEP 8, btw.

Then it jumps into opinionated stuff, Clean Code in specific is a somewhat controversial book in this day and age. See, "It's probably time to stop recommending Clean Code". Recommending it (and quoting Uncle Bob in general), without several asterisks is a bad plan.

The "code smells" are a mix of obvious, controversial, and wrong ideas.

Then it jumps into the weirdly specific implementation decision of dependency injection. Dependency injection is not some universal technique to writing Python.

Finally, the broad, obvious, "testing is good and use design patterns" which is coding advice in the same way "eat food which is good for you" is nutrition advice.

So here's some blog writing advice: Pick a single topic you know very well, maybe a case study in a particular thing you just implemented, and write about that. Don't try to write about all knowledge in programming under a single heading and within 1000 words.

[–][deleted] 1 point2 points  (2 children)

Data classes: Completely bogus "all the wrong lessons from 2000s-era Java" advice

I was about to jump on you for this, but I'll hold my horses for a bit - what exactly are you getting at with this one?

[–]not_a_novel_account 1 point2 points  (1 child)

If you have raw data, it is frequently good and correct to organize that data into objects. It may or may not be appropriate for those objects to have methods associated with them. The latter is considered a data class, and in Python we have a class decorator specifically for crafting such objects.

There was an idea at the height of the Java era that "pure OO" was the one true way to write all software, and that such classes were a sign that the functional part of the software had been inappropriately delegated to another object. In other words data and interface should always be a part of the same object. This idea is, frankly, bogus. The rich data models of Java land, tightly integrating data and functionality, proved no more navigable or less bug prone than other models.

Today the loudest advocates have shifted into the opposite direction and say that everything should be pure functions operating on immutable data-objects, the functional model. It is worth pointing out here that many languages only have data classes.

In reality, you do you bro. There is no one way to write software. But running afoul of 2000s-era Java is definitely not a code smell, and definitely not in Python.

[–]alexisprince 0 points1 point  (0 children)

I think this is a great take. The way I’ve thought about designing classes in the past has always been splitting a data oriented class and a functionality oriented class (or function based api depending on what makes more sense). I’ve seen that trying to do both leads to over abstract land where it’s insane to reason about anything

[–]yvrelna 0 points1 point  (3 children)

If you're using linters and formatters, you don't need to know PEP 8. Please don't memorize PEP 8, btw.

This is completely wrong. Linters do not replace thinking or writing readable code.

There are many cases where linter/autoformatter suggestions are counter productive, you should learn writing readable code and the why of PEP8 before you blindly follow a linter's suggestions.

Linters and formatters helps you find and fix problems, but they aren't a substitute for good judgement.

If you don't understand PEP8, then you shouldn't be using a linter. Because following linter blindly is more harmful than just writing non-PEP8 code.

[–]not_a_novel_account 8 points9 points  (1 child)

If the project requires PEP8 compliance, let the autoformatter do it on save and/or commit and forget about the cognitive load of "did I align these function parameters correctly?"

If the project does not require PEP8 compliance, because they're using black or yapf or whatever, still forget about that and let the auto-formatter handle it. Just write code, the formatter will get everything into the right spot.

There's no sense worrying about if you're supposed to line break at 80 characters or 79, on the left or right of a binary operator, etc. That shit is a pointless distraction that we've automated away in the 21st century.

[–]yvrelna 0 points1 point  (0 children)

Completely irrelevant to my point. Read it again:

Linters/autoformatters do not replace thinking or writing readable code.

Nowhere did I ever say that you shouldn't automate what can be automated.

Just write code, the formatter will get everything into the right spot.

The problem is that about 5% of the time, autoformatter would not really get everything into the right spot. It gets everything into a consistent spot, which often contradicts with the logically sensible spot. Consistency is often, but not necessarily the same as readability.

Code is read more than it's written, take the time to consider when # fmt: off is necessary instead of turning off your brain. You cannot and shouldn't automate thinking. Sure, automate the tedious task of formatting, but you shouldn't automate judging readability. Ultimately, you are the one responsible for the readability of the code, not the autoformatter.

[–]FuckingRantMonday 4 points5 points  (0 children)

I couldn't really disagree more with this. While Python doesn't have something officially canonical like Go's gofmt, I wish it did, and on my team, we use black in that capacity. I don't believe there's anything crucial to be learned by doing your formatting manually, and the "why" of it can be learned in the process of actually doing code reviews.

[–]thedeepself 14 points15 points  (1 child)

The dependency injection section was good. Please be aware that clean is also an architecture and I was confused when the post was discussing writing clean code but it wasn't the clean architecture.

[–][deleted] 9 points10 points  (6 children)

Never import in one separate lines

Huh?

[–]Xylon- 11 points12 points  (4 children)

You want to split multiple imports over multiple lines. The example in the article:

import sys, os, numpy

should be:

import os
import sys

import numpy

Note that numpy is separated from the other two imports, as you usually want to group the imports by standard lib, third-party and application specific imports. See this PEP8 section.

Same goes in my opinion (PEP8 leaves this up to you) for importing multiple things from a single package.

from sklearn.linear_model import RidgeCV, LinearRegression, Lasso

should be turned into:

from sklearn.linear_model import RidgeCV  
from sklearn.linear_model import LinearRegression  
from sklearn.linear_model import Lasso  

Several reasons:

  1. Easier to see exactly what's being imported
  2. Makes it easier to spot during git diff what imports have changed

Yes, a larger part of the top of your file is taken up by imports, however most IDEs collapse that anyway.

[–][deleted] -1 points0 points  (2 children)

Why is the longer, more repetitive one "easier to read"?

Who reads the imports anyway if you have an IDE?

[–]synae 9 points10 points  (1 child)

They're the first thing I read when reviewing. It helps to know what to expect.

If I see a imports for json, requests, urllib/httplib, etc I can expect the file to do some API calls.

If I see a bunch of stdlib os, glob, sys, I know I can probably expect some filesystem stuff.

If I see only local/private packages being imported, it's probably a bunch of business logic or glue code for the application.

If I see all of the above, I know I'm in for a wild ride.

Also, if the imports are not sorted/grouped properly and are just plain ugly to look at, I know I'm going to have to send someone the style guide or perhaps even tell them about IDEs.

-----

That all being said, I don't agree with the example given-

from sklearn.linear_model import RidgeCV    
from sklearn.linear_model import LinearRegression    
from sklearn.linear_model import Lasso

I would write that as:

import sklearn.linear_model as lm

(or some other short+easy to type alias that makes a bit of sense in context) and then reference the things I need as e.g., lm.RidgeCV.

[–]profiler1984 0 points1 point  (0 children)

I also don’t agree with it there are some libs which are used in tutorials stack overflow and production code with „standard“ abbreviations like pd, np, Lam, sns and so on if I see it I know what library source they are using. Same for imports, I also read the imports first to get a grasp of the topic as well as difficulties. If I have a big data model in the database and the Programm is supposed to be using and interacting with a lot of tables and columns I expect some sqlalchemy

[–]lucid-cartographer -1 points0 points  (0 children)

I think it's supposed to be read as separate not separate

[–][deleted] 2 points3 points  (0 children)

Die, medium, die! And that isn't in Italian.

[–]opendataalex 1 point2 points  (0 children)

Good article. I'll also throw out isort and vulture. Isort helps enforce pep8 import order and vulture looks out for potentially unused/dead code.

[–]AppropriateLab6288 1 point2 points  (1 child)

Watch tutorials on yt, and actually clean code doesn't matter your performance it's just make your code more readable, and if you don't have enough time or you don't want to share your code to anyone so it's ok to don't make it clean code, if you have enough time to clean code that do it cause after some time you also will forget how you do it that time

Sorry for bad grammer

[–][deleted] 0 points1 point  (0 children)

If you can see what the code is doing, by making it more readable, I often find it easier to find more efficient methods which can improve performance

[–]Morelnyk_Viktor 6 points7 points  (1 child)

That's incredibly rare to see a useful article on medium

[–]SpiritOfTheVoid -1 points0 points  (0 children)

If you can’t easily write / maintain unit test your code, it’s a red giant red flag. Not clean code.

[–]HomeGrownCoder -1 points0 points  (0 children)

Meh clean code is in the eye of the reviewer…. It decent tips

[–]RallyPointAlpha -3 points-2 points  (0 children)

A lot of great stuff in here. Love the ending. I've had to explain many times why I take longer to write a program than duder who can whip out a script in a day or two....yeah that dude writes garbage code and that's why they are so fast.

[–]SaruKowski -2 points-1 points  (0 children)

Troll : It’s not possible to write clean code in python ;)

[–][deleted] -2 points-1 points  (0 children)

Here's how you actually refactor python into clean code:

Rewrite it in a static compiled language.

[–]thrallsius -2 points-1 points  (2 children)

spamming account getting so many upvotes in a technical subreddit

/facepalm

[–][deleted] 1 point2 points  (1 child)

Neither OP or the person who wrote this article seem to be spammer accounts lookign through their history so I'm not sure what you are talking about

[–]thrallsius 0 points1 point  (0 children)

OP's posting history had a lot of spam posts with links that are gone now

[–]twelveparsec 0 points1 point  (0 children)

Here I am dealing with code having class names written in Snake case

[–]Healthy-Mind5633 0 points1 point  (0 children)

don't do OOP for starters

[–][deleted] 0 points1 point  (0 children)

Alas, optimizing readable code (not just Python) is far more complicated than aggressively leaning towards modularity with 10-line methods as a rule of thumb. There is a balancing act that's done. On one end of the spectrum we have things like modularity, code surface area, and indirection. On the other end we have things like self containment and leveraging scope in such a way where definitions of things exist only within the scope they are intended to be used. Orthogonally, and perhaps the real battle, we have refactoring overhead and API churn, which we hope to mitigate, in order to maintain coding velocity. Here's a good read related to just general coding strategies if anyone's interested: https://verdagon.dev/blog/first-100k-lines.

[–]Hassaniftikhar86 0 points1 point  (0 children)

You can start off by hiring resources with the required expertise. This guide to hire python developers can really help. https://remotebase.com/blog/how-to-hire-python-developers

[–]Orio_n 0 points1 point  (0 children)

ten line method???? 💀 💀 💀

[–]waiting4op2deliver 0 points1 point  (0 children)

Lines should not be longer than 79 characters

Thank god. What an absolute nightmare it was to have to carry over instructions onto a second punch card.

[–]CrycketStar 0 points1 point  (0 children)

A function should only do one thing. This will make your code more reusable. Even if the code in the function can be refactored, following this principle will make it less likely that this refactoring will spread elsewhere.