Live data from Hacker News

Why most “clever” code ain’t so clever after all

drive.google.com

51–60 of 104 posts

Re: Why most “clever” code ain’t so clever after all

#51
post #16

I run a small dev company. This is the first lessons we teach our programmers. If your code cant be understood by someone else with minimal efforts it is not good enough.

There's a cost to that too, unfortunately. Longer code may be easier to unserstand line by line, but the sheer volume of lines can make it harder to comprehend. Terseness has its advantages. Usually, making good developers write code for less experienced developers makes the code quality worse. OTOH, it can then be maintained by entry-level developers.

> Terseness has its advantages.

I'd argue there's a difference between being concise and being terse. I think that's what's at the heart of beautiful code: It expresses its ideas in a very simple, concise manner, without sacrificing readability. ("As simple as possible, but not simpler")

Re: Why most “clever” code ain’t so clever after all

#52

Earlier quoted context omitted.

My rule of thumb is that I attempt to write code that a junior programmer whose experience is limited to a little more than having taken a course in the language and has done a couple tutorials on the framework(s) can maintain. I see so many developers try to squeeze every new language feature or loads of esoteric library use cases into their code because they learned something and feel like it MUST belong in the pro…

For all of Java's pitfalls, this is one of the things it really has going for it. The language itself is extremely simple. I think adding properties instead of the weirdness of getters and setters would take it to peak simplicity and straight-forwardness. (Also, maybe eliminate inheritance and force interfaces and composition instead.)

> eliminate inheritance

Why would you want that? Wouldn't eliminating inheritance add a lot of boilerplate code?

Re: Why most “clever” code ain’t so clever after all

#53
post #9

Earlier quoted context omitted.

Do you maintain a high-enough level within the team though? Most "clever code" I've seen is called clever by people who are not yet proficient enough in a language to understand it. So with unskilled programmers pretty much anything that isn't straight combination of classes, loops and conditionals will be considered clever. There's a tradeoff here - I get the business reasons why one may want to have the codebase at…

> Most "clever code" I've seen is called clever by people who are not yet proficient enough in a language to understand it. My interpretation is the opposite. I call code "clever" after I've understood it. I agree its not universal, but in all the cases I've seen it used so far, its been another way to say "This could have been written in a simpler, more readable manner. And it should have been."

Ockham's Law of Programming: the simplest solution which solves the problem is the best solution.

Re: Why most “clever” code ain’t so clever after all

#54
post #11

Some like to say that you should never write clever code. But clever to who? Some people lambdas, map, reduce, and even polymorphism are clever. So in a vacuum the statement is meaningless. Whenever you're writing code you need to know your audience. Is the Haskell solution really that clever to someone who uses Haskell on a daily basis? That said, I always liked the saying: it's easier to write code than read it. Wh…

My measuring stick for "cleverness" has two axes.

The first axis is how far away you are from the naive solution(s). The further away you are, the longer it takes someone else to understand what you're doing. In some cases you have to take a non-obvious approach, usually for performance reasons in my experience. Fortunately, commenting is a good way to explain when you are using a non-obvious solution to a problem.

The other axis is how many edge cases your solution has relative to the general case. The negative connotation of "clever" is that the clever approach works but is over-specialized for the specific set of cases where it's used. It might not solve the general problem, but it solves enough specific cases of the general problem for your current needs. Then when for some reason the larger program changes (new feature?) and the solution is expected to handle a new case, it fails, and now you've got a clever non-working solution.

To me, code that is clever in the sense of "non-obvious algorithm" is fine when it is needed. Just comment and explain it well. The problem is when your clever code comes with a side effect of brittleness. Either document the edge cases thoroughly, or use an approach with fewer edge cases.

Re: Why most “clever” code ain’t so clever after all

#55

Earlier quoted context omitted.

For all of Java's pitfalls, this is one of the things it really has going for it. The language itself is extremely simple. I think adding properties instead of the weirdness of getters and setters would take it to peak simplicity and straight-forwardness. (Also, maybe eliminate inheritance and force interfaces and composition instead.)

> eliminate inheritance Why would you want that? Wouldn't eliminating inheritance add a lot of boilerplate code?

I think default methods take care of most of the places where boilerplate would be required. The abstract collections are a great example of this; most of the methods required of a `Collection` can be implemented from a small subset. Sometimes you'll re-implement other operations anyway for efficiency gains, but that's supported with default methods also.

However, I may just be weird. My Java coding style is probably closer to Rust or Haskell. Lots of interfaces defining my type requirements, and static methods to implement compound operations on those interfaces. I like this because it's easily testable and traceable.

Re: Why most “clever” code ain’t so clever after all

#56

