> They don't understand that unclear code is probably the number one cause of technical debt.
At the same time, verbosity can have an obfuscation quality all of its own. For simple assignment, I find a ternary operator very clear and concise, and much preferable to a 5-9 line (depending on style) if/else for a simple assignment. It also might keep you from using the single statement version of if/else if your language supports it, and that's probably justification in itself given how many problems that's caused in the past.
Specifically, I think:
usefulMetric = wantComplexCalc ? complexCalc(foo)
: simpleCalc(foo);
is preferable to: if ( wantComplexCalc ) {
usefulMetric = complexCalc(foo)
} else {
usefulMetric = simpleCalc(foo)
}
even if only because it doesn't obscure intent with what is essentially boilerplate. val usefulMetric = if (wantComplexCalc) {
complexCalc(foo)
} else {
simpleCalc(foo)
} useful_metric = complex_calc(foo) if want_complex_calc else simple_calc(foo) die "Invalid param: please enter a positive number" unless $param1 > 0;
$param2 = 0 unless defined $param2;
return undef if $param1 and not $param2;
my $foo = 1 if $bar; # This unfortunately creates a closure around $foo and is a big source of bugs.
As much flak as Perl gets, quite a lot of thought went into making it flow similar to how people think and talk (which is no surprise if you know Larry Wall is a linguist by training). There were some missteps, but it was very early in this area, so that's expected.Yet there have been modules that support it for years, and with much more features than what was recently rolled out (which was meant to be conservative).
Here's[1] what I said about this quite a while ago. Named parameters with type checking (unfortunately at runtime). I've been writing Perl using different modules (Function Parameters) which use the same syntax for about six years now (for functions, not all the sugar on Moose objects).
> Flattened lists are another one
Flattened lists never cause me a problem. If they cause someone problems, I think they've never really learned what context is in Perl. Once you know how context works in Perl and had a chance to use it to good effect, I can't imagine this complaint persisting. Perl is fundamentally different than most languages in this respect, even if it looks superficially similar to more procedural languages. This is actually a cause of a lot of problems for novice users, because they assume their experience in C/Algol derivatives will map exactly, and where it doesn't people get frustrated.
> but the worst is having to specify "use 5.020;" if I'm using Perl 5.20
What? You don't have to do that. If you want to use newer features that utilize keywords which may conflict with whatever you've written or whatever modules you are using, then yet, you need to opt into those. Perhaps you would have preferred if it silently just broke?
> They've even carried this "tradition" into Perl6 where you have to specify "use v6;" at the top of EVERY damned script.
No, you don't. If you do, and you run it in Perl 5, it will automatically swap out the interpreter for whatever Perl 6 interpreter you have in $PATH though.
> Prefixing every variable with "my" is another one which found its way into Perl6. Why can't an advanced language have default lexical scope?
The requirement to define your variables is not because it's not lexical by default (it is lexical by default, you can use no strict to see). .It's strictness which is enforced, which has been found by the Perl community to be vastly preferably to automatic instantiation of variables because it prevents bugs, and prevents a lot of confusion. You have to define your variable, because the Perl community found that a more sane default.
usefulMetric = wantComplexCalc ?
(complexity > 40 ?
superComplexCalc(foo) :
regularComplexCalc(foo)) :
simpleCalc(foo);I believe part of learning a new library/framework/language is to limit yourself to a certain subset of the API offered. After working with Ruby (the language) and Javascript (the ecosystem), I feel like that's the only way to preserve your sanity and productivity. I don't need to know 4 different ways of creating a lambda in Ruby, selecting 1 that can express the other 4 is good enough.
---
In this case, the rule would be no ternary operators, since they work well unless you nest them or unless you make them long/complicated.
Other examples -
You don't need to wrap if conditions unless you have a multi-line body:
if (myCondition)
x = 42;
y = 23;
Early returns simplify short circuiting logic unless your function becomes too long: if (myVariableAtBeginningOfFunction) {
return true;
}
...
// 2 screens later
...
if (x == 42) {
return false; // why am I not getting false?!
}
Using a variable as a conditional in javascript to test against undefined works well unless the value can be falsy: if (person.isStudent) {
showSchool();
}
if (person.age) {
showBirthCertificate(); // what if age is 0?
}Why not "no nested ternary operators"?
> You don't need to wrap if conditions unless you have a multi-line body
Why not "keep unwrapped if conditions on a single line"?
> Early returns simplify short circuiting logic unless your function becomes too long
Why not "keep functions short"?
> Using a variable as a conditional in javascript to test against undefined works well unless the value can be falsy
Why not "only use conditionals on boolean values"?
I'm not saying your rules are right or wrong, I actually follow a couple of them myself, but your wording implies that other people are simply not following rules, or their rules have a lot of nuances and special cases, but the reality is more likely that their rules are different.
Ultimately we all make different connections and form different patterns in our head. As long as a team can agree on a code style, within a few months everyone starts developing the same cognitive patterns.
If you come into a 3 year old codebase and during the first 2 weeks you need to add extra functionality to a 30-line function with an early return, are you going to refactor the early return? Or are you going to extend it into a 32-line function? What about the new hire after you?
Alternatively, your team has decided to embrace the "only use conditionals on boolean values" philosophy. You're working with a section of code that reads `if (myVar)`. It's been 3 hours, and you don't understand why the code's not working. Suddenly, you realize that at some point `myVar` was refactored from a non-nullable boolean to a nullable number, and someone missed changing this.
And the biggest offender yet - code that is grouped within a file into 'logical sections'. I've never seen this work out. What is a logical grouping for you is a confusing pairing for me. Or maybe it's that I can't immediately grok all 2000 lines of a file I've never seen before, and know where to place the method. This madness around code location is one of the quickest ways to code rot.
---
The perplexing thing to me is that these situations are completely preventable.
If you don't use early returns, scenario 1 won't happen.
Scenario 2 won't happen if you use real comparisons e.g. `if (person.age !== undefined)` (Similarly, `if (person.age != null)` breaks when null and undefined start meaning different things...)
And lastly, a canonical alphabetical/visibility ordering for methods in a file of any length is unambiguous. I don't care what the order is, as long as there is a canonical order.
---
I understand that other teams have their own rules. It's no trouble at all to adjust to things that are purely syntactic differences. But when the rules that are chosen hide lurking semantic pitfalls...I don't know why you'd risk shooting yourself in the foot.
A lot of my strong feelings on code style come from the book Code Complete. I highly recommend that to everyone who hasn't read it. It's filled with examples of confusing/broken code you might inherit, and teaches you how to avoid creating it yourself.
Edit: looks like we hit the HN thread depth limit. Happy to continue this over Twitter, check my profile.
usefulMetric = wantComplexCalc == false ? simpleCalc(foo)
: complexity <= 40 ? regularComplexCalc(foo)
: /* else */ superComplexCacl(foo)
;I'm not saying that one should go crazy with one-liners or uncommon patterns, but things like ternary operators used with reasonably short expressions in a single line of code are totally valid and should be readable to any average dev out there.
Particularly
> Also keep in mind that you're probably bothering others, more skilful ones, with unnecessarily verbose code which is to them harder to quickly scan through.
I stopped contributing to one Powershell repository because author thought that ps is hard and he wanted Get-Process. I put a "i am the greates babysiter meme" in PR and that was considered very disrespectful
Particulary
> Also keep in mind that you're probably bothering others, more skilful ones, with unnecessarily verbose code which is to them harder to quickly scan through.
Not sure I can think of too many situations where it would be otherwise.
Here is the meme:
http://content.randomenthusiasm.com/d4ZEVg4VB.jpg
Not exactly profane I would say but what do I know ...
Sounds like it was disrespectful too.
Terse code isn't much faster to read, the difference between a 300 and 400 line file isn't significant.
Your attitude of "he isn't 1337 enough to understand my code" is the logic that leads to no comments and horrible to maintain code in the first place
It doesn't take a lot longer to sit down and understand how ternary operators work, either. C'mon, it's not differential equations, it's just a notation, and a fairly simple one. It might take a newbie slightly more time at first to understand the logic. We've all been there once, you stop and stare at it for 15 minutes, but after a few times of deciphering it you get used to it. It's not about being 1337 (I surely hope that it's not what's considered elite this days), it's about learning new stuff and any averagely intelligent person can do it. Honestly, would you really hire someone who is not capable to (in a reasonable amount of time) teach him/herself how to read a ternary operator? What programming would that person be capable of doing in future?
Smart people can disagree, undoubtedly, but there's a reason why GOTO is considered to be brain cancer and pattern matching is generally considered to be great.
On a lot of those I know what makes code easier for me to read. It's not the same as some of my coworkers. Based on some of your phrasing I suspect we'd agree on a lot of them, fwiw
When the metric used is "easier to read" it becomes far too subjective IMO, things you mentioned are similar but not quite the same
I don't really see highly competent devs doing the whole J2EE architecture astronautics anymore, nor using single-char variable names. There's a tendency to write things concisely when simple, and then moving the complexity away to some other place, stashed in its own function, when it reaches a certain mental threshold of complexity. There's a tendency to use the best features languages have to offer, maximizing simplicity through orthogonal features and repeated idioms, while discarding unnecessary cruft; one of the marks of junior devs is their desire to try to fit problems into new idioms just to test out language features or strange design patterns.
Given that human intelligence is fluid but the variance just isn't that high (after all, we all have a similar amount of working memory), common design practices emerge out of this understanding for our limits for reasoning about problems. Exceptions abound in extremely technical and complicated problems (just check out non-trivial linear algebra code or bit-flipping, low-level device drivers), but the most part it just sticks out how things are made to look simple within a finite range of tradeoffs. This has been my experience in my domain of expertise; look at most current web development frameworks and they respect common patterns even in radically different languages that are really about the essence of the request-response cycle, not made-up constructs of additional complexity or a restating of the problem.
Yes we do, because the customers and their in-house architects decide how it is going to be, not us.
My pet hate.
If the 'idea' of the code isn't easily broken down into abstractions, even mentally speaking, then small functions will just obscure what's actually going on by pointing out all the implementation details that are wound together.
Look at any large C codebase and you will see plenty of goto statements to manage resource cleanup. The problem is using goto in place of structured control flow like loops and if/else. Statements like yours make it seem like there is a conceptual problem with a jump.
But all the examples of this that I've seen are still structured it's just that the language isn't able to express that structure. The most common examples are jumping out of nested loops (better solved by allowing named loops so you can use break/continue) or jumping immediately to error handling logic (better solved by exceptions, or even just simplistic try/throw/catch).
I do think there's a conceptual problem with arbitrary jumps.
https://www.visualstudio.com/en-us/articles/devopsmsft/code-...
Peter Naur - Programming As Theory Building http://pages.cs.wisc.edu/~remzi/Naur.pdf
Scala provides a whole new level of ability for people to write code that can be meaningless to others.
It really is quite different.
+ Any decent developer can read decent code in Java or whatever normal language and get along just fine.
+ Only a few people can deal with Scala - and even fewer if there's a log of specific project Scala weirdness used in a particular program.
So sure - among a narrower set of 'Scala friendly' developers, and possibly within that even narrower set of people familiar with the 'Scala weirdness' of a particular project - those people can 'get along fine'.
The problem is that this can be a pretty narrow set of people.
Scala would have to represent a pretty big advantage to propose it's general weirdness as something to bother with.
I don't think it does - hence the 'de-adoption' of various entities.
My gut tells me it's past the threshold - the 'extra power' offered Scala just isn't quite worth it's weirdness for most things, and so most devs won't learn it ... and so then it becomes less valuable from a business perspective.
It's possible we may have it peak Scala.
We'll see I guess.
True, but once get into the length of variable names in iOS and Android development, you're in a whole new territory. 38 character variables have no place in life.
And extreme's like:
outputImageProviderFromBufferWithPixelFormat:pixelsWide:pixelsHigh:baseAddress:bytesPerRow:releaseCallback:releaseContext:colorSpace:shouldColorMatch
This is 149 character.
They don't understand that unclear code is probably the number one cause of technical debt. Nobody wants to waste time trying to understand it so they start to attach workarounds and it just keeps getting worse.
Some of their code is so "clever" that I've refactored the line with 7 method calls just to understand what the hell is going on.
Lambdas and fluent syntax make me quiver with fear. In the wrong hands they let you do unspeakable things