4 ms·
Posts like this give the illusion of saying so much, but at the end of the day, they really say almost nothing at all. What actionable advice is this post reall
by king_magic 11y ago
Posts like this give the illusion of saying so much, but at the end of the day, they really say almost nothing at all. What actionable advice is this post really giving? What examples is it pointing to to illustrate the author's point?
> Use threading. Instead of naming each intermediate value, thread the value through the process without naming it.
What does that even mean?
To be honest, I'm not even really sure what the author's point is. Naming is hard? Naming is bad? Don't name things? Name everything? It just feels like an abstract nonsense piece.
- userbinator 11y agoWhat does that even mean? It means don't do this: int x = k + 3; int y = v * x; int z = y - foo(); return z; Instead, do this: return (k + 3) * v - foo();
- king_magic 11y agoMakes sense, terribly worded by the author, though. Threading generally means, well threads. Throw the word "process" in there and it makes things even less clear. Also, for the record, I totally disagree with the author on this. This: return (k + 3) * v - foo(); works great, until you need to debug it. Good luck then.
- icebraining 11y agoWhat's the problem? Just put the breakpoint on that line, then check the intermediate values (e.g. with PyDev, you can select parts of the expression to check their results).
- king_magic 11y agoNot every IDE is as helpful or forgiving for that kind of debugging. If you have things broken out, it's much easier to step through the intermediate states of expressions like that, and much easier to tweak when you need to fix something. Having everything together in One Expression To Rule Them All is a code smell, IMHO.
- icebraining 11y agoEven when using C, you can use gdb to evaluate subexpressions at a breakpoint. I don't see why is it a code smell just because some tools are lacking. I do think it's a smell if the expressions has side effects, but that's a different issue.
- king_magic 11y agoI see it as a code smell precisely because some tools are lacking. I don't code for an ideal world where all tools and developers are perfect - personally, I take a practical approach and code for the real world.
- icebraining 11y agoFair enough, but then it's only a smell in languages lacking in those tools. In my real world, I can debug it just fine.
- KingMob 11y agoTrue, but Unnecessary Variables is also a code smell, and a worse one to me, because it increases cognitive load in larger functions. In the toy function given, it doesn't really matter, but in general, I think that people should aim to code for clarity, not ease of debugging.
- nerd_stuff 11y agoIn the author's language, Clojure, it's trivial to print the intermediate value at every stage of a threading macro so you can watch your data as it transforms and pinpoint the problem, ex: (defn debug-it [x] (println x) x) (-> input-value debug-it function1 debug-it function2 debug-it function3 debug-it) Debug-it could also take a custom message at each line if you wanted the output tagged with names/numbers.
- seiji 11y agoA = max(3, 5) B = max(A, 7) C = max(20, B) C = max(20, max(max(3, 5), 7))
- mbrock 11y agoThreading aka chaining aka composing. You describe a pipeline and then send a whole value through it, thus avoiding the naming of intermediate results. Functional programmers call it "point-free style." It can't save you from naming in general, since each piece of your pipeline will be named, but it saves you from naming "variables." Here is an example of the main part of a Haskell program (using the "pipes" combinators). It starts two concurrent pipelines. One reads user commands from a queue, encodes them, then writes them to an AMQP server. The other reads results from the AMQP server and runs them through a more complicated pipeline, the details of which aren't very interesting. runEffectsConcurrently (contents commandQueue >-> encoder >-> writeTo amqp) (readFrom amqp >-> decoder >-> skipEmpty >-> logToFile >-> forever (decodeMsg state) >-> toChannel eventQueue) What I like about this style has to do with how it avoids naming intermediate results. Instead of stuff like loops, anonymous callback functions, and variables, it approaches a declarative specification of the program's structure & behavior. I still had to give names to each component, but I didn't need to come up with names for the values that flow through the pipelines.
- king_magic 11y agoYeah, that makes sense. The author's terminology/wording wasn't clear/helpful IMO. Beyond that, though - the above code looks great - until you need to debug it. Personally, I'd rather pay a 'naming tax' on things for the sake of readability / debugability over what the original author is shooting for any day.
- mbrock 11y agoI haven't needed to debug it very much. Thankfully, it's easy to insert debugging helpers at any stage of the pipeline.
- king_magic 11y agoInteresting, maybe I'm just less familiar with debugging in Haskell.
- nerd_stuff 11y agoHe's apparently talking about Clojure's thread macro specifically. If you're not familiar it can be a way to organize code in a straightforward, human-readable, easily debuggable syntax. Ex: (~> (sha1 in) (bytes->hex-string) (bytes-append #".") (displayln)) In pseudo-Python this would be: displayln(bytes-append(bytes->hex-string(sha1(in)), #".")) http://www.greghendershott.com/2013/05/the-threading-macro.html http://www.greghendershott.com/2013/05/the-threading-macro.h...