If you work as Java-developer in a company, then you normally work together in a team with other developers. This collaboration requires common standards. Today, I would like to write about the challenges of consistent formatting of the source-code from several developers and even from different Java-IDEs.
Why consistent formatting rules?
The main reason is that source code has better readability within the team. Because you can rely on white spaces, line-breaks and parenthesisto be like you are used to. You can concentrate on the content and you are not distracted by an uncommon style.
Making code reviews and fixing merge conflicts gets easier, if you do not have to guess, if the changed line is based on a formatting change or if it is semantically changed code. A helpful method is to see your commit as a patch. Ask yourself: Could I simply pick the commit onto other branches? Would you pick formatting changes? No, you would not.
If you want to place your pull request, it is also common practise in open source projects to follow project specific formatting rules. The project owner only wants to see the real content change – not the irrelevant fuss around. If you don’t create a minimal change your pull request gets rejected or never gets reviewed. That is not what we want!
So common formatting rules save time and money in enterprise development and are even useful when contributing to open source.
How can we enforce formatting rules?
First you have to agree to a common formatting with your team members.
The trivial approach is to define the formatting: You document it the configuration in the company’s Wiki or project documentation via screenshot or via textual description. Then you define that every developer has to follow the defined rules and to configure his/her IDE. But in practice you forget to configure the one or other option. Or over the years the configuration weakens. The developers had configured it once and when mismatches occur they vow that they did not change the configuration since then. Does it remind you?
It gets even worse, when you have several customer projects with different formatting rules. So, switching between projects does not only interrupt your working-flow, it burdens you to fiddle around the configuration to keep aligned to the project settings. This is tedious, error prone and it reduces the time to do the real work. Before the check-in you wonder why are changes in lines you never touched.
The second evolution of this approach is to provide the options a configuration file, which the developer has to import. The configuration files can be provided as an attachment to the wiki page, or provided on a network-share or checked in into a SCM.
There are different approaches using the configuration-file-method. Let’s stay at the scenario, that every developer in the team uses the same IDE, for example Eclipse IDE from the Eclipse Foundation.
Collaboration with Eclipse IDEs
One approach is to commit all configuration files next to the source code. The whole workspace including the .metadatadirectory and the configuration files like .project/.classpath are checked in into the SCM. To my knowledge it is mostly used in legacy projects. This may work for you, if you do not check in configuration with file-paths or if every developer has the same installation of the IDE in the exactly same paths (e.g. provided by puppet). The configuration could also be recorded via Oomph Preference Recorder, persisted and synchronized to cloud services like Eclipse User Storage Service – see this article, part #4.
If you need a specific (plugin-)configuration for a customer project you could use especially packaged IDE-distributions. You can build those via Oomph or services like Yoxos, provide them as virtual machine images or check in the whole workspace incl. the IDE.
Collaboration with other Java-IDEs
The one and only IDE, which is capable of everything, does not exist. “The right tool for the right job” is the motto. Eclipse is still defacto standard – at least when coding Java. But Eclipse is not the only competitive IDE anymore. More and more developers are switching between their IDEs. Or new colleagues, who come into the team, do not want to switch their IDE and suffer from productivity losses. A small anecdote: I met some developers which have an Android-development background, which don’t want to switch to Eclipse only for Java coding. They prefer to stay in their accustomed IntelliJ IDEA ecosystem.
With the help of build tools like Maven and Gradle the build-process is already IDE-independent and self-contained. If the IDE does not support the build tool yet, at least the build can be invoked at command line.
But how about Java-IDEs? How can you synchronise code format between different IDEs?
The trivial imitation of formatter configuration by hand is too tedious and impractical. Every developer who wanted to switch his IDE tried that and failed more or less.
In JetBrains IntelliJ IDEA exists indeed a function to import Eclipse Formatter configuration files, but this does not guarantee 100% compatibility. IDEs have different formatting engines, which have specific quirks and cannot support all formatting features of the other IDEs. This is not my sole opinion but amongst others the opinion of JetBrains itself.
A senseless undertaking, isn’t it? But what else can we do?
Approaches outside the IDE
A variant is using build scripts. For example Maven-Plugins could format the sources or let the build fail if they detect a wrong format. They use an embedded formatter engine or redirect the formatting process to an installed Eclipse instance.
Using client-side Git-commit hooks is another approach. More strict are server-side SCM-hooks. If they detect files which do not apply to the expected format, the push/commit is rejected. Amongst others Git and Mercurial support it.
Approaches within the IDE
Or once you have committed yourself to a formatting rule-set, especially to an Eclipse formatter configuration like we did, then there exists another promising variant. By using the following plugins for Jetbrains IntelliJ IDEA and Oracles NetBeans you can use the same configuration file like the Eclipse users. These plugins contain the original Eclipse formatter engine as jar files. When you format code using these the text from your Java Editor is taken, transformed by the formatter engine and replaced by the formatter output. So, there are no imitations of configuration settings involved.
Even better: The plugins also support the Workspace Mechanic-configuration files. More about that later.
Eclipse Formatter for IntelliJ IDEA
Eclipse Formatter for NetBeans
Side note about compatibility
A short side note: The Eclipse formatter engine gets improved steadily. Bugs get fixed or are even introduced. In the past in the transition from Eclipse 4.4 to 4.5 the same configuration file led to different results. A new version was not backward compatible, which introduced confusion in teams, who were not aware of this behaviour change. Thus, you have to choose engine version matching to your IDE version or choose a matching plugin version!
In our subsidiary, we use a hybrid-approach based on the discussed variants from above. Since ages there exists an Eclipse formatter configuration, which all the teams have agreed to use. One (or more project specific) pre-configured Eclipse-distributions (STS with some plugins and some minor presets for proxy a.s.o) are deployed automatically by Puppet on every developer computer. Even development middle-ware components like Maven and the JDK are deployed this way. These Eclipse-distributions have all in common that the formatter configuration is guaranteed by the “Workspace Mechanic”-plugin.
What is this “Workspace Mechanic”-plugin?
It is an Eclipse-Plugin (originally developed by Google), which can be downloaded from the Eclipse Marketplace. It periodically compares the configuration of your Eclipse installation with an expected set of configurations. If a mismatch is detected, then a dialog pops up and proposes to fix the configuration automatically. Here you will find another (German) introduction.
Our Eclipse-distributions are pre-configured to get the expected configuration files from a shared network drive or from a local configuration directory deployed by Puppet.
This way it is assured that our developers can write code without thinking about the formatter configuration. New colleagues can start to work immediately. The “ready-to-code”-distribution is already on their computer from day one. This even works for developers which want to use their own distribution. They only have to install the plugin and set the Workspace Mechanic-URL to be compliant.
Non-Eclipse users use the Eclipse formatter plugin for their IDE and configure the Workspace Mechanic-URL.
Bonus: How about “Organize Imports”, “Members Sort Order” and “Save Actions”?
Formatting sources, which is mostly adding white-spaces and line breaks, is not enough. Every IDE provides additional features like reordering imports, fields and methods and also other code-clean ups, which could be even triggered every time you save a file. Especially Eclipse provides a vast amount of these save actions. Technically these actions don’t format code, they apply refactoring to it. And thus these features are not covered by the above-mentioned Eclipse Formatter plugins, which only embed the formatter engines.
Nevertheless, basic actions like “Format On Save” or “Organize Imports On Save” are available in every IDE – natively or by plugin.
When using IDEA you can use the SaveActions-plugin from the plugin center, which provides additional “Save Actions”.
In this article, I reported about different types of IDE-specific and IDE-independent approaches, which allow teams to apply to a common Java code format. In this context, I showed you our approach of using the Workspace Mechanic-Plugin for Eclipse and the Eclipse-Formatter-Plugins for other IDEs to achieve it.
I know this not a 100% solution. You cannot make a non-Eclipse-IDE fully compatible to Eclipse. Especially when your team uses save actions or clean-up-rules, which have no equivalents in the other IDEs. So you have to configure your IDE manually to match at least the basic rules.
So, my proposals to minimize this effort and the pain:
- Keep your rules simple! Define an import and members sort order, which is configurable in all target IDEs and provide configuration files for these IDEs. Do not use all the save actions that are available.
- Use Checkstyle! Instead of using comprehensive Eclipse save actions, define a Checkstyle ruleset for your team. Run Checkstyle on your build server to track violations! Integrations for SonarQube and CI-Servers like Jenkins exist. Install a Checkstyle plugin for your IDE, which warns you about violations and even provide quick-fixes.
- In short: Minimize dependencies to the IDE!