Computer programming is somewhere between an art and a science. Your code must match the syntax that the computer expects and understands, but the style and flow of your program are ultimately up to you.
Most programming problems can be solved in many different ways and judging one as better than another can be tricky. Sometimes, things come down to personal preference, and other times one approach is just better than another. This could be for performance, conciseness, or readability.
This post explores two patterns that are more likely to be used by junior developers than senior ones. The examples below are written in JavaScript, but the general principles extend to other programming languages as well.
1. Overuse of “if” and “else” Statements
Let’s say we are writing a class used to represent Simpsons characters. The constructor of the class accepts a first name, last name, and occupation for that character.
The code below creates the class and instantiates an example character, edna.
class Character {
constructor (firstName, lastName, occupation) {
this.firstName = firstName
this.lastName = lastName
this.occupation = occupation
}
}
const edna = new Character(
'Edna',
'Krabappel',
'Elementary School Teacher'
)
Now, let’s say that we want to add a getter property to our class that returns a boolean, describing whether the character is a member of the Simpson family or not.
Edna Krabappel is not a member of the Simpson family, but Lisa Simpson would be. Here is one way that this might be achieved, but it isn’t very good.
class Character {
constructor (firstName, lastName, occupation) {
this.firstName = firstName
this.lastName = lastName
this.occupation = occupation
}
get isSimpson () {
if (this.lastName === 'Simpson') {
return true
} else {
return false
}
}
}
const edna = new Character(
'Edna',
'Krabappel',
'Elementary School Teacher'
)
console.log(edna.isSimpson) // Logs false, as expected
This code works as expected, but is unnecessarily verbose.
For starters, the else block isn’t needed. If the condition is found to be true, then the function will return a value and terminate — the else alternative will never be reached.
This fact allows us to simplify the method to the following:
get isSimpson () {
if (this.lastName === 'Simpson') {
return true
}
return false
}
Generally speaking, it’s stylistically preferable to avoid else blocks because it reduces code nesting. Although this isn’t always possible, it often is.
But even with that improvement, the method is still a bit silly. Since the getter intends to return a boolean as the output, an if statement isn’t needed at all.
This code does the same job:
get isSimpson () {
return this.lastName === 'Simpson'
}
That’s much nicer. Comparison operators are often combined with if statements, but they don’t have to be. Sometimes, it’s better to just return a boolean directly.
2. Using Functional Programming in a Nonfunctional Way
JavaScript arrays can be manipulated either procedurally or functionally.
A functional approach is often preferable because it avoids mutation and unnecessary variables, but a procedural approach can be appropriate in certain situations as well.
While your choice of paradigm may be a matter of taste, misuse of functional programming techniques can identify you as a beginner. To illustrate, here’s an example.
Let’s say that we have an array of Character objects available, and want to use this data to create an array of names.
// An example input array could look like this:
const characters = [
new Character(
'Edna',
'Krabappel',
'Elementary School Teacher'
),
new Character(
'Lisa',
'Simpson',
'Student'
),
new Character(
'Moe',
'Szyslak',
'Bartender'
),
]
// In that case the output we are looking for would look like this:
[
'Edna Krabappel',
'Lisa Simpson',
'Moe Szyslak'
]
The first step is going to be adding a getter to our Character class that returns the full name of the character:
get fullName () {
return `${this.firstName} ${this.lastName}`
}
With that available, we can move on to getting an array of full names. Here is one solution that works, but leaves room for improvement:
const names = []
characters.forEach(character => {
names.push(character.fullName)
})
This implements forEach and provides a callback function, but it might as well have been implemented procedurally.
Instead of returning a value, each iteration of the loop mutates the external names variable. A for loop could easily achieve the same thing:
const names = []
for (let character of characters) {
names.push(character.fullName)
}
forEach just isn’t the right choice for this. To ensure that the callback function remains “pure”, we should use another array method — let’s try reduce.
const names = characters.reduce((names, character) => {
return names.concat(character.fullName)
}, [])
This attempt avoids the problems associated with forEach but still isn’t great.
The problem lies with the verb “reduce”. As well as preventing externally declared variables and mutation, one important benefit of functional programming is readability.
A functional method like “filter” or “reduce” can make for more expressive and readable code when used correctly.
For example, when a programmer sees that an array is being “filtered” they can assume that a set of items are being inputted, and only a subset of those items will be outputted. The items that were not outputted were “filtered out”.
Likewise, when a programmer sees an array being “reduced” they can assume that the function will take the input set and “reduce it” to a more compact output. You might “reduce” a list of test scores to a single average.
This gives readers of your code a helpful hint of what it does. If the array was being operated on procedurally, then readers would need to dig into the code at a lower level to understand what is happening.
Getting back to the example, this solution is not ideal because the verb “reduce” does not accurately describe what is happening. Since the goal is to return one output item for each input item, “map” is a much better choice. It’s also much more concise:
const names = characters.map(character => character.fullName)
Summary
Writing code that works is good but we should also strive to write code that is succinct, performant, and readable to others.
Eliminating redundant if and else conditions and selecting array methods appropriately are a good step towards this goal.
Seemingly small details such as these are one way that experienced programmers can be distinguished from less experienced ones.
Top comments (23)
As someone currently looking for junior dev jobs, I definitely have the
if else
issue. Thanks for showing me a better way.Something that helped me change the way I viewed if statements is using early returns.
Big plus is reducing indentation and easing the cognitive load of the different forks your functions can take.
Yeah totally. Dealing with a lot of forks stinks. Also this might be obvious, but I remember being excited when I realized you could do if statements on one line, like
For a long time, I always used a block--even for
Then again, a fair amount of seniors (and depending on the language) will go back to the multiline approach, so that every line does exactly one thing (where the check and the action count as separate things).
This can be useful for finding errors and analizing test coverage reports as well as making the code easier to visually parse because it's closer to a list of instructions.
No one should judge the experience based on this. If someone misuse an FP technique, the only thing that tells me is that they are learning functional programming.
And just a tiny note here:
Array.forEach
returnsundefined
. Keeping it pure wouldn't make any sense. If someone is using it, it's very likely they want to perform a side effect, and that's not bad.I've noticed that the JS community has started using the term "functional" for everything that uses higher-order functions, which is really just a small part of it. Just using
map
orreduce
doesn't make code functional, andforEach
is about as un-functional as it gets (It literally is a nop without side effects)I like to think they refer to a "functional style". At the end of the day that's all we can hope for in javascript. We can't even enforce a function to be pure, we can only have them by convention. Sometimes I think is sad that function composition doesn't get as much atention as the array trinity (map, filter, reduce).
I wouldn't even say "functional style", rather it's about picking some of specific functional tools that fit the intended domain of ES and ignoring those that don't really add enough value and/or are just not doable in ES.
Function composition, currying, referential transparency... there's lots of concepts that get ignored because they stray too far from how people want to write javascript for the most part.
In my case, and my case only, the older I get the more details I want to see, and when I see very condensed code on one line that usually goes on many, I know that it is very likely written by someone who a few years in programming only.
While learning html, css, and javascript, keeping apart the separate functions of each was stressed immensely - markup, style, function. But I'm seeing the value of having some of the style right in the html after working with bootstrap a little bit. It sure made it easier for me to move blocks of code around when I didn't have to chase down css properties. Could you tell me your thinking on that? I'm a ultra-junior developer.
Here is an advice, my thought only! others will disagree 😊
When someone tells you “Everything must be …” then just ignore the rest of his/her words because they are pointless.
Software development is about comfort, if I put the markup in one file, and the code in another file, will it be more comfortable for me to continue building the App or Website? If yes (for that project and technology), then it is a good idea, if no, then it is a bad idea.
What you normally see in some companies stuff like “Rule nn, all validation must be done on the server side” or some rule like that, and because some big manager wrote that rule, tons of additional code and workarounds are added so the app can follow that rule.
Now think about the next developer who will change the code, will he or she quickly get up to speed and modify it, ideally, the next developer should open Visual Studio, open the project, and be able to debug it with zero additional steps.
Then when he / she looks at the code, should be clear and easy to understand, regardless if the CSS is mixed with the html or JS or not, that absolutely should not matter.
Comfortability is not just the developer, it is the all the people end to end, will the end user love the App? If slow? Unlikely, if instant, oh yes, they will love it, but having the app to run instantly may also mean less comfort on the development side, but unhappy client may also mean no income and that results in no development at all.
I can continue wiring for hours, but at the end, It is just balance 😊
Thank you so much for sharing your thoughts! I really appreciate it.
I wish people would stop perpetuating this company-induced hierarchy of developers. This scheme was introduced to find a way to pay less money to capable people. The term "senior" means nothing. We have a responsibility as developers to abolish this arbitrary structures.
This entire phrasing implies that people wouldn't want to be a "junior" developer. Meaning, that all must aspire to not be that. It's a device used by companies to cultivate imposter syndrome to turn them into more productive humans but not pay them in appropriate relation to their skill. People who start out are immediately bombared by the fact that they are something that must immediately aspire to not be any longer.
Many of these patterns are being used by people who call themselves "senior". It doesn't mean anything and it certainly doesn't make those people bad. If "juniors" are using those pattern, then you have failed them as a "senior" in educating them about what other choices they have.
If you read this, if you write code and it works for what you are trying to achieve then that is all that matters. Any pattern in code is subject to "it depends". If it's possible, i'ts not wrong. Wether it is good or appropriate, depends on the context.
Honestly, unhealthy love for getters/setters makes me sad.
They make any code that employs them look different from what it does - what looks as simple property access/write is actually a function call. Imo, there's no real reason to use them instead of functions, just the matter of taste - a bit shorter syntax and auto bind.
Best example is in games where an object has speed + angle or speed_x + speed_y depending on how you want to look at it. It's nice to access either of them as if they were actual variables and not think about how the object stores its velocity vector internally.
That being said, getters/setters go against the "Tell, don't ask" principle. Too much getters/setters are usually a sign that your objects logic might be leaking into different objects, which is very bad in terms of object orientatino.
If anything, I'd say this is worse. Assuming for a moment that it couldn't be simplified further as you do in the article, I think having the else block is preferable because it puts both branches of the decision on the same indentation level and makes it clear that it's either this or that.
If you want to reduce writing and you only have single-statement branches, you could just do
or even put it on 2 lines if the
if
-condition was a bit shorter.Hey, you inspired me to write one for CSS coding patterns that give you away as a junior developer!
These are real things. But - being Jr. is just fine. Getting something working - is always more important than Code Golf.
True enough. But in the long run, having something that's maintainable is at least as (if not more) important as having it fulfil requirements. (Of course, code golf code tends to be poorly maintainable, so I guess we're saying the same thing)
This is interesting! I consider myself a junior developer but I don’t use most of these things that would normally give me away as one (like the map thing; that’s usually my go-to)
I think the if else section is more coding style vs a level of understanding. Writing out a full else if is sometimes preferred as you might come back at some point and want to debug inside that if.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.