General Coding Guidelines

Posted on June 11, 2010

Andrzej Tuchołka Lead Code Architect

1. Names

Proper naming convention is crucial to achieve readability of the code. If you don’t create a proper name for the class/method/property, you can be sure that the next person trying to read your code will start asking stupid questions. Worst case scenario includes yourself analyzing your own source code and trying to figure out what you had in mind while writing this.

Remember, creation of naming convention is not only meant to increase code readability. It will ensure that the implementation is semantically correct and while the semantics match, our brains will be able to easily and intuitively understand the structures incorporated in the source code along with relations between different parts of the system. Also, when you switch the sides of this equation, you’ll be able to base on your speech analysis to define and check the correctness of the source code.

1.1. Good naming practices

You have to create names basing on the context in which the code is being implemented. This means that, you need to visualize a way the class, method or property names will be used and name them accordingly. Calls made using your names have to make sense in a semantical way. Also, since PHP is not handling namespaces, you need to carefully pick names that will fit both the design and that will be as much specific as possible (to prevent repetitions).

This is a list of things you need to have in mind while trying to come up with a good name for your code:

* Never repeat the class name in the names of it’s methods.
* Always write in English. If you don’t know the proper English word, consult the dictionary or a native English speaker, both you and the code will benefit from it.
* Name things precisely. If you can’t think of a precise name, you probably need to rethink code design.
* Avoid using more then 3 words to describe the subject. Again, if you can’t do that, you probably need to rethink code design.
* Class and property names have to be nouns and methods have to be verbs.
* In method names don’t be afraid to use prefixes (is, get, set) and suffixes (Max, Count, Value).
* When describing a collection of entities, always use plural, in all other cases use singular version.

A common misunderstanding arises, when developers derive the name of the subclass directly from its parent. It’s not a big issue, but decreases readibility of the source code and therefore is undesired. Imagine, that in the below example instead of naming the class “Message” we’d use “MessageDataObject?”. It doesn’t mean that you can’t reuse part of the parent class’ name in the child. Just think if it makes sense and another developer will know why did you have added a specific suffix/prefix to the class name. Remember, that class names should be self-sufficient and precise in describing the purpose of the class.

And above all remember: all names have to be descriptive and accurate in describing the purpose of the source code.

Examples:

class Message extends BasicDataObject {
    public function getTitle() {
// ...
    }
    private function isOffensive() {
// ...
    }
    private function getReceivers() {
// ...
    }
}

1.2. How to write a name

Always use camel caps to separate words in the name. Class names may only contain alphanumeric characters. Numbers are permitted in class names but are strongly discouraged. If you have a neat chance of using a "pro-abbreviation", skip it. Write all words capitalizing only the first letter.

For the first letter of code entity, different rules apply:

* Class names: first letter should be uppercase.
* Method names: first letter should be lowercase.
* Field names: first letter should be lowercase.
* Method arguments: first letter should be lowercase.
* Properties (virtual): first letter is assumed to be uppercase.

Examples:

class MessagePrinter extends BasicPrinter {
    private $messageToPrint;
    public function __construct(Message $message) {
        $this->messageToPrint = $message;
    }
    public function printTitle() {
// ...
    }
}

1.3. Exception: constants

All constants should be written using all caps. Words should be separated with underscore “_”.

Examples:

class MySqlConnection extends Connection {
    const ERROR_SERVER_CONNECTION = 0;
    const ERROR_DATABASE_CONNECTION = 1;
// ...

}

In case of constants defining rate limiting, their names should clearly indicate not only the subject of rate limiting, but also the boundaries. This should be acheived using suffixes in constant names. These suffixes include:

* …_PERCENT – meaning the scope is defined in range 0..100 with 0 meaning none and 100 all.
* …_PERMIL – meaning the scope is defined in range 0..1000 with 0 meaning none and 1000 all.

It is also expected that in constants you will use standard suffixes like:

* …_PER_HOUR, …_PER_MINUTE, …_PER_SECOND etc. – define constant number placed in time context
* …_PER_USER, …_PER_CONNECTION etc. – define a constant number placed in entity context

If you find a situation when you lack a standard suffix for this use, contact with the content owner to expand the list accordingly.

1.4. Literal values

Don't use them. Use named constants for any literal value other than obvious and special cases. Basically, you can check if an array has 0 elements by using the literal 0. But you should not assign a special meaning to a number and then use it everywhere as a literal. Also, accessing array value, you should use either a constant or a variable. The constants TRUE and FALSE should be used rather then literals 1 and 0. Typecast variables where it is needed, do not rely on the correct variable type (PHP is currently very loose on typecasting which can lead to security problems if a developer does not have a very close eye to it).

Examples:

