Great Coding Guidelines
A beginner’s guide to write code for next generations
Aurélien Deleusière – CF Camp 2012
©Aurélien Deleusière – CF Camp 2012
Who am I?
Based in Paris, France Software engineer specializing in web
technologies, development, architecture and troubleshooting
ColdFusion since 1998 Founder of Aurel&Co Involved into the French community And, yes, I’m supporting Railo
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Code for next generations
Think to the next generations of developers Think to yourself when you will have to get
back to your code later Think to your colleagues… it’s your
reputation…
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Think to the future
A working code is not enough… …it has to be robust and maintainable
Monday October 15th 2012
JUST A POINT OF VIEWBefore digging into best practices…
©Aurélien Deleusière – CF Camp 2012Monday October 15th
2012
©Aurélien Deleusière – CF Camp 2012
Readability or performances?
Both of course! But I would prefer a clean code than a fast
code Use performance mechanisms when possible
like mainly caching Always understand what you’re doing:
may this array can be huge one day?
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Mark’s CFML Myth BustersMonday October 15th
2012
©Aurélien Deleusière – CF Camp 2012
Mark’s CFML Myth Busters
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Mark’s CFML Myth Busters
Monday October 15th 2012
ART OF CODINGIn good hands,a few lines of CFML looks like poetry.
©Aurélien Deleusière – CF Camp 2012Monday October 15th
2012
©Aurélien Deleusière – CF Camp 2012
Less is more
Keep your code as simple as possible Use small functions, small files, small number
of arguments, small names… …small is beautiful Break down complex and large things to simple
and little tasks Once it works – and is tested - close your eyes
and be confident
Perfection is attained, not when no more can be added, but when no more can be removed.
Antoine de Saint Exupéry (1900 – 1944)
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Think before doing
Don’t rush on your keyboard!
Before writing, learn to think.What one understands, one expresses clearly.
Nicolas Boileau (1636-1711)
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Improve again and again
Improve your code each time you get back on it « Leave code better than you found it »
Anticipate: This function could do more… Consolidate: I’ve already seen this
somewhere… Do not duplicate code! But in any case: TEST, TEST and TEST!
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Other principles
Truth is always in source code Be curious Be confident
Do not hesitate to refactor, the only reason that should stop you is how difficult it is to test
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Languages mix
Don’t mix a logic across multiple language i.e. javascript, CFML and SQL
Keep the logic in one place
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Stealth coder
It’s not about which guidelines… …but have guidelines
When you go into a code is not yours, enter in stealth mode, mimic the style in place: Make impossible to identify you when others
read your code
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Tags or script?
Tags fit well with views Script with business code
You can only use tags, it’s your choice. You can only use scripts, it’s your choice…
…but never do that. Never.
Monday October 15th 2012
YOUR CODE HAS TO TELL A STORYMake it readable!
©Aurélien Deleusière – CF Camp 2012Monday October 15th
2012
©Aurélien Deleusière – CF Camp 2012
Coding style: be constant
Do or do not but do always the same way: to indent your code ‘ or “ ending slash for unary tags <cfabort /> spaces <cfset count = 0 /> void lines …
One style by language is a good choice
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Naming conventions
Clear name with meaning Boolean should begins with is or has (isBlue) About case:
Only object names should begin with an upper case Separate words with an upper case, avoid using the
old fashion “_”
public void function onApplicationStart() { application.physicalRoot = expandPath("/"); application.env = new model.utils.Env(cgi.server_name); application.sanitizer = new model.utils.Sanitizer(); application.cfTags = new model.utils.CFTags(); application.debug = false; ...}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Keep your code clean
Don’t leave garbage into your code<cfif 1 EQ 2>...</cfif>
Don’t comment code, remove it
You identify a portion to improve?use Eclipse tasks:
//TODO: This block needs to be refactored
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Comments
Do not overload your code with useless comment
<!--- init count to 0 ---><cfset count = 0 />
A comment is stronger when it is useful and frugal
application.proxy = {server = "",port = 80, // *MUST* be a numberuser = "",password = "”
};
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Comments
Avoid McDonald’s programming
// =======================================================// controllo esistenza fornitore su anagrafica q_fornitore = cfc_fornitori.GetAnagFornitore(idSocieta = my_idsocieta, idAnag = codFornitore, const = glb.const, dbprop = glb.dbprop); // =======================================================
// inserimento link fornitore linkfornitore = structNew(); linkfornitore.idSocieta = my_idsocieta;
//=======================================================if (q_fornitore.recordcount eq 0) { // inseriemnto tan030anagfornitori fornitore = structNew(); .....// =======================================================
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Variables scopping
Use every scope explicitly. Always Arguments, caller, query name, etc.
public Token function init(token) {variables.token = arguments.token;return this;
}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Variables declaration
Declare a variable where it’s used… avoid the old fashion of all the declaration on top (legacy from var scoping up to CF8)
public string function generate() {var i = 0;var token = "";for (; i <= 32 ; i++)
token &= chr(randRange(65, 90));
return hash(token, "MD5");}
public string function generate2() {var token = "";for (var i = 0 ; i <= 32 ; i++) {
token &= chr(randRange(65, 90));}
return hash(token, "MD5");}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Variables usage
Don’t use Magic Numbers. Never.
<cfswitch expression="#quoteRow.groupID#"><cfcase value="12">
<cfset quoteRow['isAnnual'][1] = "yes" /> </cfcase><cfcase value="13">
<cfset quoteRow['isAnnual'][1] = "yes" /> </cfcase><cfcase value="24">
<cfset quoteRow['isAnnual'][1] = "yes" /> </cfcase><cfcase value="25">
<cfset quoteRow['isAnnual'][1] = "no" /> </cfcase>
</cfswitch>
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Variables usage
Don’t use the pound sign where it is not needed
<cfset newColor = #oldColor# /><cfset newColor = "#oldColor#" />
But do instead:<cfset newColor = oldColor />
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Logic
if (isBlue == false) { ...}
Prefer:if (!isBlue) { ...}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Logic
if (!isBlue) { doThis();
} else {doThat();
}
Prefer avoiding “if not else”:if (isBlue) {
doThat();} else {
doThis();}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Logic
if (isBlue) { return true;
} else {return false;
}
Prefer:return isBlue;
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Logic
Parenthesis:if (isBlue || isRed && isSquare) {...}if (isBlue || (isRed && isSquare)) {...}
return variables.token == arguments.token;return (variables.token == arguments.token);
Order of variablesif ("blue" == color) { //don’t, use EQ?...}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Always use brackets
if (token.equals("1234"))writeOutput("ok");
elsewriteOutput("ko");
Prefer:if (token.equals("1234")) {
writeOutput("ok");} else {
writeOutput("ko");}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Exceptions
Exceptions allow you to focus on the useful code<cffunction name="login" access="public" returnType="boolean" output="false"> <cfargument name="username" type="string" required="yes" /> <cfargument name="hash" type="string" required="yes" />
<cfscript> try { var user = request.object.new("User").init(arguments.username); var hashServer = hash(session.token & user.getPassword(), "MD5");
if (hashServer == arguments.hash) { //connection successsession.user = user;user.lastLogon(username);return true;
}
var debug = "username=#user.getUsername()#<br>password=#user.getPassword()#<br>"; } catch (objectNotExistsException e) { var debug = "user not exists exception (#arguments.username#/#arguments.hash#)"; } catch (connectionFailedException e) { var debug = e.message & "<br>" & e.detail; } </cfscript>
<cfthrow type="loginFailedException” message="...” detail="#debug#" /></cffunction>
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Decoupling
Don’t make entities dependent on each others
<cfset colors = "blue,red,green,yellow" /><cfloop from="1" to="10" index="i">
<cfinclude template="sometemplate.cfm"></cfloop>
<!--- sometemplate.cfm ---><cfset i = 0><cfloop list="#colors#" index="lst">
<cfset i++ />...
</cfloop>
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
About readability
Principle: no dynamic value into the condition of a loop
for (i = 1 ; i <= arrayLen(items) ; i++) {...
}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
About readability
len = arrayLen(items);for (i = 1 ; i <= len ; i++) {
...}
Improvement: 0% to 5%
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
About readability
for (item in items) { // Railo and CF since 9.0.1...
}
Improvement: 10% to 15%
Monday October 15th 2012
A REAL WORLD EXAMPLEWe learn more from our mistakes
©Aurélien Deleusière – CF Camp 2012Monday October 15th
2012
©Aurélien Deleusière – CF Camp 2012
RequirementsMonday October 15th
2012
Control birth date: 60 days minimum Must be right with the age entered (previous
screen)
Original code
function isBirthDateValid(value,element) { var tmp = value.split("/"); if (tmp.length != 3) {return false;
} else { var month = tmp[1]-1; var year = tmp[2]; var day = tmp[0]; if (isValidDate(month,day,year) != true) { return false;
} else {return true; }}
}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
©Aurélien Deleusière – CF Camp 2012
Rewriting step 1
function isBirthDateValid(value,element) { var tmp = value.split("/");
if (tmp.length == 3) { var month = tmp[1]-1; var year = tmp[2]; var day = tmp[0]; if (isValidDate(month,day,year) != true) { return false;
} else {return true; }}
return false;}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Rewriting step 2
function isBirthDateValid(value,element) { var tmp = value.split("/");
if (tmp.length == 3) { var month = tmp[1]-1; var year = tmp[0]; var day = tmp[2];
return isValidDate(month,day,year); }
return false;}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Rewriting step 3
function isBirthDateValid(value, element) { var tmp = value.split("/");
if (tmp.length == 3) {var day = tmp[0];var month = tmp[1] - 1; //month start at 0 var year = tmp[2];
return isValidDate(month, day, year);}
return false;}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Final code
function isBirthDateValid(value, element) { try { var birthDate = $.datepicker.parseDate('dd/mm/yy', value);
if (birthDate.getAgeInDays() >= 60) {
// we retrieve the current id from ”birthDate_X”// to check the age against "age_X" var id = element.id.split('_').pop(); if (birthDate.getAge() == $('#age_' + id).val()) { return true; }
} } catch (e) {}
return false;}
Monday October 15th 2012
©Aurélien Deleusière – CF Camp 2012
Final code
Date.prototype.getAge = function() { var today = new Date(); var age = today.getFullYear() - this.getFullYear(); var monthes = today.getMonth() - this.getMonth(); var days = today.getDate() - this.getDate();
if (month < 0 || (monthes == 0 && days < 0)) { return age - 1; } else { return age; }};
Date.prototype.getAgeInDays = function() { var today = new Date(); return Math.floor((today - this) / 86400000); //ms to days (24*60*60*1000)};
Monday October 15th 2012
Thank you! Vielen Dank! Merci !@adeleusiere • aurelien.deleusiere.fr • cfml-france.com
Top Related