Clean up your code with these tips!

TL:DR

See bottom;

The breakdown

After reading the discussion If/else or just if?, it made me think that it might be helpful for some of you, for me to share a few patterns I like to follow that helps me keep my code smaller and cleaner.

It's so easy to stick to the patterns/styles of coding that you're used to or that you learned from the very beginning. This will hopefully challenge you to see if you can improve.

I'll walk you through a typical scenario and how to clean it up, by using an example from a recent piece I was working on.

Here is how you might see some developers write it.

Note: I'm coding in es6 for the example.

My code needs to confirm hostname is available, check if it's a localhost site I'm working with and if so then set my cookies to non-secure. This is required because otherwise, chrome and some other browsers will not allow cookie storage via localhost when marked as secure. See here buried deep down in the stackflow

letsecure;// Check if window.location.hostname is set.if(typeofwindow!=='undefined'&&window.hasOwnProperty('location')&&window.location.hasOwnProperty('hostname')){constdomain=window.location.hostname;if(domain=="localhost"||domain=="127.0.0.1"){secure=false;}else{secure=true;}}else{secure=true;}exportdefaultnewCookie({secure:secure});

Now a few things you might notice right off the bat. Such as getting rid of both the "else" statements by setting the top let secure to let secure = true.

We cleaned it up a bit, but we can definitely do better. Any time you see a sub "if" statement, you should ask yourself "how can I clean this up?". It's rare you need to have sub "if" statements if you know how to avoid them.

Let's first break the sub "if" statement out and put it below the main "if" statement.

We can do that by initializing our "domain" variable above to "null" or "false" (I prefer null, feel free to discuss), then set the domain to the hostname if it's available via window.location.hostname.

Next, we update our sub "if" to now check for "domain" having a truthy value on top of the original check against localhost/127.0.0.1.

That reminds me, lets clean up that check for the localhost/127.0.0.1 with some regex. domain == "localhost" || domain == "127.0.0.1" now becomes /^(localhost|127\.0\.0\.1)$/.test(domain)

If you don’t like regex, you can use this smooth tip from vojtechp to make it even easier to read.

letsecure=true;// Declared domain variable as a letletdomain=null;// Check if window.location.hostname is set, if(typeofwindow!=='undefined'&&window.hasOwnProperty('location')&&window.location.hasOwnProperty('hostname')){domain=window.location.hostname;}// Moved out and now checks additionally "domain" is setif(domain&&/^(localhost|127\.0\.0\.1)$/.test(domain)){secure=false;}exportdefaultnewCookie({secure});

Hopefully by now you're starting to see how each time, we improve the code a little more.

So how far can we take this? Let's see what else we can do.

One major improvement to my coding style, I learned off of a random blog. I really wish I could give them credit, but unfortunately it was so long ago, I forget who it was.

What they showed was to move the logic out of if statements and assign them to variables, when it involves 2 or more values. I'll have to write up another post about this, as you can get really creative with it, but for now we'll keep it simple.

TL:DR

from

letsecure;// Check if window.location.hostname is set.if(typeofwindow!=='undefined'&&window.hasOwnProperty('location')&&window.location.hasOwnProperty('hostname')){constdomain=window.location.hostname;if(domain=="localhost"||domain=="127.0.0.1"){secure=false;}else{secure=true;}}else{secure=true;}exportdefaultnewCookie({secure:secure});

Three minor additions: you can omit the ternary in your case in favor of a logical gate and you should use /regex/.test(string) instead of string.match(/regex/) if you don't want to do anything with the result and lastly, you don't want domains like localhost.mydomain.com to be interpreted as secure, so better make sure that regex captures the whole domain string - so now it looks like this:

Aw! you're so right! I should have used test vs match, also I should have added in $ for an exact match. I'll update this! Part of the fun was to show people they can resort to regex when doing multiple test against a single variable. If it was another scenario of checking the domain against lets say 3 or more possible values, then regex is a quick way to solve this.

