At FABERNOVEL, we develop mobile applications, so following our metaphor, we build cars every day. We must ensure that every change made does not affect the quality of our products. However, constantly testing our applications in every corner to check their stability and compliance with feature specifications is a very heavy workload. We have therefore put in place a set of rules and a verification system to ensure the consistency, stability and smooth operation of our systems.
I. Coherence, homogeneity and therefore scalability
In our example, the car construction project has taken shape: plans and design have been defined, as are the architecture and feature specifications for the mobile application.
A mobile application is considered maintainable if everyone can make changes without introducing bugs. The first step to guarantee this is to ensure that the code is consistent and uniform. If it follows the best practices, it will be more understandable by all teams involved and therefore more easily modifiable.
The code must therefore be:
- Easy to understand: changing a code which is not clear on its functioning will probably generate undesirable effects within our application (ie regressions). It can be avoided by for instance organizing the code properly or explicitly naming features and variables.
- Homogeneous: If it is never the same type of screw that is used to fix all the wheels of the car, every disassembly and reassembly will be long and tedious. It is the same for the development of a mobile application. We must ensure that standards such as coding style or code architecture are respected within a development team. These standards are not intended to format the code produced by a developer, but rather to provide a framework. They improve the understanding of the code and facilitate the integration of new developers or features within a project.
I.2 Static analysis
It must be ensured at each stage of the construction of the car that the assembly respects the set of rules.
Today, the assembly of cars is mostly performed by robots. Therefore, defined good practices cannot be transgressed. This is not the case for mobile applications, still developed by humans whose decisions influence the operation. If a new developer joins the team, he or she will not necessarily have in mind the established rules and may not respect the homogeneity of the project. One could possibly manually check that his or her work is in harmony with that performed on the project, but this would be very expensive.
At FABERNOVEL, we use static code analysis tools that allow us, to validate that every modification made on the project is compliant against objective rules that we have defined.
There are numerous rules which cover various areas such as:
- Pure code formatting (line breaks, indentation, dead code …)
- Choice of code patterns rather than others (use of variables or immutable objects …)
- The complexity of the code (length of functions, cyclomatic complexity …)
- The use of some frameworks
We are referring to static analysis because it does not check the functionality of our application, like a robot that verifies the type of screws used in the assembly of the car without checking that the screwed parts hold together.
I.3 The code review
The static analysis infallibly verifies that the code tested complies with the rules set defined by the team. However, some problems can not be detected using this analysis, such as code architecture issues. It is therefore important to introduce a human code-review process when developing the application. The process of code-review allows:
- To verify that the architecture of the code is correct
- To verify that the code is readable and understandable by another human than the one who wrote it (well-named elements, tidiness)
- To make a first functional review pass (= the code seems logical with regard to specifications)
To learn more about code-review at FABERNOVEL, we invite you to (re) read this article.
I.4 The scoreboard: Sonarqube
In a car, it is important to have a dashboard to get a feedback on user actions and their consequences, but also to display the status of the car’s systems. For example, it is difficult to realize that a variation in the level of tire pressure occurs if there is no warning at the dashboard.
This also applies to the best analysis tools. If they do not have a clear and precise display, they cannot be relied on to assess the health of the mobile application development project. That’s why at FABERNOVEL we use Sonarqube. This tool allows us to visualize metrics on our projects such as technical debt, code coverage or the complexity of the project. The technical debt is the time necessary to correct all the problems resulting from the non-respect of the defined rules ; code coverage is the ratio of lines of code covered by tests.
II. Test your application
A test has two objectives: to validate the functioning of a part of the system and to make sure that there is no regression throughout the development of the project (to avoid creating bug elsewhere while developing the application).
Imagine that we come to test the lights of your car. It would be extremely time-consuming to reconduct a test each time the electrical cables are moved, to ensure that the light is still operating. Even worse, if the the light ignition is not tested at each change on your car, and if at the end the light does not work, it will require to test everything from scratch to understand the cause of the problem. Today, there are systems that will diagnose the flow of current in the car’s electrical network and indicate on the dashboard the source of the problem.
There are similar verification systems in mobile development.
II.1 The right testing strategy
There are different types of tests in software development. The vocabulary associated with the tests may be different depending on the sources on which they are based. We have chosen the following categorization:
- Unit tests which will isolate part of the application and validate its operation. For example, we make sure that a light bulb works before integrating it into the structure of a car.
- Functional tests allow the validation of several bricks of our system in a perfectly known and « normal » context of usage (by reducing the dependencies to other systems; by mocking the interfaces …). In our case, we will test our car light connected to a reliable power source (an electrical outlet or a test battery).
- Integration tests allow the validation of a global feature. They are run in an integrated environment and have dependencies on other potentially unstable systems. For example, an integration test would validate the ignition or the switch-off of the car light after pressing the button on the dashboard.
- The user interface tests will test the robustness of the user interface against various formats and data lengths (long texts, emojis, large images, …).
Each type of test does not give the same level of information in case of success or failure. For example, a successful integration test can highlight the functioning of a part of the application. If it fails, identifying the source of the problem becomes difficult. On the other hand, if a unit test returns an error, it will be possible to determine exactly the cause of the problem. One must therefore choose a good test strategy to optimize the resources used.
The tests are very effective in maintaining the quality of a product. However, they can take a long time to set up and maintain. Mike Cohn in the book « Succeeding with Agile » describes an ideal strategy called the pyramid of tests.
The idea is to invest most of the time in unit tests, stabilizing the base of your pyramid as best as possible by validating one by one each operating brick. As a result, other types of tests will be more reliable because they use parts of your system whose viability will be validated by unit tests.
II.2 The case of mobile
It is often difficult to find time to set up tests. The pyramid of tests is the ideal strategy, but it requires a lot of resources. One must therefore necessary adapt the test strategy so that it really adds value to the reliability of the application.
Mobile applications are evolving softwares, especially with the new operating systems releases each year. That’s why we prefer unit tests and functional tests: unlike a test of integration, they allow us to know exactly the origin of a malfunction that would be induced by a modification of the application.
Most mobile applications retrieve data from a server to display them to the user. Mobile-server communication makes integration testing long and very sensitive: your integration test may fail because your server was unable to respond in the allotted time. In this case, your application may not have a bug, but the test still fails and you spend some time determining the source of the problem.
Integration tests are not used to make a system resistant to changes, but to validate the system functionality. Expensive to set up, we only use them to test the critical journeys of our applications. Furthermore, at FABERNOVEL TECHNOLOGIES we take advantage of the execution of these tests by both checking that our apps do not crash when browsing and by taking screenshots to verify the visual rendering.
III. Continuous integration
You now have all the systems so that any change made to your application does not affect its code consistency and functional stability.
Using again the car analogy, there is now a list of tasks to perform when one adds, deletes, or modifies something to make sure everything works.
The car is therefore more reliable, but its construction is much longer because of the time required to carry out the tests. One must find a way to automate those tasks.
At FABERNOVEL we use GIT to version our code, which allows to manage and order the different changes in the code. Via this system, any code is the increment of small successive unit modifications.
Each increment will trigger all or some of the verification tasks on our integration systems:
- Make sure the project folder is not cluttered with unnecessary files
- Update project dependencies
- Make sure the project compiles
- Run unit tests and user interface tests
- Run a static code analysis
- Upload the result of these analyzes on SonarQube
For those who are curious, here is the complete stack we used at FABERNOVEL:
- Gerrit: for the versioning of the code (and the code-review)
- Jenkins: for orchestrating different tasks and assigning them to available computers
- Fastlane: to define the test (or delivery) workflow. We have developed our own framework overlay to streamline processes between our different projects
- SonarQube / Slack: for viewing results
In conclusion, to achieve a sustainable product it is essential to build a stable base on which to serenely develop.
It is necessary to define rules, and then depending on your budget and your planning constraints, a test strategy (automated or manual) to ensure the stability of your product, which is one of the first criteria for users’ adoption.
Would you like to receive each week the new article to know all our secrets about a successful mobile application?Subscribe to our newsletter