The truth is we had been under difficult times. We spent almost three months to migrate our build mechanism from Ant to Maven. That’s the minimum time you have to put in your schedule if you are planning to do the same in a large project. There are still some collateral effects of this migration that we are struggling to solve, but fortunately they are not so critical.
Just to contextualize a little, we have a full Java EE 6 system composed of 25 integrated applications and each application has an average of 3 modules (EJB, WEB, etc), reaching ~80 modules. We manage something close to 500K lines of Java code (JSs, CSSs, JSPs and JSFs files not included), according to our Sonar analysis. It takes between 15 to 20 minutes to build everything. It depends on the mood of the server.
The decision to go for Maven came as a precondition to start a large scale refactoring of the application, which, despite using the latest technology available (Java EE 6), has suffered from a mix of frameworks, design flaws and multiple architectures over the years. We are going towards a single architecture grounded on the Java EE specification in order to optimize dependencies, reduce the evolution cost in a middle/long-term perspective and run seamless in our Glassfish Application Server.
The project structure is almost the same as it was with Ant, thanks to the flexibility provided by Maven. We have a super pom.xml file in the root folder, which basically declares all modules, plugins, additional repositories, and dependencies. The dependencies are declared in a dependency management (using the tag <dependencyManagement>). This way, all version numbers are declared in a single place. Besides the super pom.xml, we have a folder for each integrated application and inside each folder we have a application pom.xml and three other folders, one for each Java EE module (EAR, EJB, WEB). The application’s pom.xml inherits from the super pom and it basically declares the modules composing the application. Inside the module folders we have one more level of pom files. These pom files inherit from their respective application’s pom files and describe the particularities of their modules. In summary, we have three levels of pom files, from the system as a whole to the level of Java EE modules.
|Example of structure similar to the one we are using.
For development purposes, we avoid deploying the entire application locally. That’s why we have an EAR module in each application. This way, we save time deploying only the application we are working on. Those application EAR modules are not taken into consideration when packaging to deploy on the servers. To build the full EAR for the servers we have a special application that contains a EAR module, whose pom file declares all EJB and WEB modules as dependencies. Performing the goal package on this pom.xml will actually create the super EAR file.
|EAR module to package the entire system in a single deployment file.
Evaluating the project after Maven implementation, we could notice the following benefits:
Maven contributed to simplify the logic behind the build: Now, everybody is aware of what is going on because pom.xml files are much easier to understand than build.xml files. Our Ant files were generated by Netbeans, thus very big and unreadable. We were actually lucky to have them working for so long, since it was difficult to maintain them. No question that we would find a point of irremediable chaos very soon.
Maven also contributed to put some order in all project dependencies: We went from a ~100 MB EAR package to a ~50MB one, a very significant reduction of 50%. It contributed to make the deployment time shorter.
We had the opportunity to clean up the project: While gathering the dependencies to write the pom.xml files, we discovered that some modules were not needed any more; libraries spread through the modules were also removed in favour of Maven’s dependency management. In summary, we have said “Maven is a nightmare” until the day we finally had everything in order and we became happier and relaxed. That’s what most people say as well, since it’s not easy to find solutions for a particular scenario, and everybody has a particular scenario to deal with.
Short learning curve: Once Maven was put in place, we visited all developers, reconfigured Netbeans to recognize the Maven projects and explained to them how to proceed from that point on. All of them could immediately continue with their development activities and just a few call for support were triggered. None of these calls were blocking issues. I have to say that Netbeans contributed a lot to reduce the learning curve because all necessary goals are performed directly from the IDE and there is no need to go to the command line, as it usually happens with Eclipse.
Unfortunately, we had some setbacks:
The build now takes longer with Maven: We have noticed a decline on developers’ productivity due to that, making us a bit frustrated at the end 🙁 Since we are not going to rollback to Ant, we are considering JRebel for dynamic reloading of changed code to compensate the additional time we are spending.
We are using some libraries that can’t be found in Maven’s central repositories or elsewhere: Some are commercial libraries and others are too old. We also found libraries available with inconsistencies, throwing many exceptions at runtime (i.e. Apache FOP). For each one of these situations we had to find workaround solutions that were not so elegant, but we cannot stay like that for so long. We have to install a local Nexus repository to address special cases. This is in our check-list.
Occurrence of unexpected behaviours: the best of the efforts is not enough to avoid unexpected behaviours in the application. We have built a spreadsheet listing all applications and their respective modules; documented all dependencies from libraries and between modules; depicted the project structure; went deeper into details. In order to elaborate this spreadsheet we spent several days investigating the guts of the system, absorbing low level mechanisms and design decisions. All the collected information was used on the migration. Nevertheless, the rearrangement of dependencies and the removal of duplicates and unused libraries caused broken navigation flows, alert messages coming from nowhere, changes on URL paths and many other surprises. Unfortunately, we couldn’t predict those problems and we spent much more time on fixes than what was initially foreseen.
I would like to conclude giving some advices for those planning to adopt Maven in a middle/large scale project:
Communicate the migration to end-users: it’s very important to communicate to end-users what is going to happen in the coming days. Users should be aware that, as they have the duty to improve their business, we also have the duty to improve ours. It means the delivery of new features will temporarily slow down to pave the way to a better product with faster releases. If they are not aware of what is going on, they will have very low tolerance to problems, undermining the reputation of the project.
Don’t be afraid to change even what is working well: We have questioned ourselves why to migrate to Maven if Ant is working so well. Actually, our strategy is to reduce complexity to streamline the resolution of problems. So, we were not afraid to migrate because preventive measures are very important too.
Keep the entire migration under version control to help the investigation of problems: Once all pom files were created and versioned, every little changes in those files should be committed separately in order to revert changes in case of unexpected problems. It helps to isolate the causes. It is also good to know that there is no conflict between Ant and Maven files. So, both can stay in the same branch during the migration without any impact on developers.
Don’t start a big refactoring without a build system like Maven: a successful refactoring depends on a detailed understanding of the application and adopting Maven will push you to perform an extensive investigation. In addition to that, the project will be cleaner and better organized.
There are other alternatives to Maven, such as Apache Ivy and Gradle, but, despite all deserved criticism, we still recommend Maven when replacing Ant because of its maturity; vast plug-in portfolio; abundant documentation on the web; and rich IDE support. However, it’s a good idea to evaluate other alternatives once Maven is put in place. After the initial tsunami, other waves will come quietly.