You're welcome. I'm usually rather eager to solve things with regex myself. So I usually think again: "will a regex make that code better?" and try it without the regex. In ~50% of the cases, I keep the regex. For the sake of having an example, I feel it's justified. For live code, I would have removed it.

I am not familiar with JS since I write in another language, but your example is clear enough to follow.

Still, I did not find that the examples after the first improvement got any better. To me, "more readable code" is not necessarily "shorter code" and - again - I am not very familiar with JS, but your final result is not very readable to me. You abstract away code in a const, and I am an advocate of doing that but these constructs are so small that I find it gains little. Personally I would have stopped after the first improvement. Improving the code is good, but remember that better is the enemy of good enough ;)

For some of the people out there, this may not be a style they like. I also could have also went in to more detail as to why abstracting out the logic to constants can help clean up the code, with more scenarios. But for many people, they like this and it helped them. So it’s really about taking what works for you and leaving the rest behind.

Gotta admit, that does indeed look a hundred times more readable (assuming you're familiar with regular expressions).

I would just like to chime in on this line of code in the final example:

constdomain=hostnameAvailable?window.location.hostname:false;

I think it would be better if the fallback value was null instead of false. It doesn't change anything about the program, but semantically, null makes more sense because the variable domain expects a string value. If we were to stick with using false, then I don't think it makes sense that a domain name is a Boolean value. I think it would make more sense to say that it is null, or rather nonexistent.

But then again, I might just be nitpicking here. Nonetheless, it still is a hundred times more readable than the initial code.

On one hand, I feel ridiculous I have a function that will only run once.
On the other, there are no let bindings in the file.

I did consider Array.prototype.includes() but elected not to use it for just two elements.

I don't think the RegEx has good readability, especially having had to escape the dots.

I also noticed that you used === for comparing to "undefined" but == for the domain.

Is there a reason you are using hasOwnProperty instead of just the truthiness of the objects? Is it more performant?
Myself, in the process of writing this, I went back and changed it, and was happily surprised that

Doing a function is typically a sure thing. It's never stupid to abstract out to a function. It's a great habit to practice. Even if it only gets used once, you are completely right about it helping to avoid having to do things such as declaring additional variables and also making the assignment highly clear const secure = needsSecure() vs const secure = !isLocal;.

With the RexEx, that was more of an option to show others that you could bring in RegEx to do your checking. But you and others have pointed out, that my goal was to make the code more readable... so to a lot of people, it's hard to read so therefore it did not make the code "easier to read".

Far as strict comparison, vs non-strict. That is a bad habit I need to break. You caught me red-handed lol. Stick with using strict comparison, and only use non-strict as needed.

Now for the final part, hasOwnProperty is there for a good reason. I am wanting to specifically check for a Boolean answer, so hasOwnProperty will give me that. You can definitely do it your way and it'll work. When it's a single variable, that is how I do it.

When I'm digging down in to an object I prefer to be more intentional with it by using hasOwnProperty

It's actually really unclear how to do such checks, you have to keep in mind what failures you actually expect to have.
On one hand, if you expect an object, truthiness gets rid of null, undefined, false (we'd be getting the false from the typeof equality, as well as hasOwnProperty) as well as less importantly 0, and "".

But on the other hand, if you expect a number, you will have weird failure on 0, which is very commonly a normal number. In which case you often check for undefined.

constfn1=(num=1)=>num// How would we write this without default notation?constfn2=num=>num||1// NO, YOU DIE!constfn3=num=>(num===undefined?1:num)// it's okay to not use typeof x === "undefined" in this context, it's a declared argument.

Honestly, truthiness seems like the best bet to me, I just need to keep track of when it can be a 0 or "" or a literal significant false and it'll be okay.
I think I'll just keep using that.

>(undefined).potatoes//TypeError: Cannot read property 'potatoes' of undefined>(null).potatoes//TypeError: Cannot read property 'potatoes' of null>(true).potatoesundefined// And it will never be anything truthy on a non-object, right? RIGHT?>(true).valueOf[Function:valueOf]// OH GOD DAMMIT!!