Live data from Hacker News

Want cleaner code? Use the rule of six

davidamos.dev

121–130 of 352 posts

Re: Want cleaner code? Use the rule of six

#122
post #49
post #38

Earlier quoted context omitted.

Right?! That should instead be -len("foo") or -NUM_PREFIX_PARAMS

That doesn't improve anything in terms of knowing why the number is there.

len("foo") certainly does, and the global constant is a great place to put a comment, if the name isn't descriptive enough.

Re: Want cleaner code? Use the rule of six

#124

I don't necessarily agree with the step of putting the code in a separate function; that often works, but just as often makes it so that the code can't be read top-to-bottom anymore which hurts readability. In this case there's, I think, a better alternative; the equivalent-ish code in Ruby for the example code here would be something like this: values = s .partition('?')[-1] .split('&') .map { |key_value| key_value.…

[deleted]

Re: Want cleaner code? Use the rule of six

#125
post #112

This rewrite is more performant than the original: query_params = s.split('?')[1].split('&')[-3:] map(lambda x: x.split('=')[1], query_params) The calculation of query_params, having no dependency on the lambda parameters or anything being mutated, has been lifted out of the lambda, and thus spared from repeated execution by map. The compiler for that language won't do this automatically.

What? No it isn't! You didn't parse that correctly. The query params were never in the lambda to begin with. Python function calls have strict (not lazy) semantics, i.e. "applicative order", i.e. both expressions passed as arguments to map() are evaluated before the map body gets them as parameters, thus the query params would only be evaluated once, even when inlined as they were originally. Same with the lambda def…

Sorry; it looked to me like x.split('=')[1], query_params is a tuple being returned by the lambda. But of course that leaves map without the needed argument.

Re: Want cleaner code? Use the rule of six

#126
use statically typed programming languages. Favor composition over inheritance . Develop bottom-up (reusable classes) instead of large-scale up-front design. SOLID principles (SRP being the most important). The Bottom-up approach also favors Unittesting. Code reviews, clear code formatting rules (simple editor plugins do the trick). Use static code analyzers. IMHO this kind of object-oriented programming leads to NEW code being written to implement features and NOT old code being tampered with. Ideally, the (tested) units of code (classes) have such clear responsibility that you do not have to touch them once they are implemented. If Super-classes begin to emerge, refactor.

Re: Want cleaner code? Use the rule of six

#127
post #108

Reminded me of 'Object Calisthenics' by Jeff Bay. Basically an exercise for a toy project where you adhere to 9 rules: 1. Only One Level Of Indentation PerMethod 2. Don’t Use The ELSE Keyword 3. Wrap All Primitives And Strings 4. First Class Collections 5. One Dot Per Line 6. Don’t Abbreviate 7. Keep All Entities Small 8. No Classes With More Than Two InstanceVariables 9. No Getters/Setters/Properties https://william…

Oof, these all seem absurd to me.

> 1. Only One Level Of Indentation Per Method

One level of indentation just leads to an explosion of tiny one-use methods with weird names, and now you can't read the code linearly. You will almost certainly never reuse these tiny methods, especially since you're likely consigning them to an instance of a class instead of a free function, so all you've done is forced people to jump around a lot.

> 2. Don’t Use The ELSE Keyword

Not using the else statement just obscures the fact that there's a branch in the code. Obscuring something important seems to be the opposite of what you should do.

> 3. Wrap All Primitives And Strings

Ugh, that seems verbose and clunky, especially in a language like Java without operator overloading. I'm all for type aliases or typedef's, or, creating a class if the builtin primitives don't work (I think a Money class makes sense because you don't exactly want to use a float, for instance). But just putting wrappers all over the place sounds grotesque.

> 4. First Class Collections: Any class that contains a collection should contain no other member variables

Why even have a class then? Why not just have functions that operate on a collection? It's much more generic that way, since if you're using iterators or an abstract collection interface, you can potentially allow the user to choose the exact data structure, and you avoid the ceremony of creating a new type that's again just a wrapper.

> 5. One Dot Per Line... Basically, the rule says that you should not chain method calls.

