comment 0

#30 Cyclomaticly Complex Settings View Controller

Simple screens evolve

In every project simple screens can happen. Let’s think for example of a simple Settings screen. Customer wanted a Settings screen on which a user would be able to Set Option 1 and 2 and to Logout from the application. It seemed so simple so developers used a UITableView with 1 section, hard-coded text displayed in cell and actions invoked directly from tableView(didSelectRowAtIndexPath:).

But it was ok, after all it was just three options, no big deal. When a few weeks passed by, customer came back and decided that the user has to be able to set another two options in the app and that all non-related options should be visually separated. So developers added those options and separated non-related ones by using multiple sections in a UITableView with .grouped style.


But developers used this long switch statement in many methods that dealt with tableView. They also had been using SwiftLint (a tool for code quality mentioned in issue #11 and issue #26) that indicated that their cyclomatic complexity limits for those methods were overreached.


Wait! Cyclo-what?!

Cyclomatic complexity

Documentation for codebeat (another tool for code quality assurance) mentioned by us in issue #10 has a great explanation of what cyclomatic complexity is:

The cyclomatic complexity of a section of source code is the number of linearly independent paths within it. For instance, if the source code contained no control flow statements (conditionals or decision points), such as if statements, the complexity would be 1, since there is only a single path through the code. If the code had one single-condition if statement, there would be two paths through the code: one where the if statement evaluates to true and another one where it evaluates to false, so complexity would be 2 for a single if statement with a single condition. Two nested single-condition ifs, or one if with two conditions, would produce a cyclomatic complexity of 4. (…)

OK, now when we know what cyclomatic complexity is, we can see some code and resolve its problems!

Cyclomaticly Complex Settings View Controller

So in the end, developers ended up with tableView(:cellForRowAtIndexPath:) method implementation that looked like this:

Their UITableView had 5 sections, 4 of them contained only 1 row and navigated to a different screen, 1 of them had 3 rows with different option to logout from the app.

The developers had set rigid cyclomatic complexity rule that will invoke a warning when the rule reaches 5 possible paths of execution through the method.

There is also tableView(:didSelectRowAtIndexPath:) method with high complexity. You can check this example project to see full source code.

Cyclomaticly Simple Settings View Controller

OK, but how can we design source code to resolve complexity issues?

This one simple trick can clean up our code and simplify complex methods. We can use a ViewModel struct to represent cell’s looks and behaviour.

For the Settings View Controller, the struct contains a name and an accessory indicator to be displayed in a cell. It also stores an action to be performed when user taps the cell. For first row in Settings View Controller we would write such a code:

Since method called in action closure is defined in Settings View Controller (self), there is a problem. First of all, a capture list has to be used. Secondly, we cannot construct let viewModel: [[ViewModel]] property before initialization of superclass, because the closure uses self.

To solve that problem, the property can be declared as fileprivate var viewModel: [[ViewModel]] = [] and filled with appropriate data after init of a superclass or in viewDidLoad() method:

Now implementation of tableView(:cellForRowAtIndexPath:) is as simple as that:

You can find full sample project here.

TL;DR;

Simple screens with naive implementation can grow fast through time and turn into complexity burden. It’s good to have a code quality guard to warn you by saying Fix it!. If you don’t have a clue how to fix an issue, ask your colleagues, switch your thinking from switch statement to some abstraction, watch Swift Talks and read blog posts to be more creative in problem solving!

References

Leave a Reply


*