Notes on Release, Build and CI Engineering

Integration engineer in a Java shop

Or some ramblings on the difference between the mindset of developers and integration engineers, based on a totally unscientific observation.

Some time ago I worked as a Build/CI Engineer in a Java development team. I came there with zero knowledge of the Java ecosystem. I had to learn a lot, including at least three kinds of Java garbage collection and how many brackets one needs to write a “Hello world”.

I have several favorite stories from those times, and this one is about how I untangled the mess of a Gradle the Java developers managed to create in their repository.

Development vs Integration

Let’s start with a question. Why was there a mess?

My answer to that is: they were senior experienced developers, but they were developers.

And a typical developer is driven by a desire to code things the way they want them to be. They have power, they have control, they have the ability to make things for themselves and no one should tell them how it should be done. At least theoretically. In their minds.

While Build/CI/Integration Engineers rarely ever see or use things coded the way they want them (I am looking at you, Jenkins).

Integration engineer's desire or, better to say, necessity is to use the pieces you are given and to adapt them to the environment you are forced into.

You don’t expect the environment to bend to your will. Which also often means you don’t feel especially bad, when it doesn’t. You find joy in building a puzzle, so that it fits.

DevOps vs SysAdmin vs User sidenote

I blame this development mindset as a main reason for the DevOps fever.

If you visit a DevOps conference, half of the talks there are about people writing a generic tool to manage all the other generic infrastructure management tools. There are rarely talks about how you used tools written by someone else. Because despite its best intent, DevOps culture put development on the top of the “food chain” and turned DevOps into an idea that every SysAdmin should write code now.

I often feel out of place in DevOps crowds, and I explicitly asked my management to change my title from a DevOps to a CI Engineer some years ago. Because I often want to cry out loud:

- We are supposed to be USERS!

Not the kind of users who are being mocked for not understanding the basics. But the users who are proud of mastering the tools and integrating them one into another and using them to solve real-world problems.

And yes, being a responsible, effective, collaborative and knowledgeable Professional User, who is able to learn and understand new tools, is a highly valuable and rare engineering skill.

Back to the story

There was me, Java developers, and a repository with 200 000 lines of Java code and 1000 lines of Gradle scripts.

Gradle is an opinionated build tool. It is supposed to be declarative, it is written in Groovy, but occasionally a build script can go as deep as to underlying Java factories of containers of abstract interfaces and things like that..

As every other build tool, Gradle is also a constant source of frustration for any development team.

On my team only one, the most senior, person was able to work with it. When he saw Gradle not doing something correctly he would write a Groovy function to do it the right way. And eventually he wrote about 1000 lines of Groovy code. And then he left.

Thus, when I joined there was no one to ask about the state of the build scripts, but there was also no authority to tell what should be done about them.

I opened the scripts and tried to read them.

100500 opened tabs of Gradle documentation and three months later, I realized that in those scripts we keep overriding some Groovy class methods to change the way we handle subcomponents and their dependencies. We redefine paths where to look for their configs, tests and versions. And we are doing it again and again in a build task, in a test task, in each of the helper tasks…

Instead of trying to refactor and generalize the code I did a very simple thing: I moved the java code of each component into a path, where Gradle expects it to be by design. I put tests in the default tests path and sources in the default source path as it is recommended by the Gradle documentation. And by doing that I cleared up the build scripts to somewhat 50 lines of the configuration data(name, owner, bugtracker url, this sort of thing) and exactly zero Groovy scripting. Apparently, once you put the files in places where Gradle expects them to be, you don’t need to tell it what to do anymore, it all just works out of the box.

The moral of the story

I almost hear a person reading this far and asking:

Wait, instead of configuring the build tool to take files from where they were, you changed the layout of the whole project?!

And yes, this is the point.

To use a tool effectively it is not enough to look into its documentation and learn how to configure what you want to configure. It is important to learn how the tool wants to be configured.

I am not a big fan of Gradle. I find Groovy annoying. I find the ability to reference the same variable by at least three different names confusing. Yet, if the choice has been made to use it to build a project, then I better adjust my project so that it is easier to use the tool. Unless I have a really good reason to fight it.

And it will save everyone a lot of trouble.