Another very informative blog taken from http://net.tutsplus.com/tutorials/tools-and-tips/20-all-too-common-coding-pitfalls-for-beginners/
JavaScript
Tips
1
- Unnecessary DOM
Manipulation
The DOM is slow. Limiting your interaction with it will greatly
increase your code’s performance. Consider the following (bad) code:
|
1
2
3
4
5
|
// anti-pattern
for (var i = 0; i < 100; i++){
var li =
$("<li>").html("This is list item #" + (i+1));
$("#someUL").append(li);
}
|
This code actually modifies the
DOM 100 times, and unnecessarily creates 100 jQuery objects. 100! A more
correct approach would be to either use a document fragment, or build up a
string that contains the 100<li/> elements, and then appends that HTML to the containing
element. That way, you jump into the DOM a total of once. Here’s an example:
|
1
2
3
4
5
|
var liststring = "";
for (var i = 100; i > 0; i--){
liststring += "<li>This
is list item #" + (99- i);
}
document.getElementById("someUL").innerHTML(liststring);
|
As noted above, with this technique, we touch the DOM only once,
which is an improvement, but it also relies on string concatenation to build a
large string. There’s a different way that we could approach this, using
arrays.
|
1
2
3
4
5
6
7
|
var liststring = "<li>"
var lis = [];
for (var i = 100; i > 0; i--){
lis.push("This is list item
#" + (99- i));
}
liststring +=
lis.join("</li><li>") + "</li>";
document.getElementById("someUL").innerHTML(liststring);
|
When building large strings, storing each piece of the string as
an item within an array element and callingjoin() is more efficient
than string concatenation. This is one of the fastest and easiest ways to build
repetitive HTML in JavaScript without using a template library or framework.
2
- Inconsistent Variable
& Function Names in JavaScript
This next item isn’t a performance issue, but is extremely
important – especially if you are working on code that other people work on, as
well. Keep your identifiers (variable and function names) consistent. Consider
the following variables as an example:
|
1
2
3
|
var foo = "bar";
var plant = "green";
var car = "red";
|
It wouldn’t make sense to add another variable, called Something. This introduces
inconsistency in your variable naming pattern, causing your brain to
cognitively flag this variable as being different or special. This is why
constants in most languages are traditionally defined with all caps.
You can take this a step further by maintaining similar length,
grammatical structure, and explanatory nature when naming functions. For
example, consider the following contrived function:
|
1
2
3
|
function subtractFive(number){
return number - 5;
}
|
Naming a function that adds five to a given number should follow
the same pattern, shown here:
|
1
2
3
|
function addFive(number){
return number + 5;
}
|
Sometimes, you might name a function to indicate its return
value. For instance, you might name a function that returns an HTML string getTweetHTML(). You might also prepend
a function’s name with do, if the function simply performs an operation and doesn’t
return a value, eg: doFetchTweets().
Constructor functions typically follow the tradition of classes
in other languages, capitalizing the first letter:
|
1
2
3
|
function Dog(color){
this.color = color;
}
|
As a general rule of thumb, you should be descriptive when
naming your identifiers. Classify them together with other similar identifiers
by maintaining a naming pattern that is readable and offers hints to the nature
of a variable or function’s purpose.
3
- Use hasOwnProperty() in for...in Loops
JavaScript’s arrays are not associative; trying to use them as
such is frowned upon by the community. Objects, on the other hand, can be
treated as hash tables, and you can iterate over an object’s properties by
using the for...in loop, like so:
|
1
2
3
|
for (var prop in someObject) {
alert(someObject[prop]); // alert's
value of property
}
|
The problem, however, is that the for...in loop iterates over
every enumerable property on the object’s prototype chain. This can be
problematic if you only want to use the properties that exist on the actual
object.
You can solve this issue by using the hasOwnProperty() method. Here’s an
example:
|
1
2
3
4
5
|
for (var prop in someObject) {
if (someObject.hasOwnProperty(prop))
{
alert(someObject[prop]); // alert's
value of property
}
}
|
This version only alerts the values of the properties that
directly reside on someObject.
4
- Comparing Boolean Values
Comparing boolean values in a condition is a waste of
computation time. Take a look at the following for an example:
|
1
2
3
4
5
|
if (foo == true) {
// do something for true
} else {
// do something for false
}
|
Notice the condition: foo == true. The comparison of foo and true is unnecessary
because foo is already a
boolean value (or it’s a truthy or falsey one). Instead of comparing foo, simply use it as the
condition, like this:
|
1
2
3
4
5
|
if (foo) {
// do something for true
} else {
// do something for false
}
|
To test for false, use the logical NOT
operator, as shown below:
|
1
2
3
4
5
|
if (!foo) {
// do something if foo is false
} else {
// do something if foo is true
}
|
5
- Event Binding
Events are a complicated subject in JavaScript. Gone are the
days of inline onclick event handlers (except in some very rare “splash page”
cases). Instead, use event bubbling and delegation.
Let’s imagine that you have a grid of pictures that need to
launch a modal lightbox window. Here’s what youshouldn’t do.
Note: we’re using jQuery here, assuming you are using a similar library. If
not, the same bubbling principles also apply to vanilla JavaScript.
The relevant HTML:
|
1
2
3
4
5
6
|
<div id="grid-container">
<a href="someimage.jpg"><img
src="someimage-thumb.jpg"></a>
<a href="someimage.jpg"><img
src="someimage-thumb.jpg"></a>
<a href="someimage.jpg"><img
src="someimage-thumb.jpg"></a>
...
</div>
|
The (bad) JavaScript:
|
1
2
3
|
$('a').on('click', function() {
callLightbox(this);
});
|
This code assumes that calling the lightbox involves passing an
anchor element that references the full size image. Instead of binding to each
anchor element, bind to the #grid-container element instead.
|
1
2
3
|
$("#grid-container").on("click",
"a", function(event) {
callLightbox(event.target);
});
|
In this code, both this and event.target refer to the
anchor element. You can use this same technique with any parent element. Just
make sure to define the element that should be the event’s target.
6
- Avoid Ternary Redundancy
The overuse of ternary statements is quite common both in
JavaScript and PHP.
|
1
2
|
// javascript
return foo.toString() !== "" ?
true : false;
|
|
1
2
|
// php
return (something()) ? true : false;
|
A condition expression always returns a true or false value, meaning you
don’t need to explicitly addtrue/false as ternary values. Instead, you could simply return the
condition:
|
1
2
|
// javascript
return foo.toString() !== "";
|
|
1
2
|
// php
return something();
|
PHP Tips
7
- Use Ternary When
Appropriate
if...else statements are a central part of most languages. But doing
something simple, such as assigning a value to a variable based upon a
condition – well, they can junk up your code. Consider the following code:
|
1
2
3
4
5
6
7
8
|
if ($greeting)
{
$post->message = 'Hello';
}
else
{
$post->message = 'Goodbye';
}
|
This code can be reduced to one line, while still maintaining
readability by using the ternary operator, like this:
|
1
|
$post->message = $greeting ? 'Hello' :
'Goodbye';
|
It’s clear, concise, and gives you the functionality you need.
8
- Throw Exceptions Instead
of Inception-Style Nesting
Let’s face it: many levels of nesting is ugly and difficult to
maintain/read. The following code is a relatively simplified example, but they
get much worse over time:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
// anti-pattern
$error_message = null;
if ($this->form_validation->run())
{
if ($this->upload->do_upload())
{
$image =
$this->upload->get_info();
if ( !
$this->image->create_thumbnail($image['file_name'], 300, 150))
{
$error_message = 'There was an error
creating the thumbnail.';
}
}
else
{
$error_message = 'There was an error
uploading the image.';
}
}
else
{
$error_message =
$this->form_validation->error_string();
}
// Show error messages
if ($error_message !== null)
{
$this->load->view('form',
array(
'error' => $error_message,
));
}
// Save the page
else
{
$some_data['image'] =
$image['file_name'];
$this->some_model->save($some_data);
}
|
That’s some nasty code, but you can make it drastically cleaner
by using exceptions, like so:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
try
{
if ( !
$this->form_validation->run())
{
throw new Exception($this->form_validation->error_string());
}
if ( !
$this->upload->do_upload())
{
throw new Exception('There was an
error uploading the image.');
}
$image =
$this->upload->get_info();
if ( !
$this->image->create_thumbnail($image['file_name'], 300, 150))
{
throw new Exception('There was an
error creating the thumbnail.');
}
}
// Show error messages
catch (Exception $e)
{
$this->load->view('form',
array(
'error' => $e->getMessage(),
));
// Stop method execution with
return, or use exit
return;
}
// Got this far, must not have any trouble
$some_data['image'] = $image['file_name'];
$this->some_model->save($some_data);
|
It might be the same number of lines, but it allows for
considerably more readable and maintainable code. It also avoids those
difficult debugging sessions, where you’ve missed a possible path through the ifstatement. Keep it
simple!
9 - False-Happy Methods
Ruby or Python developers are used to watching for trivial
exceptions. While that sound tedious, it’s actually quite a good thing. If
anything goes wrong, an exception is thrown, and you instantly know where the
problem is.
In PHP – and especially when using older frameworks,
such as CodeIgniter – you get what I refer to as “false-happy code” (as opposed
to exception-happy). Instead of having an exception get all up in your face, it
just returns a false value
and assigns the error string to some other property. This forces you to fish it
out of the class using a get_error(); method.
Being exception-happy is far more advantageous than
being false-happy. If an error occurs within your code (eg: could not connect
to S3 to upload an image, or a value is empty, etc.), then throw an exception.
You can also throw specific types of exceptions by extending the Exception class,
like so:
|
1
|
class CustomException extends Exception {}
|
Throwing a custom exception makes debugging considerably easier.
Tip
10 - Use Guard Clauses
It’s common to use if statements to
control a function or method’s execution path. It’s tempting to test a
condition and execute a lot of code when the condition results in true, only to simply return
in the elsestatement. For example:
|
1
2
3
4
5
6
7
8
|
function someFunction($param) {
if ($param == 'OK') {
$this->doSomething();
return true;
} else {
return false;
}
}
|
This kind of solution, however, represents a potential for
spaghetti code. You can make this code easier to read by reversing the
condition. Here’s the better version:
|
1
2
3
4
5
|
function someFunction($param) {
if ($param != 'OK') return false;
$this->doSomething();
return true;
}
|
Isn’t that easier to read? It’s a simple change that makes a
drastic difference in the readability
of your code.
Tip
11 – Use while for Simple
Iterations
The for loop is commonly used when you need, for example, a
counter. Here’s a simple for loop:
|
1
2
3
|
for (var i = 0; i < x; i++) {
...
}
|
There are some very good reasons to use a for loop, but a while loop may be better
if you just need something simple, like this:
|
1
2
3
4
|
var i = x;
while (i--) {
...
}
|
It doesn’t work in every situation, but it is an alternative.
Tip 12 – Keep Methods Maintainable
A
method is an object’s unit of work, and limiting your methods to a maintainable
size makes your code easier to read and maintain. Take a look at the following
monster method:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
class SomeClass {
function monsterMethod() {
if($weArePilots) {
$this->goAndDressUp();
$this->washYourTeeth();
$this->cleanYourWeapon();
$this->takeYourHelmet();
if($this->helmetDoesNotFit())
$this->takeAHat();
else
$this->installHelmet();
$this->chekcYourKnife();
if($this->myAirplain() ==
"F22")
$this->goToArmyAirport();
else
$this->goToCivilianAirport();
$this->aim();
$this->prepare();
$this->fire();
}
}
}
|
Consider breaking this monster method into smaller, descriptive
chunks, each being responsible for performing one well-abstracted action. This
is easily one of the most frequent mistakes made by newcomers.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
class SomeClass {
function monsterMethod() {
if($weArePilots) {
$this->prepareYourself();
$this->tryHelmet();
$this->findYourAirport();
$this->fightEnemy();
}
}
private function prepareYourself() {
$this->goAndDressUp();
$this->washYourTeeth();
$this->cleanYourWeapon();
$this->chekcYourKnife();
}
private function tryHelmet() {
$this->takeYourHelmet();
if($this->helmetDoesNotFit())
$this->takeAHat();
else
$this->installHelmet();
}
private function findYourAirport() {
if($this->myAirplain() ==
"F22")
$this->goToArmyAirport();
else
$this->goToCivilianAirport();
}
private function fightEnemy() {
$this->aim();
$this->prepare();
$this->fire();
}
}
|
There we go: cleaner, and easier to debug!
Tip
13 - Avoid Deep Nesting
Too many levels of nesting makes code difficult to read and
maintain. Consider the following:
|
1
2
3
4
5
6
7
8
9
10
|
function doSomething() {
if ($someCondition) {
if ($someOtherCondition) {
if ($yetSomeOtherCondition) {
doSomethingSpecial();
}
doSomethingElse();
}
}
}
|
You can refer to Tip #10 to make this code easier to read by
reversing some of the conditions.
|
1
2
3
4
5
6
7
8
9
10
11
12
|
function doSomething() {
if (!$someCondition) {
return false;
}
if (!$someOtherCondition) {
return false;
}
if ($yetSomeOtherCondition) {
doSomethingSpecial();
}
doSomethingElse();
}
|
This code is considerably cleaner and produces the same results
as before.
When you find yourself with nested if statements,
closely examine your code; your method may be performing more than one task.
Here’s an example:
|
1
2
3
4
5
6
7
|
function someFunc() {
if($oneThing) {
$this->doSomething();
if($anotherThing)
$this->doSomethingElse();
}
}
|
In these cases, extract the nested methods into their own
method:
|
1
2
3
4
5
6
7
8
9
10
|
function someFunc() {
if($oneThing) {
$this->doSomething();
$this->doAnotherThing($anotherThing);
}
}
private doAnotherThing($anotherThing) {
if($anotherThing)
$this->doSomethingElse();
}
|
Tip
14 – Avoid Magic Numbers and
Strings
Magic numbers and strings are evil. Define variables or
constants with the values you want to use in your code.
Instead of this:
|
1
2
3
4
5
|
function someFunct() {
$this->order->set(23);
$this->order->addProduct('superComputer');
$this->shoppingList->add('superComputer');
}
|
Specify what those numbers and strings mean, and assign them to
a variable with a meaningful name, like this:
|
1
2
3
4
5
6
7
|
function someFunct() {
$orderId = 23;
$selectedProductName =
'superComputer';
$this->order->set($orderId);
$this->order->addProduct($selectedProductName);
$this->shoppingList->add($selectedProductName);
}
|
Tip
15 - Use Built-In Array
Functions
Use the built-in array functions instead of foreach().
Not Ideal:
|
1
2
3
|
foreach (&$myArray as $key =>$element)
{
if ($element > 5) unset
($myArray[$key]);
}
|
Better:
|
1
|
$myArray = array_filter($myArray, function ($element)
{ return $element <= 5;});
|
PHP offers a variety of array methods. They’re confusing at
first, but take a day and try to learn as many as possible.
Tip
16 - Don’t Overuse Variables
It’s easy to overuse variables, but remember that variables are
stored in memory. For every variable you create, the system needs to allocate
memory for that variable. Look at this code:
|
1
2
3
4
5
|
public function get_posts() {
$query =
$this->db->get('posts');
$result = $query->result();
return $result;
}
|
The $result variable isn’t necessary. The following code omits that
variable:
|
1
2
3
4
|
public function get_posts() {
$query =
$this->db->get('posts');
return $query->result();
}
|
The difference is subtle, but we were able to improve this
simple example. We kept the $query variable because it relates
to the database, while $result related more to our logic.
General
Programming Recommendations
Tip
17 - Rely on the Database
Engine
A database is designed for working with data; use its tools and
abilities to make your application more efficient.
For example, you can avoid redundant database
queries in many circumstances. Most plug-and-play user management scripts use
two queries for user registration: one to check whether the e-mail/username
already exists and another to actually add it to the database. A much better
approach is to set the username field to UNIQUE. You can then use native MySQL functions to check
whether or not the record was added to the database.
Tip 18: Properly Name Your Variables
The days of naming your variables x, y, z are
over (unless, of course, you’re dealing with a coordinate system). A variable
represents an important part of your logic. Don’t want to type a long name? Get
a better IDE. Modern IDEs auto-complete variable names in a blink of an eye.
Tip 19 - Methods Represent Actions
Name your methods with verbs representing the action they
perform. The main concept is the exact opposite of the variable naming scheme.
Use a short, but descriptive, name in a large scope (ie: public methods), and
use a longer and more detailed name in a short scope (ie: private / protected
methods). This helps make your code read like well written prose.
Also avoid any language other than English, when
naming your methods. It’s annoying to read function names like 做些什麼()
or делатьчтото() in your project. It may be impossible for other programmers to
understand your intent. While it might seem arrogant, for better or worse,
English is the adopted language of code. Try to use it, if we’re working on a
large team.
Tip 20: Structure Recommendations
Finally, code structure is just as important to
readability and maintainability as anything else we’ve talked about today. Here
are two recommendations:
·
Indent with four or two
space-width tabs. Anything more, such as eight spaces, is too much and will
make your code difficult to read.
·
Set a reasonable
line-width and respect it. Forty characters in a line? We’re not in the ’70s
any more; set your limit to 120 characters, put a mark on the screen, and force
yourself or your IDE to respect that limit. 120 characters gives you a nice
width without making you scroll.