Coding Guidelines

General

The main reason of this document is to help to achieve a clean code, which is:

  • Readable: easily understandable – by other developers
  • Maintainable: easily changeable by other developers as well
  • Flexible: can be extended and add new functionality
  • Testable: can be unit testable – where other classes are mocked even if the classes are the part of the component or not. The test should cover at least a positive and a negative flow where the mock objects provide different results.

Design/architecture

  • One file – one class: it is very confusing if a file contains different classes. The project structure should mirror the class structure.
  • One class – one responsibility: each class has to have one specific concern. Do not create huge classes, which performs different tasks and stores different states.
  • Keep the class size fewer than 600 lines. If the lines exceed the limit it probably means the class performs to many tasks and should separate to more classes.
  • One method – one task: one simple task should be performed by a method
  • Keep the method size less than 60 lines or one screen size. Preferable is less. Much easier to overview a smaller method. Moving code to smaller methods makes the original method more readable, especially if you use descriptive names – and you should. The smaller methods are more reusable and maintainable as well and changing them can introduce fewer errors.
  • Different modules should not be referenced directly even if the module is part of the code or a third-party library. Direct references make harder (or impossible) the proper unit testing and also the possibility to vary the classes later. Declaring a clear minimumprotocol also helps the proper planning. If a module contains more classes the classes can depend on each other of course.
  • Accessing different modules: keep reference only to the objects you really have to.
  1. Use parameters: the most easier to test and provides the clearest architecture also the most understandable approach.
  2. Use properties to set the dependent instances.
  3. Use a public dedicated class (service locator), which provides the required instances (dedicated methods provide the instances of singletons or can behave like factories).
  4. Use singletons only if you’re don’t have any other option.

Naming

  • Use self-descriptive names. The name should suggest what the method does. Good names can institute simple comments. Avoid shortenings. Always think of the mind of a developer who doesn’t work on the project: will he/she understand what is that method/variable? What it does?
  • File names should be the same as the class names. Remember: one file, one class.

Coding

  • Keep the code clean (apply the guideline): don’t hesitate to change a code snippet when you change or add something if you see the result is not clear. Leaving small dirty code snippets results in an unmaintainable code.
  • Avoid code duplication: if the same code snippet should be copied to somewhere else always make a new method instead and call that from both parts. The code will be more readable, understandable, maintainable and smaller.
  • Separate queries (getters) from modifiers (setters). Always be clear what a method does: modifies the state of the class or retrieves a value. Do not mix them!
  • Do not use more than two (three) parameters for methods. If you really need more, consider passing a dedicated parameter object instead or use properties to set the desired values.
    Other option is to change the logic of that part of the code as these kinds of problem suggest there is too much to do.
  • Do not embed different method calls in each other. Limit it to one call for a parameter.
    Long lines mean something is wrong with the code. Setting local variables and passing them to the call make the code much clearer and easier to debug.
  • Do not use string literals or constant number values in the code. Use named constants instead. The constant numbers do not say too much about the purpose of the values but their names can do. This way all the key constants will be in one place so the changes are simpler and the readers of the code also have an overview of the magic numbers in the code.
    • use const strings instead of string literals: helps debugging as well
    • use enums, consts for constant numbers
    • Do not call long running operations from main thread. They will block the main thread where the user interaction happen and the application will seems to unresponsive sluggish.
      Network calls should run always on background thread.
    • Do not use exceptions to signal simple errors (especially from init methods): exceptions are for critical and/or developer errors. Return some default value (NULL/nil) or provide a returning error parameter.
    • Call property getter/setter accessors instead of access ivars directly. One can modify later the getter/setter to add additional logic or implement different behavior (for example lazy-binding, logging or debugging).

Comments

