Table of Contents
- Why do we care? Most of out time is spent maintaining code.
- What is Maintainable code
- Code Style
- Programming Practices
- Automation (make everybody’s life easier)
- Summary
- More about Nicholas C. Zakas
Why do we care? Most of out time is spent maintaining code.
If you open an editor and:
- It’s blank – you are writing new code.
- Something already there – you are maintaining code.
Most of us learned JavaScript on our own and developed our own “best” practices
Maintainability = Developing as a Team
What is Maintainable code
Works for 5 years without having to rewrite
Maintainable code is:
- Intuitive – You look at it and it kind of makes sense.
- Understandable – If you look at something more complicated for a while, you can understand what it does.
- Adoptable – You want other people to be able to come in and make changes without feeling that the code is going to explode.
- Extendable – You can build on top of the existing code to do more things.
- Debug-able – Set up your code so somebody can step through it and figure out what it does.
- Testable – If you can write unit and functional tests, it will save you a lot of time.
Be Kind to Your Future Self!
Chris Eppstein, Creator of Compass
Code Style
Communicate with each other through the code – Programs are meant to be read by humans
Style guides
- Popular Style Guides
- Pick a style for the team and stick to it. (Don’t have everybody indent the code however they like etc.)
- Minimize amount of code per line – much less likely to have a merge conflict.
//Bad
if(found) { doSomething(); doSomethingElse();}
else { doMore(); doEvenMore();}
Code language: JavaScript (javascript)
- Best to space things out.
//Good
if(found) {
doSomething();
doSomethingElse();
} else {
doMore();
doEvenMore();
}
Code language: JavaScript (javascript)
Comments
- You shouldn’t have to read through entire file to understand what the code is doing.
- Not too many comments though, just like good seasoning in cooking – just the right amount.
At the very least:
- Add JaveDoc style comments at the top of each function.
/**
* A simple demo function that outputs some text
*
* @param {String} text The text that will be written to console
*/
function demoFunction(text) {
alert(text);
}
Code language: PHP (php)
- For a difficult to understand code.
switch(mode) {
case 1: //First Visit
doSomething();
break
case 2: //Every other visit
doSomethingElse():
break;
default:
doNothing();
}
Code language: JavaScript (javascript)
- Code that might seem wrong at a first look
while(element && (element = element[index])) { //Note: testing assignment, do not edit
doSomething();
}
Code language: JavaScript (javascript)
- Browser specific code (i.e. IE6 workaround)
- Make sure to add a comment, otherwise a helpful colleague will fix it for you ๐
Use logical names for your functions and variables
- Don’t worry about length, you can compress it during build process.
- Variable names should be nouns (i.e.
var book
). - Function names should begin with a verb (i.e.
getName()
). - Avoid names that have no meaning (i.e.
var a; function foo()
). - Use camel casing since
camelCasingIsTheJavascriptWay
. - For Constant-like variables use –
UPPER_CASE_WITH_UNDERSCORE
.
Programming Practices
There are two ways of constructing a software design: One way is to make it so simple that there are obviously no deficiencies, and the other way is to make it so complicated that there are no obvious deficiencies.
C.A.R Hoare, Quick-sort Developer
Keep Front Layer Separate
- CSS – Presentation
- JavaScript – Behavior
- HTML – Data/Structure
Rules of the road
- It is not intuitive to look for html code in javascript file, or for javascript code in html file
- Keep your JavaScript out of HTML
- Avoid
<button onclick="doSomething()">Click Me</button>
- Avoid
- Keep your HTML out of JavaScript
- Avoid
element.innerHTML = "<div class=\"popup\"></div>"
- Avoid
- Keep JavaScript out of CSS
- Use Templates!!!
Event Handlers should only handle events
- Bad Example
//The wrong way!!!
function handleClick(event){
var popup = document.getElementById("popup");
popup.style.left = event.clientX + "px";
popup.style.top = event.clientY + "px";
popup.className = "reveal";
}
Code language: JavaScript (javascript)
- Better Example – factor out function so it can be passed around and tested
//Better, but still wrong
function handleClick(event){
showPopup(event);
}
function showPopup(event){
var popup = document.getElementById("popup");
popup.style.left = event.clientX + "px";
popup.style.top = event.clientY + "px";
popup.className = "reveal";
}
Code language: JavaScript (javascript)
- Even better, don’t pass
event
object. Extract data that you need and pass that on to the function.
//Good
function handleClick(event){
showPopup(event.clientX, event.clientY);
}
function showPopup(x, y){
var popup = document.getElementById("popup");
popup.style.left = x + "px";
popup.style.top = y + "px";
popup.className = "reveal";
}
Code language: JavaScript (javascript)
Do Not modify objects that you do not own
//i.e. We extended
Number.prototype.toFoo = function() { return "bar" };
Number(1).toFoo(); //Returns "bar"
//2 months later, developers at Chrome decide to implement the same method as
Number.prototype.toFoo = function() { return "baz" };
//It may break your code. And even if you force it to work, you could have a new co-worker join your team
//who would expect Number(1).toFoo() to return "baz" and she will be very confused to see "bar" instead.
Code language: JavaScript (javascript)
- Modifying existing methods is bad
- Adding new methods is also bad. You don’t know what will happen in the future, what methods might be added to the original object.
Throw your own errors when you know functions will fail
- It’s like another note to self or other programmers, when things might be hard to figure out.
var Controller = {
addClass: function (element, className){
if(!element){
throw new Error("addClass: 1st argument missing");
}
element.className += " " + className;
}
}
Code language: JavaScript (javascript)
Avoid null comparisons, unless null value is specifically assigned
- Bad
function(items){
if(items != null){
items.sort();
}
//Will work with:
//var items = true;
//var items = 1;
//var items = "blah";
}
Code language: PHP (php)
- Better communicate your intention and prevent false positive with:
function(items){
if(items instanceof Array){
items.sort();
}
}
Code language: JavaScript (javascript)
- Use:
- instanceof to test for specific object types
object instanceof MyType
- typeof to test for primitive types
typeof value == "string"
- BEWARE typeof null == object
- instanceof to test for specific object types
Separate config data
- Bad – Need to factor out items that might change
function validate(value) {
if(!value){
alert("Invalid value");
location.href = "/errrors/invalid.php";
}
}
Code language: JavaScript (javascript)
- Keep items data away from your application logic.
var config = {
urls: {
invalid: "/errors/invalid.php"
},
strs: {
invalidmsg: "Invalid value"
}
};
function validate(value) {
if(!value){
alert(config.strs.invalidmsg);
location.href = config.urls.invalid;
}
}
Code language: JavaScript (javascript)
- When you change data, you shouldn’t have to re-run unit tests to make sure logic is still the same
- Items to factor out
- URLs
- All String displayed to user
- Any HTML that needs to be created from Javascript – use templates.
- Settings (i.e. Number of items per page)
- Unique values that are repeated multiple times
Automation (make everybody’s life easier)
Build process is magic
- Add/Remove debugging code
- Concatenate files
- Generate Documentation
- Validate Code
- Test Code
- Minify Files
- Deploy Files
Build tools
- js-build-tools – easy preprocessors. Supports:
// #ifdef debugEnabled
someFunction();
// #endif
Code language: JavaScript (javascript)
Documentation Tools
Linting
Compressors
Task Runners
- Ant (Note: Ant was probably a good advice back in 2012, but today I would just use Grunt)
- Grunt
Build types
- Development
- Add/Remove Debugging
- Validate Code
- Test Code
- Generate Documentation
- Testing
- Add/Remove Debugging
- Validate Code
- Test Code
- Concatenate files
- Minify Files
- Deployment
- Add/Remove Debugging
- Validate Code
- Test Code
- Concatenate files
- Minify Files
- Deploy Files
Summary
- Use style guidelines
- Loose coupling of layers makes changes and debugging easier
- Good programming practices allow for easier debugging
- Code organization and automation help to bring sanity to an otherwise crazy process
Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.
(Unknown)