Keeping your code clean

Keeping your code clean - this is something that doesn’t always go hand in hand with programming, especially in a larger team where people can have different experience and code style preferences. You may ask "clean code - is it that important?". Believe me, it is.
The scenario is usually simple - there is a very important feature to implement, but there is also a very short deadline for it. Probably every programmer had such a situation in his career. Often, it ends with getting the job done with the intent of writing code that works but, sometimes it’s not as beautiful as you would want. But if you write dirty code, you are only incurring a debt to yourself, because you'll probably have to go back to it again. Now imagine that you’re coming back after a long time…
This post will show you a few quick tips for cleaner code and tools that can help maintain the same code style and avoid errors that can/will lead to less readable code.
LOC
You've probably heard that abbreviation multiple times in many articles and it's not new to you. This is repeated very frequently, but many programmers simply forget about it. It is also something that novice programmers do not pay much attention to. LOC means lines of code and it’s one of the metrics used to measure the size of a program. The fewer lines of code, the easier it is to read it. I think it is not a strange statement.
The main mistake is creating functions that have more than one purpose. If a function is too long, it is a sign that it probably has more than one purpose. Reading it can also cause a lot of problems. This of course also applies to the size of files - it is better not to overdo it.
Solution? Split functions into smaller ones and make sure that they’re not doing too much.
Correct Indentation
It seems that this is not so important - one space more or less, what's the difference? However, this is the first thing that stands out the most. In fact, this is a very important issue that strongly affects the readability of our code. Consider the following code that does not have any indentation:
extension Sequence where Element: Hashable {
func containsDuplicates() -> Bool {
var set = Set()
for element in self {
if !set.insert(element).inserted {
return true
}
}
return false
}
}
Doesn't it look terrible? Of course it does. This is quite an extreme case which you will probably never see, so let's look at another snippet that has indents, but they are missing in some places:
extension Sequence where Element: Hashable {
func containsDuplicates() -> Bool {
var set = Set()
for element in self {
if !set.insert(element).inserted {
return true
}
}
return false
}
}
It is not as tragic as before, but it’s still not perfect. Let's see a perfect version then.
extension Sequence where Element: Hashable {
func containsDuplicates() -> Bool {
var set = Set()
for element in self {
if !set.insert(element).inserted {
return true
}
}
return false
}
}
Do you see a difference? It's really important, so pay attention to your indentation habits!
Naming Standards
Another very important thing. Most projects are developed by teams consisting of more developers than just one, and this means that the code should be readable for everyone. When you create a variable or a function, you should give it a full name which will be descriptive enough to give a general idea of what it does. Never use only one letter in the name. It is better to spend more time on appropriate naming than on future redesigns.
Let’s consider the following simple function:
extension Date {
func add(_ v: Int) -> Date? {
var components = DateComponents()
components.day = v
return Calendar.current.date(byAdding: components, to: self)
}
}
This code is not readable at all and other developers definitely will not understand what this method does. Of course, you can add documentation to the code, but it's still not a good way out - the code itself should be readable. Let's try to do some refactoring.
extension Date {
func addDays(_ value: Int) -> Date? {
var dateComponents = DateComponents()
dateComponents.day = value
return Calendar.current.date(byAdding: dateComponents, to: self)
}
}
Isn't it much better now?
Variables/Methods Declaration
All variables and methods should be grouped according to access level - public methods and variables should be above those marked private. All variables in a class should be declared at the top of the class. Doing it this way will save you time scrolling over the whole class to find where it was declared.
Methods should also be declared in the same order as they are used - method A which calls method B shouldn't be below it.
Code Style
The last thing, and surely the hardest one - code style. Many developers have their own code style based on their experience, and it can not be clearly stated that a given style is the best and everyone should follow it.
One way to develop is to participate in open source projects, as well as to check the code of other programmers. The function you are working on at the moment has probably been implemented more than once. Of course, we are not talking about copying and pasting a ready solution, but about analyzing it and drawing conclusions. Maybe the solution has some drawbacks? Maybe you can offer something different? You can really learn a lot this way. It is also worth to check some Swift style guides - for example, from LinkedIn and Ray Wenderlich.
But what if you are taking care only of the clean code in your project? What if there are several programming styles in it? What to do to make the project consistent? How to make sure the whole team follows the same style? A lot of questions, but fortunately there is a solution - linting tools.
Linting Tools
I will not bore you with a typical definition of "lint" that you can read on Wikipedia, so I will explain it briefly - these are the tools that check your code in terms of programmatic and stylistic errors. They are very helpful in identifying common mistakes, but also in keeping a consistent code style. And now I will show you some linting tools that you can use in iOS projects.
SonarQube
SonarQube is an open-source web-based platform for continuous inspection of code quality that can be extended with open-source plugins. It supports more than 20 languages like Java, C/C++, Objective-C, C#, Swift, and many others. .
Sonar has a few metrics which cover a generous area of code quality:
- Reliability - Number of bugs
- Security - Number of vulnerabilities
- Maintainability - Number of code smells
- Coverage - Number of lines covered by the tests
- Duplications - Number of duplicated blocks of lines
- Size - Number of all files, classes, functions, and statements
- Complexity - Complexity calculated based on the number of paths through the code
At this moment Sonar has 116 rules for Swift, which are divided into four groups:
- Vulnerability - 4 rules
- Bug - 14 rules
- Security Hotspot - 1 rule
- Code Smell - 98 rules
They can also be grouped by severity:
SonarQube can be integrated with continuous integration systems, however the free version supports only a few languages and can be used with public repositories only. It has a web dashboard which can be easily shared and can be really helpful in a situation when you work on legacy code. You can use Sonar with a local or remote server and configure it by adding a sonar-project.properties file beside the .xcodeproj file to your Xcode project root folder. If you want to disable some rules, you’ll need to use a web dashboard and deactivate them there.
Conclusion
It’s a really great tool, however it requires a running server and we can’t integrate it with Xcode to see all errors during the implementation process. The free version only supports open-source projects.
Tailor
Tailor is an open-source cross-platform static analysis and lint tool for Swift. You can use this tool on macOS, Linux, and Windows. It analyzes your code to ensure that the Swift style and conventions are followed. It has 30 rules available and primarily uses the Java target of ANTLR. At this moment it has 1244 stars on Github and the last commit was on 6 December 2017.
Unlike SonarQube, you don’t need a server to run this tool. You can also integrate it with Xcode to get Tailor’s output within the Xcode Editor Area and in the Log Navigator. Installation is done by Homebrew. You can also generate a report in formats like HTML or JSON.
Configuration is done by adding a .tailor.yml file to the project root folder. You can include or exclude certain files and directories from analysis, enable and disable specific rules, as well as specify an output format or color scheme for the CLI.
Conclusion
Using a tool without a server and the possibility to integrate it with Xcode is a cool thing. It’s also very simple to customize by using a configuration file which can be placed in a repository. Doing it this way means that all developers in the project will be using the same configuration. The only downside is the small number of rules.
SwiftLint
This is probably the most well-known tool. It’s an open source project developed by the Realm team which you’ve probably already heard of. Right now it has more than 10,000 stars and 1,000 forks on GitHub. SwiftLint has 150 rules and it’s constantly being maintained.
Like Tailor, you can install this tool by using Homebrew as well as CocoaPods. Integration with Xcode is also possible. Configuration is also similar - you need to create a .swiftlint.yml file in the project root folder. You can disable or enable optional rules, add paths which should be included and excluded during linting, and configure some rules.
There are a lot of rules, but if you run out of something you can define your own in the configuration file. SwiftLint can also automatically correct certain violations and generate a report in different types.
Conclusion
A really great tool which has been maintained since April 2015. Probably the most famous linting tool in the Swift community. You can integrate it with Xcode and your continuous integration tool by using Homebrew or a dependency manager. There are a lot of rules and the possibility to create your own.
Why should we use this tools?
During implementation of the application we have a lot on our minds and we're not perfect - we make mistakes. But since there are tools that can prevent them, why not use them? It’s also good to have an established style in the project and the development team. It’s very useful to have a consistent codebase, especially when you work in a big iOS team.
Why establish your own set of rules? Here at Netguru we have a house style which all projects must follow. Thanks to this, the projects in which a tool is used are consistent and there are no problems when a new developer joins it. Every single build will correct your tiny mistakes and will inform you about all violations. Don’t be afraid and use one from the start of your project, and if it is already in progress, think about implementing one. Trust me, you will not regret it.