class User {
    const EMPTY_PASSWORD = 0;
    const INVALID_PASSWORD = 1;
    public function setPassword($newPassword) {
        if (!empty($newPassword)) {
            $isPasswordValid = $this->checkPassword($newPassword);
            if ($isPasswordValid) {
// ...
            } else {
                throw >new CantChangePassword(self::INVALID_PASSWORD);
            }
        } else {
            throw >new CantChangePassword(self::EMPTY_PASSWORD);
        }
    }
}

1.5. Loop variables

In the most unlikely event, when you will be forced to define a “for” loop you should use variables i, j, k for consecutive loop levels. This kind of variables should also be applied when using loop indexing in while and do..while loops.

If you happen to get over 3 levels of loops, you should seriously reconsider your code design.

Examples:

// ...
    while ($i messagesCount) {
        $deletedMessageId = $this->deleteMessage($i);
        if ($deletedMessageId !== FALSE) {
            $this->log(sprintf(LANG_DELETED_MESSAGE_ID, $deletedMessageId));
            for ($j = 0; $j observersCount; ++$j) {
                $this->observers[$j]->refresh();
            }
        } else {
            $i++;
        }
    }
// ...

Due to the ease of exchanging for and foreach loops, it is required to:

* use foreach when keys or values that you’re going to iterate with are semantically meaningful
* use for when values have no other meaning then being the n-th item in the set

1.6. Standard names

Methods of the classes that will be written will have a set of similar prefixes and/or suffixes. It is important that they mean the same thing in the whole code and correspond to these definitions:

* assert… – defines an assertion method that will check the correctness of the concept that is being asserted. For example to assert that the variable $field actually contains a field. A call to the assertField($field) will break the execution if the value passed in the parameter is not a field. Assertions always throw exceptions on failure.
* assure… – defines a method that will validate and fix if neccesary the variable given by the parameter. It has to return a fixed value, or throw an exception if it is not possible to fix it. For example a call to assureFieldIsLoaded($field) should check if the field has all the data that can be loaded, if that is not the case load it and return a fixed $field variable.
* is… – performs the check on parameters and returns a TRUE / FALSE result. Does not throw any exceptions or break execution. Using above example, method isField($field) will return TRUE if the variable $field contains a valid field object and FALSE otherwise.
* get… – just make sure that the name actually corresponds to what is returned. For example if one needs an id of the user it can be either getUser()->getId() or getUserId().
* set… – just make sure that the name actually corresponds to what is being changed.
* can… – returns a boolean result with answer to a question asked in the method name. For example: canAddField($field) will return TRUE if the field can be added to the object.
* as… – this prefix should be followed by the type/class name that will define a format in which the data of the object will be returned. For example: asArray(), asString.
* from… – this prefix should be followed by the type/class name that will define an input format. Method will replace internal fields of the object basing on data provided to the method. Examples: fromArray, fromString.
* has… – method has to return a boolean result that will provide information if the object(usually representing a set) contains/has an item basing on a given search item type (shown in the 2nd part of the method name) is found for a given value (provided via a parameter).

You should also join prefixes into forms like getBy…, getFrom… etc.

1.7. Directory names

Folder names should ideally contain only one word, but in case it’s impossible use “-” to separate the words in the name.

2. Coding practices

2.1. Scoping variables

Both, the effectiveness and readability of the source code requires developers to use proper variables handling in their source code. Each of the variables has a lifespan defined within the scope of a method that defines it. As long as the class fields are tied into the existence of an object, the regular variables are tied into the methods they’re defined in. Defining a reasonably sized method (in terms of lines of code) also has a positive impact on the amount of memory used in each execution of the method.

The variable usage can and will overlap, but we can optimize this by moving parts of the code into separate private methods that will narrow the scope of availability of the value to the part where it is actually needed.

2.2. Lazy developer effect

Don’t be lazy writing the source code. Always make it complete in terms of error handling to the extent of your current knowledge. Actively fight the temptation of leaving something “as-is” and if you see a way of improving, do it. The benefit of this approach not only affects the source code, but also yourself. With time, the good practice will be an obvious thing to do from the beginning and your coding experience will be much more satisfactory.

2.3. Passing data through parameters

Do not use arrays to pass many parameters into a method. Instead of that, personalized collections should be implemented to handle groups of objects. If you need to define much more complex way of handling things within a method that requires to pass many input parameters to it, that means that you should define a specialized class to handle that kind of routines.