There are two types of comments regarding the target:

  • Public comments for the user who want to use the class: describe what the method does. Should be in the header file. Usually doxygen compatible comments should be used (for reference see: http://www.stack.nl/~dimitri/doxygen/docblocks.html)
  • Private comments for other developers who work on the code: describe how the method works. Always think you explain the code.
    Should be in the implementation file and use regular commenting

For comments keep in mind the following basic rules:

  • Place a file header comment in each file; the structure and look should be declared by the project.
    Usually the header contains the component/class name, author, company and other general information
  • Comment the class: give a clear description about the main concern of the class. If necessary describe how the class should be used even with code snippets if necessary
  • Comment each method/property
  • Use the single-line comment (//) in the code instead of multiple line comments (/* */).
  • For readability reason add a space after the comment sign: // a comment
  • Do not add doxygen like comments inside methods – these won’t be extracted and won’t appear in the generated documentation!
  • Do not leave commented code snippets in the code in long term. If it really needed to let the code in, describe why was it commented out, when can one uncomment it.
    Commented code blocks are meaningless and nobody knows after a time why that code was there or was commented out. Usually nobody will use that code part any more.

Spacing and Formatting

Can vary between projects but must be uniform in one project. Good practice to use the default formatting of the IDE/language.

 

iOS

General

Apple provides a clear documentation and guideline about coding: Coding Guidelines for Cocoa at https://developer.apple.com/library/mac/ – documentation/Cocoa/Conceptual/CodingGuidelines/CodingGuidelines.html.

As the apple guideline describes all aspects in a detailed way this document contains only the most frequent issues found in the existing code or where clarification was necessary.

In some circumstances it is possible to avoid some of these rules but always discuss it with the team lead.

Naming

  • Usually unnecessary to explicitly declare iVars (instance variable, a member) for properties, the compiler automatically creates them for you. Using the latest XCode you don’t have to specify the @sythesizes so the code will be more compact.
    The usage suggest you what is used: ‘self.myIvar’ a property, while an iVar (without the ‘self.’) would be ‘myIvar’ (@synthesize was used) or ‘_myIvar’ (@synthesize wasn’t used).
    If you really need an ivar for a property there is usually also a reason to distinguish the ivar name with a prefix or postfix.
  • Do not use and in method names for parameters, except if the method performs different actions (so the actions are delimited by the and, not the parameters):
    wrong: – (int)runModalForDirectory:(NSString *)path andFile:(NSString*)name andTypes:(NSArray *)fileTypes;
    better: – (int)runModalForDirectory:(NSString *)path file:(NSString *)name types:(NSArray *)fileTypes;
    different actions: – (BOOL)openFile:(NSString *)fullPath withApplication:(NSString *)appName andDeactivate:(BOOL)flag;
  • Do not use get in getter accessor names.
  • Class names and global shared constants should start with a short prefix, which is a unique abbreviation of the project or module, substituting namespaces what are missing in ObjC.
    For example: MAFLogonManager – Mobile Application Framework Logon Manager
  • File names should be the same as the class name except in case of categories. Category file names should start with the original class name followed by a ‘+’ sign and the name of the category. For example: NSString (Additions) category should be in a file named NSString+Additions
  • For singletons use the shared or default method name prefix for methods which provides the instance of the class
  • For parameter (and local variable) names use a prefix: aParam, anObject, theObject.
    This marks that the variable is temporary. Useful further if the parameter would have the same name as an ivar or property.

Coding

  • There must be at least one designated initializer, which calls the designated initXXX method of the superclass. The designated initializer must be the method with the most parameters. Always override the original designated initializers when you make a new subclass (introducing a new of overriding an existing initializer) to make sure your initializers will run and your class will be initialized properly.
    Good practice to call the designated initializer from other initializers in the same class.
  • Set the IBOutlet properties to nil in viewDidUnload to release the resources. The XCode generates the code for you this way (for example if you add a new referencing outlet).
  • Do not call accessors (setting to nil a property) from dealloc and always consider calling it from init…. Call release in dealloc and set the ivar directly in init.
    Subclasses can be already in invalid state (deallocated all iVars) when dealloc method of the super executes, making accessor methods potentially unreliable.
    A setter method may be doing more things than simply releasing the property. It also sends out KVO notifications automatically even if you implement the setter/getter manually. Even if you’re not implementing the setter yourself, a subclass might. In all cases it is not a good idea to run the related code from dealloc.
    Note: XCode generates the code for you this way for example if you add a new referencing outlet through interface builder.
  • Do not call release on the result of a property getter even if it was called on self.
  • Put private ivars in the implementation file.
    The header file is published like a protocol. The user of the object doesn’t have to know the inner structure of the class.
    @implementation MyViewController {
    int myIntIVar;
    }
  • Do not put private method and property declarations into the public header file. It makes the class structure unnecessarily complex and dangerous if someone starts to use them. Put them into a class extension instead (the compiler doesn’t force to declare private methods!).
    @interface MyViewController ()
    @property (nonatomic, copy) NSString *myPrivateProperty;
    @end
  •  Use the AppDelegate only for application level operations and events. Put other code to specific classes and ViewControllers. Keep the AppDelegate clean (refers to one class-one concern).

Common errors

  • Always consider the proper usage of property attributes.
    A property to an immutable class can always get a mutable instance. Use copy (instead of retain) if you want to make sure the data won’t change after the property was set. Mainly with strings and arrays.
  • For button taps use TouchUpInside instead of touchDown or other touches except if that is the requirement.
  • Don’t forget to implement viewDidUnload if you have viewDidLoad.
    If there is a memory warning the system releases the hidden views and calls viewDidUnload. When the view will appear again the system loads the view again and calls viewDidLoad. Without a viewDidUnLoad the application will leak.
  • Use the dot notation only for properties. Do not use them for parameterless methods.

Comments

  • Use #pragma mark to visually partition code, and add a short, meaningful description to the given block
    #pragma mark – Public method implementations
  • Use !!!, ???, TODO or FIXME in comments if you want to highlight something but don’t let them in for a long period.
  • In some cases you can use #warning or even #error in your code to signal special cases or avoid wrong usage of the code. Usually these are used in an #if or #ifdef condition.
  • If the project uses other libraries always cross-references them even if there must be a project, which uses the precompiled libraries.
    Cross-referenced libraries are easier to debug and the development of the libraries are also easier.
  • Using cross-referenced libraries all the bundles and used files should be referenced from the referenced projects (instead of using the built/maven version).
    Modifying the file (for example an xml in the bundle of the referenced library) will be visible right after the modification. Otherwise the library should be submitted to the repository wait for the build and update the files using maven or other tool.

Project settings

  • If the project uses other libraries always cross-references them even if there must be a project, which uses the precompiled libraries.
    Cross-referenced libraries are easier to debug and the development of the libraries are also easier.
  • Using cross-referenced libraries all the bundles and used files should be referenced from the referenced projects (instead of using the built/maven version).
    Modifying the file (for example an xml in the bundle of the referenced library) will be visible right after the modification. Otherwise the library should be submitted to the repository wait for the build and update the files using maven or other tool.