Being Prepared for the Future
[The links to the project’s repo and the referenced gists have been updated.]
Software engineering is the part of software product delivery that is all but repetitious. It is about solving unique problems in unique ways. Although the same problem should never be solved a second time, we sometimes need to refine our problem definition to improve our solution. Not only should the puzzle be solved, it should also be solved within a certain time. This build-test-learn feedback loop leads to ever better solutions.
Although software engineering has nothing repetitious in it, software product delivery is a process of continuous repetition of the same tasks over and over again. The iterative approach to software development embraced by Scrum and other Agile methodologies yields the best results when repetition is applied consistently. Something that can be either achieved by the most meticulous and anal of engineering sticklers or by those that use automation to handle the job for them. I am not a meticulous anal engineering stickler, that I promise.
Before we can repeatedly improve our solution, a Phonebook application, we must improve the build system we created in episode one and two. We need to do this because our Phonebook will live on the Internet. Episode five, the episode you are currently reading will deliver that improvement.
The story thus far…
In previous episodes I covered the importance of setting up your build environment. Putting the focus on quality assurance as part of your automated process. The series uses the example of a Phonebook application, with very basic functionality. In the previous episodes I showed how applying Test Driven Development (TDD) and Behavior Driven Development (BDD) will lead to high quality code that meets all requirements and at the same time will save development time by limiting the amount of YAGNI code.
YAGNI : Ya Ain’t Gonna Need It
It has been a while since I published the first four episodes in this series. I will give you a brief overview of the previous episodes, with a link to those episodes. All source code for each of the articles is available on my Github account. I will provide a link at the end of this posts, as well as all the previous posts.
Since episode four the version of
Gradle has been updated to
JaCoCo Gradle plugin is updated to version
Cucumber has been updated to
jUnit updated to
5.6.2. All versions of dependencies are maintained outside of the
build.gradle file, in the file called
dependency_versions.properties. You will find all source code in my public Github repository.
Public Repository in support of the Medium article series by Arc-E-Tect on the development of software. This branch is…
With all history out of the way, onto the present where we prepare ourselves for the future. Scroll down for links to the previous episodes.
Here we go…
The application being developed, a phonebook, is simple and until now it has been kept as simple as possible. I will keep it that way, adding more features once the need arises. This makes sure that the effort put into the application will yield value to the user instead of just giving a good feeling because we kept ourselves busy.
The focus was on getting the foundation for our application engineered just right. Before I take the application to the web and extend its features, in order for it to become usable, there are just a few more bits and pieces that need to be in place. These bits are related to our use of Gradle.
The Gradle plugin versions was already added to the
build.gradle file in a previous episode. The reason for having this plugin in all my build files is that it provides me an easy and convenient way to keep up to date of all my dependencies from my build file.
Versioning in this episode is about tracking the version of the application itself. I always choose to follow Semantic Versioning as it encodes a lot of useful information in the version number of the application. Provided of course that you do it right. A great source on the topic can be found here:
Semantic versioning requires some discipline in how you maintain your software, but since we do software engineering the right way in this series, that should not be a problem.
There are a lot of plugins for Gradle supporting semantic versioning and after looking at a lot of them, I picked the plugin maintained by Joel Mongard. You can find the plugin on Github at his repository:
When thinking about using Open-Source Software (OSS) in your products, I always recommend to not only look at the functionality you will get from the framework, library or product but more importantly take a close look at how actively the software is maintained. Good metrics are the number of days since the most recent changes to the code, the number of maintainers of the project, the number of issues and responses to questions.
Because versioning is such an important aspect of the application, I spend a lot of time comparing the various plugins available. I settled on Joel Mongard’s plugin because it was simple in its use and it did exactly what I wanted it to do.
At the end of episode 4 of the series I showed that applying TDD and BDD will ensure that the quality of your code is very high. Not only because the application is tested at a behavioral level, which I think is way more significant then at a functional level, but also because all but one character of the written code is touched by the automated tests.
To make sure that quality is a trait of the software engineering practices is not a fluke, but something consistently infused into the product, it is important to track it over time. For this I use the plugin
Gradle-cucumber-reporting by SpacialCircumstances. The plugin can be found here:
The plugin will generate nice reports based on your Gherkin scenarios. It is not the only one of such reports. I am definitely planning to look at some other products. One its quality assurance aspects I find most useful is the trend-view. The plugin will generate a file with the results of your test-runs. This file is used to show over time how the quality of the product was tested.
The last plugin that is added to the build environment is called `Lombok`, which is a tool that will generate boilerplate code based on annotations in the source code.
Lombok will generate Getters and Setters for classes, as well as constructors, and methods such as
toString(). Just to give an impression of what the tool provides, look at this example from the Phonebook application:
My Integrated Development Environment (IDE) of choice (Jetbrains’ IntelliJ IdeaC) supports Lombok as well with a plugin, which provides the option to Delombok code, expanding annotations to the vanilla Java version. That is what I used to create the example above.
The complete documentation for Lombok can be found here:
With the build environment enriched with these three plugins for Gradle, it is time to clean-up the code.
Starting with the
Contact class, the boilerplate code is removed and instead we use the Lombok annotations
@ Data and
@ NonNull The
@ NonNullwill ensure that the field
phoneNumber cannot be
null, it results in the generation of a constructor taking a string as only argument, which is then assigned to the field
phoneNumber. That magic is realized through the
@ Data annotation, which will also generate all relevant Getters and Setters as well as a meaningful
Alternatively, and possibly more readable for those who are new to Lombok, the class can be annotated with
@ Getter ,
@ EqualsAndHashCode. You might be wondering why the
@ Setter annotation is not added to the list. This is because the field
phoneNumber is marked to be
final, so it cannot be changed and therefore a Setter would not make sense.
Next is the
build.gradle file itself. I like my build files to be modular. It makes life easier when it comes to maintaining the build environment, but more importantly, it allows me to re-use other build files more easily. Our
build.gradle file is currently still short and easy to comprehend, but as the application becomes more sophisticated our
build.gradle file will become more complex. And we will need to make choices where to put what in the file. For example, dependencies can be put almost anywhere in the
build.gradle file and you can have separate blocks containing dependencies. I almost always chose to add dependencies where they are needed instead of a large dependency block. And then I refactor my
build.gradle file and move these sections to separate files under the
Take a look at the Github project in the s01e05 branch, which contains the code for this episode. As you can see, I externalized the sections required for Cucumber support, the JaCoCo support, the jUnit support and the support for semantic versioning. These individual Gradle files are then applied to my `build.gradle` file.
Finally, I run SonarLint to scan the sources for known issues and of course fix them.
At this point, the project is in great shape to be used for some real software engineering done in the right way. There is still a lot to do, but going forward, all will be around building the application. And of course, making sure that the quality of our current version of the application is consistent.
Final check to be performed is running SonarLint to scan the source code without the need for SonarQube installed and as part of the build cycle. SonarLint integrates with the IDE. The Gradle plugin I use does the same but as part of the build. I want my application sources to be according to that best-practices in the industry, so the check of my build depends on the results of SonarLint’s scan action of the sources in Main.
Doing a final `Gradlew clean build dependencyUpdates` on the project after adding and configuring the plugins, I know that the application builds meets all requirements, is tested, has code coverage of 80% or more and the code adheres to the standards the rest of the world agrees are good ones to follow.
Time to push the new code to Github and tag it with a semantic version by running `gradlew releaseVersion`.
As always, the source code is available from this Github repository for free. Make sure you select the correct branch before you clone.
Public Repository in support of the Medium article series by Arc-E-Tect on the development of software. This branch is…
Episode One introduces you to the series. This episode is setting the scene and provides the baseline for this series’ project. A good read when you want to start from scratch and want to understand the reasons behind my tool selection.
Software Engineering Done Right
How to really apply common sense knowledge and principles
Episode Two covers Behavior Driven Development (BDD), a way of requirements specification, focusing less on functionality and more on the application’s behavior in certain use-case scenarios. This is the episode where I add BDD support to my build environment. Do not worry, I have updated all tools to current versions, even though the text may refer to older versions.
Benefits of Being a Software Vegetarian
Software Engineering Done Right Series— s01e02
Episode Three is about code coverage and explains the pros and cons of using code coverage to measure quality. This episode provides some recommendations on how to deal with low coverage of your code by tests. This is also the episode where the build environment is updated to include support for JaCoCo, a code coverage tool. Although the tooling has been updated in the source code, the text may still refer to older versions.
Episode Four is where it all comes together. Although the application is barely worth being called an ‘application’, it is advanced enough to validate that the build environment works as intended. It also shows that by applying TDD and BDD practices we get an application that behaves exactly the way we want it to, and that the amount of code written is exactly the code we need, no YAGNI. There is only one character in our code, a curly bracket, that is not covered by our tests.
On the go and done reading? Check out this continuing piece of pure fiction.
The text very explicitly communicates my own personal views, experiences and practices. Any similarities with the views, experiences and practices of any of my previous or current clients, customers or employers are strictly coincidental. This post is therefore my own, and I am the sole author of it and am the sole copyright holder of it.
Special thanks to my lovely wife Olcay, as well as my friend Sytse who took the time and made the effort to review my article. I am confident that the article’s quality was significantly improved by their feedback.