Why not Maven

From Juneday education
Jump to: navigation, search


In our teaching material related to Java programming, we have a few assignments and exercises that require some work when it comes to building and deploying the system being built. Since we don't use IDEs like Eclipse or IntelliJ, the students are forced to learn how to compile and run applications that consist of libraries and other resources (like databases).

The strategy we have chosen, is to let the students download third party libraries and software needed, put these resources in their directory tree and use features like the Java class path in order to compile and run. When this amounts to quite long command lines, we also provide them with bash scripts so that they can speed up their development time by only having to issue commands like:

$ ./clean.sh && ./build.sh && run.sh

The question might arise; Why not let Maven handle dependencies, building and running?

Our rationale for not using build tools

Allows for explaining how the Java environment works

For simpler and smaller assignments or exercises, we simply show them how to download e.g. a required third party JAR file, how to compile their code against this library and how to run the application with the library in the class path. A typical example would be a small application which reads from an SQLite database and processes data and outputs some results to the standard out stream.

We see this as a great opportunity to teach the students what a library is, how the JDBC architecture works with external drivers, and to iterate the concepts of compile-time versus run-time.

In the case of SQLite JDBC drivers, we also take the opportunity to investigate the contents of the JAR file, to explain how it is possible that a call to DriverManager.getConnection(url) can return an object of a class which origins from the third party library (the JAR file). We think this is a valuable "behind the scenes" knowledge which puts the use of JDBC in context.

For an application that depends on, say a JAR file with the JDBC drivers for SQLite, the complexity isn't very high. In order to compile your application, you don't need to care about any third party libraries, since the JDBC architecture uses the standard Java JDBC API. This API consists of mostly Java interfaces and a few concrete classes (like DriverManager and SQLException). This makes for a great opportunity to recap Java interfaces and their uses.

To run the application, on the other hand, the students soon realize that they need to have access to the third party driver, since DriverManager acts like a factory for providing a Connection object of the right kind, the kind that connects to a named SQLite database. So when running, the students need to make sure the corresponding JAR file is on the class path.

This becomes even more interesting when they have the JAR file in some location, and the packages for the application in another location; the class path needs to ensure that the Java runtime can find both the JAR file and the e package for the main class.

The first step for the students is typically to download the driver JAR file from the web, and here we take the opportunity to show them how to do so directly in the command line, to avoid downloading using a browser, then locating the downloaded file and moving it to the preferred location in their software directory tree. We show them curl and wget as simple means to get a file from a web location.

The next step is to compile the application. This is something the students at this point are familiar with, since they have been working in the command line since the first introduction to Java. When running the application, we show them how to include the JAR file they downloaded in the class path, so that the correct concrete classes will be used via JDBC.

Maven is overly complex

Now, we could have used Maven and a pom file for this. But we feel this is an extreme overkill. Let's say we use the following pom.xml for a small application which uses JDBC and SQLite to read some fruit names from a database and print them to the terminal:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <!-- https://mvnrepository.com/artifact/org.xerial/sqlite-jdbc -->

Then, the students would do this to build the application (including downloading of the necessary JAR file if needed):