This is the first one I roughly agree with, but I wouldn't consider it a hard rule. Chaining .map and .filter together for instance is a very common pattern.

> 6. Don’t Abbreviate

min/max is just as clear as minimum and maximum. I'm not using "index" in my for loop when "i" will do. "n" is perfectly well understood as a count of things. Abbreviations when used properly make code easier to read, not harder.

> 7. Keep All Entities Small... No class over 50 lines and no package over 10 files

Ok, assuming the problem can't be simplified, all you've done is now fractured all that functionality into tens/hundreds of files. How is that easier to follow? Sure, there's balance in all things, but I'd probably rather read a 1000 line class than 20 small files split over 2 packages.

> 8. No Classes With More Than Two Instance Variables... I thought people would yell at me while introducing this rule, but it didn’t happen

They were being polite. I'll do it for them. What the fuck?

The example he gives is also awful, where instead of using a string for name, he makes Name a type (ugh) with FirstName and LastName. Not only is that overly ceremonial, but it's wrong, there are plenty of names from various cultures that do not fit cleanly into FirstName and LastName. Also, what happens if he wants to store a MiddleName? That's three instance variables! Ohno! OR what if the person has like 10 middle names (this shit happens). Are we going to have 5 nested data types for that?

> 9. No Getters/Setters/Properties ... My favorite rule. It could be rephrased as Tell, don’t ask.

My brain feels like it's going to explode.

> It is okay to use accessors to get the state of an object, as long as you don’t use the result to make decisions outside the object.

Why else would you want to get the state of an object?

> Any decisions based entirely upon the state of one object should be made inside the object itself.

If your classes are 50 lines long, I guarantee you that other classes will be making decisions on other objects behalf.

> Then again, they violate the Open/Closed Principle.

I think the industry is largely realizing that this is a bad principle, as it implies inheritance. I think most people outside the enterprise java world now realize that using interfaces or free functions is largely better.

Re: Want cleaner code? Use the rule of six

#128
Split Into Multiples Lines has a real problem, which appears in the example code.

Let say you have a long code block that includes the revised snippet:

> query_params = s.split('?')[1].split('&')[-3:]

> mylist = map(lambda x: x.split('=')[1], query_params)

> ...

> ...

> (some more complex transformations, that only depends on mylist)

When you're reading the later stages of the code, you still have to maintain a memory of what "query_params" does, even though it's no longer relevant. That actually increases the burden on your working memory. The one-liner is more complex to understand initially, but it self-documents that the only info that is relevant to the downstream is the result of the map(...).

In general, the more variables that are declared in a code block, the more effort it is to understand, and the effect is probably superlinear with the number of variables. I'd say if you have to declare more than 5-6 variables, you should split into a separate function.

Re: Want cleaner code? Use the rule of six

#129

I don't necessarily agree with the step of putting the code in a separate function; that often works, but just as often makes it so that the code can't be read top-to-bottom anymore which hurts readability. In this case there's, I think, a better alternative; the equivalent-ish code in Ruby for the example code here would be something like this: values = s .partition('?')[-1] .split('&') .map { |key_value| key_value.…

Definitely a good point, refactoring is great and has a bunch of benefits but can also be overdone and create problems. I've heard/read Sandi Metz talk about this as "The Wrong Abstraction"[1].

The basic argument is that any time you do an extract refactor you're creating a new layer of abstraction that the next reader will have to learn and understand. This can also get worse over time as the abstractions drift away from their original purpose.

The solution she provides is to be okay with a little bit of duplication, then as patterns naturally arise in the codebase you can refactor when you know a few use cases and can clearly define the concept.

[1]: https://sandimetz.com/blog/2016/1/20/the-wrong-abstraction

Re: Want cleaner code? Use the rule of six

#130

use statically typed programming languages. Favor composition over inheritance . Develop bottom-up (reusable classes) instead of large-scale up-front design. SOLID principles (SRP being the most important). The Bottom-up approach also favors Unittesting. Code reviews, clear code formatting rules (simple editor plugins do the trick). Use static code analyzers. IMHO this kind of object-oriented programming leads to NEW…

[deleted]
Post reply on HN