9 ms·
I like code that reads like a Dick & Jane book ("See Dick. See Jane. See Dick run. See Jane run."). However, it appears to be trendy to write insanely diffi
by stevecalifornia 10y ago
I like code that reads like a Dick & Jane book ("See Dick. See Jane. See Dick run. See Jane run.").
However, it appears to be trendy to write insanely difficult to read code. To use the analogy, Shakespearean code. Instead of one line of code doing one thing the developers will write a ton of functionality into one line of code by using fluent and method chaining. As someone reviewing the code I have to keep this mental stack of what the code is doing and it just becomes too much to process.
It's a personal opinion, but I had to share.
- adamnemecek 10y agoThis only a problem in dynamically typed languages.
- jmcomets 10y agoJust so this is clear, in Java this pattern is very present, especially since Java 8 (Streams). Before that, there was the Builder pattern[1]. It's also present in C++/C# in the same form. [1]: https://en.wikipedia.org/wiki/Builder_pattern https://en.wikipedia.org/wiki/Builder_pattern
- TimJYoung 10y agoI can't up-vote this enough. As someone that started doing development in the late 80's, I find this style of coding to be infuriating. It completely destroys the ability to map lines of code directly to function calls without resorting to manual coding rules that require that each .function() be on a separate line, and makes debugging way harder than it needs to be. And, for what purpose ? To avoid a local, temporary variable ? Do these developers think that their code is faster this way, or...what ? It's "write-only" code - good luck to the next guy that has to read it. And, don't get me started on: if <Constant> = <Variable>... :-)
- MrLeap 10y agoTo get you started, I'd like to compare my problems regarding `if <Constant> = <Variable>` with yours. This assumes you aren't the kind of lunatic to actually assign a constant inside of an if's condition. 1. I can't articulate exactly why, but that should totally be flipped. The constant should be on the right side! `if(3.17 == possiblyPi)` would make me seriously question the author's motives. 2. It's personal preference, but in almost every situation I'd prefer to use a switch over an enum than lots of constants.
- TimJYoung 10y agoSorry, I should have made it clear that what I posted was pseudo-code, so just assume that = is equivalent to == or whatever in the target language. 1) Yes, my issue was the constant being on the left side. I've seen it done a few times, and I'm sure it's probably just a "I did it that way when I first started and it stuck" or something similar, but it just never looks right to me. I just want to scream "But, you're comparing the variable !!!!". :-) 2) Constants are useful when there are going to be gaps in the values (message dispatch codes), but yeah, I also agree here - enums are always the way to go, if you can do it. Switches are also great, but can be problematic at times due to the way that they aren't always implemented in a consistent manner among various languages with respect to fall-through and breaks.
- onion2k 10y agoI can't articulate exactly why, but that should totally be flipped. Should it? If you accidentally use an assignment operator (eg = ) instead of a comparison (eg === )[1] with the constant on the left your code will throw an exception, which is what you want. If you put the variable on the left and accidentally use an assignment then you'll overwrite the variable with the constant value and return true, consequently executing whatever is in the block of code that the comparison is supposed to be checking for. You don't want to do that. That could be really bad. [1] If you use == then you are bad and wrong.
- MrLeap 10y agoGood point. I've been writing a lot of coffeescript recently, and the `is` operator insulates me from that whole situation. re [1] - javascript isn't the only language == isn't bad and wrong everywhere!
- dualogy 10y ago> And, don't get me started on: if <Constant> = <Variable>... That seems to be quite the pet peeve with many and I quite like the style in certain scenarios: namely the common one where the constant is a simple literal and the variable portion is a longer (no, not excessively long, just.. longer ;) chain of things, a call within a call or some operator etc. It's as if to signal "there is some crunching/intricacy here but look, it's just to check against this simple value here right at the start". Kinda reassuring. Likewise find it quite readable for checking for magic strings / code-monikers (of course to be avoided but sometimes not when dealing with certain input formats etc) and especially when a couple of such in a row are tested..
- noobiemcfoob 10y agoI like your example a lot. It's easy to imagine a monstrosity of an equation stretching off to the right, but knowing the solution (or at least a solution) can constrain the knee-jerk reaction of "oh, that looks complicated"
- Falling3 10y agoWhen learning C in college, I was specifically taught to use CONTSTANT == variable. Accidentally omitting a '=' is common and putting the constant on the left side ensured the compiler would catch the mistake.
- valleyer 10y agoif (x = 5) is a default warning in clang (and I think gcc) nowadays.
- kennu 10y agoI would argue that by using CONSTANT == variable, you are reducing the cognitive load of the compiler, but increasing the cognitive load of the human reading the code (who has to mentally flip the expression around). I think the original article intended to say the same thing.
- SomeStupidPoint 10y agoThats just what you're familiar with. I find it perfectly natural to read "if 5 == x:" without having to flip it around. (And it's not about "cognitive load" on the compiler, it's about fail to error not fail to silent success.)
- closed 10y agoAgreed. I think the key here is that consistent exposure over time to patterns reduces cognitive load through "chunking".
- nurettin 10y agoCompilers don't have cognitive loads.
- adrianN 10y agoAsk C++ compilers when they have to chew through Boost ;)
- deleted 10y ago[deleted]
- Swizec 10y agoI love chaining, but one verb per line. Instead of something like Me.getFish.skin.debone.flour.salt.fry.eat It would be something like Me.getFish .skin .debone .flour .salt .fry .eat I find this more readable than doing it without chaining like this: fish = Me.getFish fish.skin fish.debone fish.flour fish.salt fish.fry Me.eat(fish)
- rb808 10y agopersonally I prefer without chaining, makes much more sense as its what I've always seen until the last ~5 years. The other part you didn't mention is that you have to amend all the functions like getFish, skin etc to return the object which I think makes their signature unnecessarily less clear.
- Terr_ 10y agoYeah, just because something looks like chaining doesn't mean it's really repeated calls on the same object. Even with some static-checking of types, it could also be a copy of the object. While blocky, the repeated thing.do() format is explicit about what object is being operated on.
- maxxxxx 10y agoI find the version without chaining easier to debug.
- girvo 10y agoI don't know, I'd just set a breakpoint in my editor regardless of the form?
- beagle3 10y agoI hear you. I don't like method chaining either. Instead of window.FindCanvasForObject(obj).Color(RED).MoveTo(10,30).LineTo(50,20). ... I much prefer: o = window.FindCanvasForObject(obj) o.Color(RED); o.MoveTo(10,30); o.LineTo(50,20); (Where, in C++ I would enclose this inside a { curly block } to give o the right type and make it local, and in Python I would add a "del o" at the end; and yes, I reuse 'o' to mean 'object' in these cases as much as possible, occasionally having "ox" and "oy" when I have x and y objects to deal with simultaneously). I think it provides the fluency of method chaining with the readability of "standard" code, but this style seems to get scorn from both the chaining-loving people and the chaining-hating people. Oh well, different strokes etc.
- nostrademons 10y agoHow about: window .FindCanvasForObject(obj) .Color(RED) .MoveTo(10, 30) .LineTo(50, 20) This avoids the repetition of the local variable name, while still making it clear what's being called on the object.
- golergka 10y agoBut on what object? The fact that calling .MoveTo(10, 30) would return the same object it has been called on, and not, for example, a handle to created movement animation, is not exactly obvious. Modern pattern of methods which just return the objects that they've been called on, by default seems to be very trendy, but I fail to see how is it helpful.
- nostrademons 10y agoSame way that you use any other API: by reading the docs. This is at least a very common pattern; it's highly likely that whoever maintains this code will have seen it before. And if you're using an IDE, the IDE will even tell you this as you hit '.' BTW, it doesn't have to be the same object: if memory is abundant and CPU is not, it can often make sense to create a fresh object with each call. Doing this lets you share partially-constructed objects without worrying that mutation will result in surprising effects: let box = NewCanvas() .DrawLine(50, 0) .DrawLine(50, 50) .DrawLine(0, 50) .DrawLine(0, 0) let scene = [ box.Fill(Color.RED).TranslateTo(200,300), box.Fill(Color.BLUE).TranslateTo(100, 300), box.Fill(Color.GREEN).TranslateTo(400, 500) ] scene.forEach(box => box.Draw())
- awinter-py 10y agoHmm -- you're talking about programming in the small, as in line-by-line style. Cognitive load also affects devs at the scale of a whole project, i.e. understanding how the program fits together across different modules, across state changes and across time. What's the dick & jane solution for project-scale organization?
- lacampbell 10y agoBingo. People like to hold forth on the small scale - but what about communication between components? I watched "The Art of Destroying Software" [1] the other day and I've been thinking about the concepts a lot. Thought provoking talk - apart from the surveys he keeps conducting. Making a nice method isn't that great. But a nice "component" or "module" or "service" - that's the key. Try and break your program up into little programs. But not too little... maybe that's the way? [1] https://vimeo.com/108441214 https://vimeo.com/108441214
- ndh2 10y agoThe topic is good, but these short sentences and long pauses between the sentences make it really really hard to watch.
- kimburgess 10y agoI love that term "Shakespearean code" — beautiful exploitation of the language, that when analysed deeply is amazing, but on the surface is just really fucking horrible to read.