17 Responses to “General Coding Guidelines”

  • Iván Guardado
    June 14, 2010 at 12:51 pm

    I think there is a bug in the example:

    for ($j = 0; $j++; $j observersCount) {

  • Andrzej Tuchołka
    June 14, 2010 at 1:17 pm

    Damn typo. Fixed. Thanks =]

    I’ve always been a fan of open source bug tracking

  • Mariano
    June 15, 2010 at 6:31 pm

    I do not really know if this is the right place to say this. But I suggest you to deal with a bigger server.

    Tuenti has a lot of people and sometimes the server gets collapsed, so it stop working… its annoying.

    It would be great if you could make a migration to a bigger server. Even if this had to take a few days, at the end of all tuenti would be much more enjoyable.

    Best Regards

  • xOneca
    June 15, 2010 at 7:43 pm

    There seems to lack some “less than” simbol or so in the “Loop variables” example, both in the while and in the for.

  • Andrzej Tuchołka
    June 18, 2010 at 3:12 pm

    @xOneca: yeah :/ We need to get the WP configured correctly to display code snippets. This is also why I’ve put on hold posting the rest of our coding standards – 90% of the examples get broken even more making the content completely unreadable. Well… the wordpress is a bit broken but at least we’re pumping new features for the users :)

    Mariano: That’s the best thing I might have read on friday :D Thanks for that tip, I’ll make sure to forward it to the systems team for you! =]

  • Pacovi
    June 19, 2010 at 12:58 pm

    I’ve been searching the way to leave an opinion about a feature that I think that’s important about security issues, but I haven’t found a better way to contact.

    I suppose that developers have already think about this, but it’ll be a great improvement to the site if users could access tuenti via https instead of using plain http. Sometimes people uses their phones or a not secure wifi to access and it’ll be a great improvement in security.

  • pepe Moreno
    June 21, 2010 at 1:39 am

    hi guys, i would highly recomend that you work on making tuenti more compatible with mozilla firefox as a lot of spanierds use it and at the moment most of your buttons, icons and images are not displayed

  • Paul
    June 21, 2010 at 10:15 am

    Witam.

    Moglibyscie zrobic social slider, taki jak ma np facebook.

    http://wiki.developers.facebook.com/index.php/FBJS/Examples/Slider

  • J. Javier Maestro
    June 22, 2010 at 10:24 am

    @Mariano I feel your pain. Rest assured, we will upgrade our server from the current 2GB of RAM to a more appropriate 4GB. I am sure this will speed the user experience by an awesomeness factor of at least 11. Many thanks for your suggestion!

  • bisho
    June 22, 2010 at 10:36 am

    @Mariano: Maestro was joking. Tuenti is BIG. We have *hundreds* of servers dedicated to the service. We constantly improve our servers and add new ones to production without any downtime, we have 24/7 service and we try to keep 100% uptime.

    If you have problems, please contact with user support and give details about your issues. This is definitely not a mater of upgrading a server!!!

  • Andrzej Tuchołka
    June 22, 2010 at 10:38 am

    @Pacovi: yes, we are constantly thinking about it. Unfortunatelly there are quite a few issues with ssl working on this scale. There are few aspects to that (you probably didn’t notice, but tuenti is using ssl for authentication) but it is problematic especially for phones and devices with less computing power and high latency on connections.

    @Pepe: yes. Quite a few people on our team use FF. Well… most of them. =] The thing you’re experiencing is probably some just a statics cache hicckup. It shouldn’t happen but I’m sure that it’s not FF only. We love FF.

    @Paul: Pewnie =] Najpierw jednak musi powstac efektywny system integracji z innymi stronami.

  • Antonio de la Iglesia
    July 4, 2010 at 10:55 am

    When do you plan to launch a public API?

  • Andrzej Tuchołka
    July 15, 2010 at 1:31 pm

    There are no plans related with it so far. :(

    We are discussing this topic for approximately a year now but for different business related reasons it’s still not planned for implementation/release.

  • Jonathan Kingston-Fear
    July 22, 2010 at 11:48 am

    0.1 Indent your code!
    0.2 Indent your code!

    It might sound basic to you guys, but as I often have to work with code that people I have never met have written and then extend it, the most frustrating thing is when you want to do something simple and you have to figure out dozens of lines of inappropriately indented “if” statements (especially when a switch would have been more appropriate!) inside another “if” statement, inside a loop, inside function, inside a class!

    Good post!

    P.S. @pepe — if you think tuenti can sometimes be unpredictable in Firefox then you have obviously not even tried using it in Chrome – I regularly find myself clearing cache and logging in again or manually pasting the URL into the address bar to get certain pages to load…

  • Andrzej Tuchołka
    July 26, 2010 at 2:27 pm

    Jonathan, I couldn’t agree more.

    We do have the aligning/indenting rules set but inside the Coding Standards for each of the technologies.
    We’ll be publishing them when this annoying problem with code formatting is fixed (should be done by now afaik, or maybe it’s fixed, but the posts need to be updated… I’ll check in a free minute).

  • Geert Leerentveld
    July 28, 2010 at 2:37 pm

    How is it possible to get access to your API? Do we need to sign up as a partner first?

    Any info would be great!

  • Andrzej Tuchołka
    July 30, 2010 at 10:42 am

    Yes, it’s accessible only for our partners afaik.

Leave a Reply

  • (required)
  • will not be published (required)