This article hinges on a rather silly fallacy. Luckily the author does us the favor of making his mistake very clear in the curve-fitting analogy; but first look at the code. He gives several examples of poorly-written FP code (which we're supposed to believe is "clever" by virtue of being FP), then introduces some new problem constraint which is carefully selected to make the FP solution break but some equally ridic…

I honestly didn't see the same thing as you, my understanding is that using the Lagrange Interpolation is the "clever" choice, but when you add more points, you'll end up with a higher order polynomial and widely different curve which is probably not what you wanted in the beginning.

I read the piece more as a reminder that most specs are usually incomplete/too specific/not conveying what is actually needed, and a warning against cornering oneself with a too clever solution. I also didn't see any big issues with their stance on FP, except maybe that they dismissed the Monoid solution that someone posted down in the comments that looks both robust and readable.

Re: Why most “clever” code ain’t so clever after all

#57

Earlier quoted context omitted.

Not every company wants highly skilled programmers. Depending on the complexity of the project, and cost of defects unskilled programmers may be the most cost effective.

I know. Took me a while to realize it and understand why companies think that way, but it boils down to the fact that as programmers, we're not paid to do a good job, we're paid to do a good enough job. Those two goals are very often at odds. It seems to be a typical clash of craftsmanship with market economy.

That's a good point. There is also a fine line between craftsmanship and intellectual self-gratification at a customer's expense. Doing a good enough job that solves a customer's problems without gold-plating or unneeded complexity is what professionals in most fields are ethically required to do.

As tired as I am of seeing sloppy code, I also intensely dislike the trend at the other end, of creating a half-dozen RESTful microservices and throwing away the relational DB just because it seems cool, maintainability be damned.

I'm hopeful that software development (especially business software development) will someday escapes it perpetual adolescence, and will develop stronger ethical standards.

Re: Why most “clever” code ain’t so clever after all

#58
Software design is often about finding the correct balance between the available implementation methods. Trading memory for time (low-mem/slow recalculation vs higher-mem/fast precomputed-table) is the usual example.

Software design involves a similar trade-off where simple (but repetitive) code can be traded for a smaller (and maybe more complex abstraction). It's not about "cleverness" (though that can be a strong warning sign), but instead if the abstraction involved is correct, useful, and appropriate.

> My code in Listing 4 is not based on those assumptions.

Yes. It's based on the new assumption that it might be necessary to "add that pair to the list of cases" in the future.

> I choose not to read into requirements more than needed.

Except for the new abstraction that attempts to allow for other word replacements not mentioned in the original specification.

While I agree that hard-coding assumptions is usually a bad idea, soft-coding[1] can also be a problem.

> FP

> OO

That's the Expression Problem[2], which always involves yet another trade-off. Some types of modifications are easier under FP, others are easier under OO.

[1] http://thedailywtf.com/articles/Soft_Coding

[2] http://c2.com/cgi/wiki?ExpressionProblem

Re: Why most “clever” code ain’t so clever after all

#59

for(var i in list) { (function(element) { someAsyncCallThatNeedsTheRightIndexedElement(element); })(list[i]); } I've seen people grumble that this is " too clever " I've been known to snap back " Bootcamps don't have a monopoly on what technical solutions are valid " Pointers are probably too clever for most people. Admittedly, goto is too clever for me. :(

I'd just write:

  for(var i in list) { 
    someAsyncCallThatNeedsTheRightIndexedElement(list[i])
  }
though I usually try to avoid for loops with `.map` or `.forEach`:

  list.forEach(someAsyncCallThatNeedsTheRightIndexedElement)
The IIFE in your code is unnecessary and I would thus probably side with the too clever camp in this case.

Re: Why most “clever” code ain’t so clever after all

#60
post #24

I didn't make it past the fizzbuzz example. But I wouldn't call the solution with cycle all that clever. Here's a better one: https://themonadreader.files.wordpress.com/2014/04/fizzbuzz.... the punchline reproduced below: fizzbuzz' :: Int -> String fizzbuzz' n = (test 3 "fizz" . test 5 "buzz") id (show n) where test d s x | n `mod` d == 0 = const (s ++ x "") | otherwise = x fizzbuzz :: [String] fizzbuzz = map fizzbuz…

Feature request: Client should be able to specify either 3, or 1023 for the number needed to print "fizz." Feature request: Client should be able to optionally request "Lizard" as another string whenever the number is a multiple of 13. That's what the article is referring to. Your function may be more clever, but it's more specific, works in only exactly the requested cases and is harder to change.

  fizzbuzz' :: Bool -> Bool -> Int -> String
  fizzbuzz' big doLiz n = (fizz . test 5 "buzz" . lizz) id (show n)
    where
     test d s x | n `mod` d == 0 = const (s ++ x "")
                | otherwise = x
     fizz = if big then (test 1023 "fizz") else (test 3 "fizz")
     lizz = if doLiz then (test 13 "Lizard") else id

  fizzbuzz :: Bool -> Bool -> [String]
  fizzbuzz big doLiz = map (fizzbuzz' big doLiz) [1..]
Post reply on HN