$ mvn install
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building dbexample1 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
Downloading: https://repo.maven.apache.org/maven2/org/xerial/sqlite-jdbc/
Downloaded: https://repo.maven.apache.org/maven2/org/xerial/sqlite-jdbc/ (7 KB at 13.0 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/sonatype/oss/oss-parent/9/oss-parent-9.pom
Downloaded: https://repo.maven.apache.org/maven2/org/sonatype/oss/oss-parent/9/oss-parent-9.pom (7 KB at 139.5 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/xerial/sqlite-jdbc/
Downloaded: https://repo.maven.apache.org/maven2/org/xerial/sqlite-jdbc/ (5872 KB at 3465.9 KB/sec)
[INFO] --- maven-resources-plugin:2.6:resources (default-resources) @ dbexample1 ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] Copying 1 resource
[INFO] --- maven-compiler-plugin:3.2:compile (default-compile) @ dbexample1 ---
[INFO] Changes detected - recompiling the module!
[WARNING] File encoding has not been set, using platform encoding UTF-8, i.e. build is platform dependent!
[INFO] Compiling 1 source file to /home/rikard/programming/java/maven/target/classes
[INFO] --- maven-resources-plugin:2.6:testResources (default-testResources) @ dbexample1 ---
[WARNING] Using platform encoding (UTF-8 actually) to copy filtered resources, i.e. build is platform dependent!
[INFO] skip non existing resourceDirectory /home/rikard/programming/java/maven/src/test/resources
[INFO] --- maven-compiler-plugin:3.2:testCompile (default-testCompile) @ dbexample1 ---
[INFO] No sources to compile
[INFO] --- maven-surefire-plugin:2.17:test (default-test) @ dbexample1 ---
[INFO] No tests to run.
[INFO] --- maven-jar-plugin:2.4:jar (default-jar) @ dbexample1 ---
[INFO] Building jar: /home/rikard/programming/java/maven/target/dbexample1-1.0-SNAPSHOT.jar
[INFO] --- maven-install-plugin:2.5.2:install (default-install) @ dbexample1 ---
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-shared-utils/0.4/maven-shared-utils-0.4.pom
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-shared-utils/0.4/maven-shared-utils-0.4.pom (4 KB at 84.1 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.15/plexus-utils-3.0.15.pom
Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.15/plexus-utils-3.0.15.pom (4 KB at 69.8 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-api/2.2.1/maven-plugin-api-2.2.1.jar
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-profile/2.2.1/maven-profile-2.2.1.jar
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-registry/2.2.1/maven-plugin-registry-2.2.1.jar
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-settings/2.2.1/maven-settings-2.2.1.jar
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-project/2.2.1/maven-project-2.2.1.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-api/2.2.1/maven-plugin-api-2.2.1.jar (13 KB at 188.8 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-interpolation/1.11/plexus-interpolation-1.11.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-plugin-registry/2.2.1/maven-plugin-registry-2.2.1.jar (30 KB at 211.8 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-model/2.2.1/maven-model-2.2.1.jar
Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-interpolation/1.11/plexus-interpolation-1.11.jar (50 KB at 350.3 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-artifact-manager/2.2.1/maven-artifact-manager-2.2.1.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-settings/2.2.1/maven-settings-2.2.1.jar (48 KB at 293.8 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-repository-metadata/2.2.1/maven-repository-metadata-2.2.1.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-profile/2.2.1/maven-profile-2.2.1.jar (35 KB at 198.5 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/backport-util-concurrent/backport-util-concurrent/3.1/backport-util-concurrent-3.1.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-artifact-manager/2.2.1/maven-artifact-manager-2.2.1.jar (66 KB at 260.8 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/maven-artifact/2.2.1/maven-artifact-2.2.1.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-repository-metadata/2.2.1/maven-repository-metadata-2.2.1.jar (26 KB at 97.9 KB/sec)
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-model/2.2.1/maven-model-2.2.1.jar (86 KB at 334.1 KB/sec)
Downloading: https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-shared-utils/0.4/maven-shared-utils-0.4.jar
Downloading: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.15/plexus-utils-3.0.15.jar
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-project/2.2.1/maven-project-2.2.1.jar (153 KB at 584.8 KB/sec)
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/maven-artifact/2.2.1/maven-artifact-2.2.1.jar (79 KB at 201.1 KB/sec)
Downloaded: https://repo.maven.apache.org/maven2/backport-util-concurrent/backport-util-concurrent/3.1/backport-util-concurrent-3.1.jar (324 KB at 771.3 KB/sec)
Downloaded: https://repo.maven.apache.org/maven2/org/apache/maven/shared/maven-shared-utils/0.4/maven-shared-utils-0.4.jar (152 KB at 352.2 KB/sec)
Downloaded: https://repo.maven.apache.org/maven2/org/codehaus/plexus/plexus-utils/3.0.15/plexus-utils-3.0.15.jar (234 KB at 535.2 KB/sec)
[INFO] Installing /home/rikard/programming/java/maven/target/dbexample1-1.0-SNAPSHOT.jar to /home/rikard/.m2/repository/minimal/database/dbexample1/1.0-SNAPSHOT/dbexample1-1.0-SNAPSHOT.jar
[INFO] Installing /home/rikard/programming/java/maven/pom.xml to /home/rikard/.m2/repository/minimal/database/dbexample1/1.0-SNAPSHOT/dbexample1-1.0-SNAPSHOT.pom
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.252 s
[INFO] Finished at: 2019-04-28T15:06:03+02:00
[INFO] Final Memory: 19M/234M
[INFO] ------------------------------------------------------------------------

Next, to "run" the application using Maven, the students would need to do this:

$ mvn exec:java -Dexec.mainClass="minimal.database.Main"
[INFO] Scanning for projects...
[INFO] ------------------------------------------------------------------------
[INFO] Building dbexample1 1.0-SNAPSHOT
[INFO] ------------------------------------------------------------------------
[INFO] --- exec-maven-plugin:1.6.0:java (default-cli) @ dbexample1 ---
[INFO] ------------------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.638 s
[INFO] Finished at: 2019-04-28T15:23:01+02:00
[INFO] Final Memory: 10M/240M
[INFO] ------------------------------------------------------------------------

Did you notice the three fruits being printed to the screen? Didn't think so ;-)

It's important to understand that we are not against Maven, Ant, Gradle or any other build tools. They are probably great for large projects. We avoid them in our course material because we think they introduce too much noise and overhead complexity.

To download dependencies, compile and run the example program without Maven, the following command lines would have been used:

$ wget 'http://central.maven.org/maven2/org/xerial/sqlite-jdbc/'
--2019-04-28 15:31:22--  http://central.maven.org/maven2/org/xerial/sqlite-jdbc/
Resolving central.maven.org (central.maven.org)...
Connecting to central.maven.org (central.maven.org)||:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 6012084 (5,7M) [application/java-archive]
Saving to: ‘sqlite-jdbc-’

sqlite-jdbc-3.27.2. 100%[===================>]   5,73M  3,77MB/s    in 1,5s    

2019-04-28 15:31:23 (3,77 MB/s) - ‘sqlite-jdbc-’ saved [6012084/6012084]

$ javac -cp 'src/main/java/' src/main/java/minimal/database/Main.java && java -cp 'src/main/java:sqlite-jdbc-' minimal.database.Main

Maven introduces a new nomenclature and organization

A thing with both IDEs and build tools that we believe is an impediment to learning programming and Java, is that they introduce a terminology and nomenclature which is confusing to the students (and to us). A central concept that all IDE and build tool makers seem to have a thing for, is the concept of "Project". While there is nothing wrong with thinking of your source code in terms of a "project", it is not a concept within the Java terminology. There is nothing called Project as far as the Java compiler and runtime are concerned. Still, every time you start coding on a new assignment, program, application, exercise (yes, we could call it Project too!) using an IDE, the first thing you need to do is to create a "new Project". This is of course an abstraction, but the implications are indeed concrete because of how the IDEs organize their code. If not addressed, the students may very well think that a "Project" is a Java concept and has to do how Java source code must be organized and that's not true.

The build tools use the same jargon. If you inspect the root element of a pom.xml (Maven build configuration file), that element is surely enough <project>. This may seem like a detail and certainly not a big deal. But it doesn't end here. In order for Maven to find the source code to build, the code must be organized under a directory tree in current directory with the following structure: src/main/java . While it is a good idea to separate source code from the compiled code, there is no rules what-so-ever where the source code must reside. The src/main/java relative path is an invention of Maven (and the likes). As far as the compiler is concerned, you might as well put your code in src/here/is/the/code.

Understanding paths, the difference between a relative path and an absolute path is something we've seen that students today struggle with. They may be digital natives, born with a mobile and tablet computer in their hands, but they are not "command line natives". Interestingly, it seems as if the more used to using technology the students have become, the less they know about the way computers, operating systems and programs work.

Understanding packages, which is strongly related to relative paths, is a must for someone who wants to learn Java. This is one of the reasons we "force" them to use the terminal and shell, to expose them to the inner workings of the file system and operating system at large. We have been teaching Java for nearly two decades and we have a strong feeling that students that were taught programming using an IDE from scratch have much less understanding of the way packages, class path and environment variables work. For this reason, we think it might be wise to first teach the students how to compile and run applications "manually" before introducing more complex tools for automated builds, dependency resolution etc.

Just think about it, if you inherit someone's pom.xml file and you get tons of errors trying to build it and the errors seems related to paths and packages somehow. How would you go about and trouble shoot that, if you have no idea of how the Java compiler and runtime works regarding these topics?

Maven is a useful skill

We do think, however, that using both IDEs and build tools are a great thing to know when you get your first job as a developer. But we recommend that these tools are introduced only after the students have a thorough knowledge of "the inner workings" that goes on behind the scenes when developing Java software. Perhaps such tools could be introduced in a "project" course (see, that's a suitable name for working with Maven and Eclipse Project concepts), or a dedicated "Programming tools" course. At least, we think that one should think carefully about whether these tools really are necessary for small assignments and when and how to introduce them. And, of course, that we teach the students how these tools work and how to use them, before we demand that the students use them.


Others' opinions on Maven

Here are a few selected opinions on Maven from a developer perspective. We haven't found any texts about Maven from a pedagogical perspecive but please let us know if you find or know of any.