

Beautiful code — The Manifesto - bjg
http://www.bestinclass.dk/index.php/2009/11/beautiful-code-take-1/

======
snprbob86
The author writes:

"I’ve received about 6 comments from C# developers all giving me their take on
a better version of the liquid-value code above. A couple of them using Linq,
which simplifies the code substantially. I’ve taken a drastic step in deleting
all those comments — sorry guys!!"

 _sigh_ OK, clearly this guy is not worth attempting to have intelligent
discourse with. What good are comments if you just delete those from anyone
who disagrees with you?

~~~
lbj
@snprbob86: I don't mind you moving comments from my blog to HN, but I do mind
you misquoting and thereby lying publicly - it's not good for you and it's not
good for me.

Here the full quote: "Hi all — I’m serving up the first comment!

I’ve received about 6 comments from C# developers all giving me their take on
a better version of the liquid-value code above. A couple of them using Linq,
which simplifies the code substantially. I’ve taken a drastic step in deleting
all those comments — sorry guys!!

Not because they didn’t present valid points, but because they entirely missed
the point — I tried to spell it out with the K example — We’re discussing
principles here, not code examples. I have no doubt that my rusty C# can be
written in a more idiomatic sense, using better libraries etc. But thats much
beside the point. The point is, that while the language so freely permits and
even encourages me to code that way — I will end up seeing that type of code
in my systems. If I had the privilege of hiring a team of superior geniuses
and unspeakable coding skills, then sure, they might consistently produce rock
solid functional code even in C# — but that’s not a real world scenario.

So lets stick with the principles. And if anybody does provide examples,
please connect them with something discussed in the post. That makes for a
better discussion than just swapping code.

Thanks to all for taking the time, sorry for being so harsh /Lau"

~~~
snprbob86
Not reproducing the full comment does not constitute a misquote.

Using Clojure doesn't enable you to magically write perfect code. You posted
well written Clojure and poorly written C#. You can write poor code in any
language.

If you wished to remain on the topic of imperative vs functional, you should
have avoided phrases like "using C# as the tool has added a huge degree of
ceremony". You made a direct attack on the language, not on the coding style.
You also make significant mention of the number of lines of code, but it seems
as though you have intentionally included boilerplate to make your point.
Being misleading and deleting comments are not ways to make an effective case
for your cause.

EDIT: Oh, and on the actual subject of functional style. I still much prefer
the C# approach as it reads in order you perscribed:

1) calculate liquid value of each item

2) filter candidates

3) accumulate value

    
    
      (from asset in assets
       let liquidValue = GetLiquidValue(asset) // 1
       where DoubleMargin(asset, liquidValue)  // 2
       select liquidValue).Sum()               // 3
    

Compared to the Clojure which reads:

    
    
      (reduce (sum-field :productioncost) 0       ; 3
         (filter doubleMargin?                    ; 2
               (map attach-liquid-value assets))) ; 1
    

or the Python which reads:

    
    
      sum(liquid_value                           # 3
          for liquid_value, asset in assets
          (get_liquid_value(asset), asset        # 1
           for asset in assets)
          if double_margin(asset, liquid_value)) # 2

------
snprbob86
Let's compare apples and apples, rather than apples and oranges, shall we?

    
    
      (reduce #(+ %1 (:productioncost %2)) 0
        (filter #(> (:liquidvalue %) (* 2 (:productioncost %)))
          (map #(assoc % :liquidvalue (* (:sdfactor %) (:productioncost %))) assets)))
    

vs.

    
    
      (from asset in assets
       let liquidValue = asset.SDFactor * asset.ProductionCost
       where liquidValue > asset.ProductionCost * 2
       select liquidValue).Sum()
    

I'd prefer that C# _3_ code any day of the week.

~~~
markerdmann
You seem to be intentionally taking that Clojure code out of context. The
refactored of version of that code, which compares much more favorably with
your C# 3.0 version, was given as:

    
    
      (reduce (sum-field :productioncost) 0
         (filter doubleMargin?
               (map attach-liquid-value assets)))

~~~
snprbob86
On the contrary, I think that the C# code the author presented was unfairly IN
CONTEXT. It showed using statements, a namespace, the program entry point, and
other boilerplate. While I agree that C# has a non-trivial class boilerplate
and non-zero function boilerplate, the Clojure you quoted doesn't even show
any function boilerplate (defn foo [args] body)

I compared a C# 3 expression to a Clojure expression.

And that bit of Clojure that you quoted uses helper functions which are not
defined. The C# version of that is:

    
    
      (from asset in assets
       let liquidValue = GetLiquidValue(asset)
       where DoubleMargin(asset, liquidValue)
       select liquidValue).Sum()
    

Clojure is a great language, but this article unfairly bashes C#, which is
also a great language.

------
chipsy
Blind Clojure love. I like how right as he starts to approach the specific
problems that Tim Sweeney and Epic have to deal with in handling what is
fundamentally a mutability problem(unified game state), he sweeps them under
the rug so that he can go back to talking about how functional code is
beautiful, disregarding that it is insufficient for the problem at hand.

------
jongraehl
More flamebait from lau. See also Clojure vs. X.

There is a place for mutation (certain algorithms absolutely require it), in
spite of the obvious advantages of immutable+functional programming.

------
alexgartrell
“Every line of code, whether it be PHP or Clojure has roughly the same
potential for a bug. But 20 lines of Clojure may sometimes translate into 1000
lines of PHP.”

Not PHP, but C:

    
    
        int x = 6;
    

I'm pretty confident about that one. A lot of those 1k lines of code will be
"stating the obvious". I don't think it's fair to imply that the probability
of a fault in a line of C code is anywhere near the probability of a fault in
a line of Clojure.

I doooo like Clojure though :)

~~~
swombat
I can point to a Clojure line that has similar characteristics (and I don't
even know Clojure):

(+ 1 1)

Done. Clojure's awesome, right? No errors. That rocks, huh?

No. Even that line has the potential for errors:

    
    
      1. You could have a typo (int z = 6; int x = 7;)
      2. You could have misunderstood the requirements (it should actually be float x = 6.5)
    

The only possibility you excluded with this trivially simple line is:

    
    
      3. An error in how you used your own tools (easier to imagine if the line involved pointers).
    

Part of the difficulty of debugging is, you don't know _which_ lines have
errors in them. If you have 1000 lines, you potentially have to review them
all to find the bug. If those lines are poorly compartmentalised, so that you
can't heuristically find your way to the likely location of the bug, that is
doubly the case. Conversely, if you only have 20 lines of code, then you only
have 20 lines to read before you've definitely seen the line with the bug
(whether you recognise it is another matter, which has more to do with
experience, capability, and the clarity of the code).

Intention-revealing code does tend to be much, _much_ clearer, though.
(although I'll grant you it's possible to obfuscate code with malevolent
intent).

