Being a large open-source project, Inkscape relies on contributions from a wide collaborative community to develop its vector graphics application. As such, it is challenging to ensure that the desired quality attributes like functionality and correctness are sufficiently met.1 Inkscape does employ processes to ensure quality, like the use of test suites, adherence to coding standards, and continuous integration pipelines. Nonetheless, Inkscape leverages its large active user community to find and report bugs which are then tackled by developers. The developers use Rocket Chat to coordinate their work.2
In this essay, we explore the mentioned quality processes and their coverage, the overall quality culture, and accumulated technical debt of Inkscape.
Continuous Integration
Inkscape’s continuous integration is split into four pipelines: source documentation
, static analysis
, on push
, and on merge request
. The first two pipelines are scheduled to be executed once a week, while the remaining pipelines run when a developer pushes to a branch, or when two branches are merged via a merge request.
Each pipeline builds Inkscape on each of the supported platforms (Linux, MacOS, and Windows). It is built twice on Windows, once using a 32-bit compiler, and once using a 64-bit compiler. The Windows builds are performed on AppVeyor3 while all other jobs run on GitLab CI/CD4. The Windows builds are always performed last to reduce the number of builds on AppVeyor in case one of the other pipeline jobs fails.
The source documentation
pipeline, in addition to building Inkscape, generates source code documentation using Doxygen5, performs static analysis via clang-tidy6, and validates the translation files. After that, the documentation and static analysis results are deployed to the Inkscape documentation website7.
The static analysis
is a simplified version of the previous pipeline which skips the generation and deployment of the source code documentation. Instead, it just performs the static analysis and publishes its results.
The on push
pipeline, besides building Inkscape, runs several checks on the source code to ensure correctness and code quality. It verifies that all source files include a license header, performs static analysis, runs the unit tests, and checks whether none of the third-party source files were altered.
Finally, the on merge request
pipeline builds Inkscape, validates the translation files, and runs the unit tests to ensure that the changes made do not break the functionality of the master branch.
Testing
The focus of Inkscape is on the addition of features and usability, and thus usability testing8. This is mostly done through meetings between developers and users and discussed on Gitlab through merge requests and issues.
Other types of testing used to ensure the quality of Inkscape include performance, compliance, and unit testing9. Most important of these is the compliance testing, which is focused on compatibility with the SVG file format.
Test Coverage
Inkscape contains a total of 298 unit tests. Most of these tests (261 tests) directly interact with the command line interface. The remaining tests focus on utility functions (29 tests) and the rendering of SVG elements (8 tests).
Unfortunately, the test coverage is not tracked within the continuous integration, nor are there any automated tools included in the codebase to measure it. Instead, we followed the profiling instructions10 in combination with gcovr11 to analyze the source code. The coverage is shown in the table below.
Metric | Executed | Total | Coverage |
---|---|---|---|
Lines | 20950 | 170326 | 12.3 % |
Branches | 14809 | 255955 | 5.8 % |
As mentioned before, the focus of Inkscape is not on testing. However, we would suggest that future bug fixes and features come with at least one unit test each. This would not only improve the stability of the system, but also reduce future maintenance cost.
Hotspot components
Since the start of 2020, the number of contributions has decreased significantly, as can be seen in the figure below. This is due to the release of version 1.012 at the start of May 2020. Before that, however, the number of contributions were steadily rising, indicating the increasing popularity of Inkscape. By analyzing all these contributions, we identified hotspot components, which are defined as files in the codebase that are changed often.
The figures below were generated using Codescene.13
The largest hotspot component is the preferences dialog implementation, contained in the inkscape-preferences.cpp
file, which is the large red dot on the left in the figure above. The file is responsible for the look of the preference dialog that the user can open. It contains more than 2800 lines of code, most of which is code that is similar to the lines depicted in the figure below, where the options of the preference window are initialized. As the preferences are already categorized, an improvement would be to split the preferences file into separate files based on the categories.
Another hotspot is the selection-chemistry.cpp
file, which is the large red dot in the bottom right of the figure above. This file implements the functionality for doing operations on selected items (e.g. duplicating an item). A lot of different functionality exists for operations on selections, so this file has grown to be very large; containing about 3300 lines of code. A good improvement could be to try and find clusters of functionalities, and again group them together into separate files.
Code quality
Code quality determines the ease of understanding, writing, and maintaining code. At the most basic level, it includes maintaining a specific coding style14, and contributing instructions15; both of which are specified by the Inkscape community.
Inkscape uses clang-tidy for static analysis, which is also used in the CI pipeline. The generated bug summary reports dead assignments, logic errors, and memory errors. At the time of writing, a total of 375 bugs were found. Most of which were related to dead assignments, null pointers, and memory leaks.16
We can also quantitatively measure the code quality using metrics such as a function’s cyclomatic complexity and the percentage of comments. The cyclomatic complexity metric measures the number of execution paths through a function or method.17 With the help of a freeware SourceMonitor18 we found out the average complexity of Inkscape to be 4.48 which makes it low to medium complex19; a commendable value for such a large project. On the other hand, looking at the percentage of lines that are commented, Inkscape is found to be lacking. Using SourceMonitor, this value comes to be around 24%. Overall, we find Inkscape’s code quality to be good albeit with few areas needing improvement.
Quality culture
Inkscape has accumulated a total of 2260 issues and 2888 merge requests over the past three years since it migrated to Gitlab. Before its migration, it used a legacy bug management system20 where it had 3188 registered issues. The members of the Inkscape community take active part in discussing the issues and working on the important aspects of the related merge requests. However, the platform of discussion is not the integrated Gitlab chat. Most of the time, the discussion takes place in the Inkscape chat.21 And if the issue is important enough, the discussion is shifted to the weekly developer’s meeting.22
Unfortunately, this means that we cannot objectively analyze the quality of architectural discussion/code review that takes place before an issue is merged. Based on the limited data we have on the critical issues; it seems that the issues are often clearly discussed before being closed. Also, since we attended the developer’s meeting for the past three weeks, we can confirm that they are quite productive. The board members meet up with any active developer and take part in discussing the issues and present weekly summaries.
Citing an example, a primary issue23 where Inkscape was proposed to be converted into a native Mac OS application, had a lot of quality discussions in both the Gitlab chat and the developer chat24. The discussion and development period lasted for nearly 5 months before the issue was finally marked as resolved.
Technical Debt
Development of Inkscape began in 2003, and unsurprisingly the project is tied down to the decisions made over the course of 18 years. Instances of positive overhauls, such as the transition from using C to C++, show that Inkscape tried to keep their technology updated. However, residuals of the past software engineering decisions still remain. In this section we explore some of this technical debt.
Paradoxically, the strength of Inkscape’s dynamic vision to grow as per the community’s demands is also one of its potential weaknesses. Due to the inadequate up-front definition of the project’s long-term direction, development may begin without consideration of, yet unknown, future goals. Inkscape typically plans ahead for only one release, requiring future releases to redo previous work.
An important source of technical debt in Inkscape is the use of many tightly coupled components. As described in the previous essay, the main document consists of an XML tree which is very closely mapped to an Object tree. In such designs, any change in one component affects the other, and hence they are less suitable to change. The effort spent in maintaining such a design is high.25 Another issue with coupling is the extensive use of observers. These make it hard for any one component of the system to function individually. A solution would be to replace the observers with a publish-subscribe based design.26
The source code documentation of Inkscape can be significantly improved as well. Without ample documentation, it is difficult for further development to take place as contributors require more time and effort to understand the working of the project. This becomes especially apparent when it comes to the use of signals, which are sprinkled all over the codebase with little to no documentation. Inkscape uses Doxygen5 to extract documentation from the source code and generate graphs describing the program’s structure.
There is also no documentation describing the project’s architecture as Inkscape’s architecture described on their wiki page is outdated. The file structure of the source code does not always reflect the architecture of the application either. This issue is planned to be resolved in a future release, relieving some amount of technical debt.27
These issues leave developers unfamiliar with the system struggling to understand how it works, resulting in hindrance of future development.28
Conclusion
As a result of Inkscape’s long existence, a fair share of technical debt has accumulated. The developers have tried their best to keep up with time, for example by transitioning from C to C++. However, a large amount of technical debt is bound to always remain in such a large project. Some parts of the codebase might be hard to understand, but it is very impressive that a group of volunteers has managed to build and maintain such an extensive and ever-evolving project. This truly speaks to the capabilities and passion of the developers.
Appendix
Test Coverage Script
We wrote the following script to automate the generation of the code coverage report. We hope to contribute it, or a cross-platform variant of it, to the project such that, in the future, test coverage can be properly tracked.
#!/bin/sh
mkdir build
cd build
cmake -D"CMAKE_CXX_FLAGS=-g -O0 -Wall -fprofile-arcs -ftest-coverage" -D"CMAKE_C_FLAGS=-g -O0 -Wall -fprofile-arcs -ftest-coverage" ..
make -j $(grep -c ^processor /proc/cpuinfo) CFLAGS="-g -O0 -Wall -fprofile-arcs -ftest-coverage" CXXFLAGS="-g -O0 -Wall -fprofile-arcs -ftest-coverage"
make check
mkdir html
cd html
gcovr -j $(grep -c ^processor /proc/cpuinfo) --root ../src --object-directory ../build/src/CMakeFiles/inkscape_base.dir --exclude ../src/3rdparty --html-details coverage.html
-
Quality assurance in open-source systems - https://core.ac.uk/download/pdf/82302507.pdf ↩︎
-
Rocket chat - https://chat.inkscape.org/channel/inkscape_user ↩︎
-
App Veyor - https://www.appveyor.com/ ↩︎
-
GitLab CI - https://docs.gitlab.com/ee/ci/ ↩︎
-
Doxygen - https://www.doxygen.nl/ ↩︎
-
clang-tidy - https://clang.llvm.org/extra/clang-tidy/ ↩︎
-
Inkscape Doxygen generated documentation - https://inkscape.gitlab.io/inkscape/doxygen/ ↩︎
-
Usability testing - https://wiki.inkscape.org/wiki/index.php?title=UsabilityTesting ↩︎
-
Testing Inkscape - https://wiki.inkscape.org/wiki/index.php?title=Testing_Inkscape ↩︎
-
Inkscape profiling - https://wiki.inkscape.org/wiki/index.php/Profiling ↩︎
-
Version 1.0 release page - https://inkscape.org/release/inkscape-1.0/ ↩︎
-
Codescene - https://codescene.io/ ↩︎
-
Inkscape’s coding style - https://inkscape.org/develop/coding-style/ ↩︎
-
Inkscape contribution guidelines - https://gitlab.com/inkscape/inkscape/-/blob/master/CONTRIBUTING.md ↩︎
-
clang-build results - https://inkscape.gitlab.io/inkscape/scan-build/ ↩︎
-
Code Complete 2, Steve McConnel, Microsoft Press - https://www.oreilly.com/library/view/code-complete-second/0735619670/ ↩︎
-
Source Monitor, freeware code analyzer - http://www.campwoodsw.com/sourcemonitor.html ↩︎
-
Code complexity and clean code - https://www.brandonsavage.net/code-complexity-and-clean-code/ ↩︎
-
Inkscape legacy bug management tracker - https://inkscape.org/develop/bug-management/ ↩︎
-
Inkscape chat - https://chat.inkscape.org/channel/team_devel/ ↩︎
-
Inkscape developer’s meeting - https://inkscape.org/cals/event/1/ ↩︎
-
Gitlab chat regarding an important Inkscape issue - https://gitlab.com/inkscape/inkscape/-/issues/84 ↩︎
-
Developer chat regarding an important Inkscape issue - https://chat.inkscape.org/channel/team_devel?msg=524yPtCv7A9q7235B ↩︎
-
Imapact of coupling on technical debt - https://www.researchgate.net/publication/303830568_Technical_Debt_and_System_Architecture_The_Impact_of_Coupling_on_Defect-Related_Activity ↩︎
-
Publish-subscribe pattern - https://en.wikipedia.org/wiki/Publish%E2%80%93subscribe_pattern ↩︎
-
Future release plans - https://wiki.inkscape.org/wiki/index.php?title=Future_Architecture ↩︎
-
Technical debt - https://martinfowler.com/bliki/TechnicalDebt.html ↩︎