cassandra

Cassandra – A shift from SQL

We have had lot of shifts in the paradigm in how we think about persisting data and retrieving them as efficiently as possible. For the longest time, we have had SQL as our goto solution for persisting data. SQL definitely is an awesome solution and that is the reason why it had survived the test of time for so long (Fun Fact: The first commercial RDBMS was Oracle which got released in 1979 [1]) and is definitely not in any space to go down in the near future.

 In my opinion, SQL gave us all a near perfect, generic solution for persisting data. SQL gives a lot of importance to things such as data-integrity, atomicity, normalization of data so the data is always in a consistent state whilst maintaining the query performance. Hence, it has got its own way to sort out things among itself with joins, foreign-keys, etc. Of-course, life is not always too fair. This magic that SQL does comes with a price to scale. SQL datastores are often not horizontally scalable and would require manual and application logic to shard the data to decrease the load. One other big challenge with SQL is having a single point of failure. The reason for this is again attributing to its inability to scale horizontally.

We were taught to think database design in this way, and hence that is what we do the best. But majority of the applications do not care about the size of the data or how its stored. On the other hand we don’t actually mind if the data is replicated in multiple locations. In fact, memory has become so cheap now, that we would love to have data duplication where ever possible.

With the intrusion of big data on almost every domain, it does not always make sense to hold on to SQL way of doing things. I’m in no way suggesting that SQL does not have future and everyone who are depending on big data need to resort to NoSQL way of doing things. The idea is to think by prioritizing the feature-set you would need for your datastore to have and, be open to pick and prioritize what you would need. Keep in mind that using both NoSQL and SQL hand-in-hand is not considered a bad practice at all. Just make sure that you are not over engineering your use case.

There are multiple options in the market right now. But, we are going to talk about one such datastore; Cassandra. Why Cassandra? Because, that is the one I have the most insight to talk about. Cassandra, has now reached a very mature state with many big-shots using it as their datastore. Few of them worth mentioning are Netflix, Apple, SoundCloud, etc. So, what is this Cassandra all about? Cassandra is a very powerful, battle-tested data-store that provides high availability with high read and write throughput.

I did talk about letting go few features that relational database provide could give you benefits such as ability to scale horizontally, increase the availability, etc. So, what is the compromise that we have to make if we choose Cassandra? It is the data model.

Data model is the best way you can fine tune your cassandra cluster. Relational databases often deal with creating a logical entity called tables, and relationships among the tables using Foreign-keys. Since Cassandra does not have any kind of joins or relation-ships, the data has to be stored in a denormalized fashion. This is actually not a bad thing in casssandra. But the catch is that, we need to know the query access patterns before designing the model. But if done properly, the performance that we get out of Cassandra is phenomenal. Here is a link that talks about the benchmarking on cassandra cluster at Netflix.

I would like to get this going as a series, so I will stop talking about cassandra now and we’ll start off with how to model your data in cassandra in a different post.

 

Standard
maven reactor
build-tools, java

Maven reactor: A smart way to a modular project structure

Usually, I would just avoid any thing that involves XML processing or XML configuration in it. So, I wasn’t a big fan of maven either when I started using it. Have I had any good alternate to build projects, I would have undoubtedly inclined towards it. Now, I do understand that gradle is still out there giving a very tough competition to maven. But, I feel it still has lot of distance to cover up; Maven just has got an awesome head start and I don’t think it could be replaced by gradle, even though with a lot new framework’s supporting it (Android, Spring, etc.). I was quite amazed to know what capabilities that maven could do to ease up the life of a programmer.

We can go on and on if I start talking about maven. But I would like to share one interesting feature I like about maven; The Reactor plugin.

It is often recommended to have your projects small and concise for obvious reasons. But usually, we find one huge project or a bunch of small standalone projects that depend on each other. Even if we divide a huge project into multiple small and cohesive projects/libraries/modules, we still have an overhead to manually make sure that the projects are built in the right order to make sure the right dependency is picked up. Many projects end up growing enormously due to this extra overhead on the developer when building the project.

Maven, does have a smart way for us to manage the modules for us without us having to make sure if the modules in the projects are built in the right order. Let’s see how that is done.

So, how reactor project works is that, you would have to setup a top-level pom that manages all your modules. This is usually called the parent-pom. All the modules that are part of this project will just be another simple maven project that will inherit this parent-pom. Along with this you will also, need to specify to the parent-pom on what are its children/modules. This will ensure maven does all the magic for you while its building your project.

Structure of a Maven reactor project

Structure of a Maven reactor project

That is all you need to do. Let’s now take a look at how to define your parent-pom.

Parent-pom:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0&quot;
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;
<modelVersion>4.0.0</modelVersion>
<groupId>com.indywiz.springorama.reactor</groupId>
<artifactId>maven-reactor-parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
<module>maven-reactor-app</module>
<module>maven-reactor-util</module>
</modules>
</project>

view raw

parent-pom.xml

hosted with ❤ by GitHub

If you check out what is different when you compare the pom with a traditional pom file is the following.

  • Packaging is set to pom instead of jar/war. This is because, your parent-pom is just a maven entity to manage your module, it is not a project that produces any artifact for you.
  • The modules tag. This tag is responsible for defining what are all the projects that the reactor has to manage.

Keep in mind that the order you define your modules does not matter, we will go thru that part in the end.

Now lets look at the module-pom.

Module-pom:


<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0&quot;
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance&quot;
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"&gt;
<parent>
<artifactId>maven-reactor-parent</artifactId>
<groupId>com.indywiz.springorama.reactor</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>maven-reactor-util</artifactId>
<name>maven-reactor-util</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.7</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

view raw

module1-pom.xml

hosted with ❤ by GitHub

So, in this example, the first module is just a util library where I am using commons-lang3 library from apache. One other thing you will have to note is that we do not need to specify the groupId and the version in this pom. They are inherited from your parent-pom.

Now, I would like to use this module as a dependency on my module 2. The second module’s pom is similar to the first module. I just add the first module as the dependency to it.


<dependency>
<groupId>com.indywiz.springorama.reactor</groupId>
<artifactId>maven-reactor-util</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>

Now, all you have to do is to build the parent pom and see the magic happen.

Maven reactor build result

Maven reactor build result

So, what just happened was that, when we built the parent pom, reactor build part kicked in and maven started to check what are all the modules that come under this project, build the dependency graph and dynamically figured out that module2 (i.e the util project) depends on module 1 (the app module) and build util module before it started building the app module.

I deliberately, reversed the order in which I defined the modules in the parent pom. If you check the parent-pom’s modules tag, we defined app module before the util module. I did that on purpose to show that the order in which we define does not matter. Maven reactor will figure out the right order to build these project irrespective to the order in which they are defined in the parent pom.


<modules>
<module>maven-reactor-app</module>
<module>maven-reactor-util</module>
</modules>

I hope you guys also enjoyed this post. I’d be happy to hear your feedback. In case you can check out the complete example in github here.

Standard
RxJava
asynchronous, java, libraries

RxJava: A much needed programmer friendly library

Recently, I had to do a lot of concurrent-programming. To be honest, it has not been a pleasure ride. Writing java programs with concurrency in mind is not a straightforward task. Primary reason being, not many utilities come bundled with the language to ease up the concurrent task in hand. A few of them to name are Future, CompletableFuture, Executors. In my opinion, the best help java provides to us is thru CompletableFutures. We have talked about CompletableFutures in a post already.

Nevertheless, I feel that CompletableFutures solves a very specific problem, i.e. to chain asynchronous tasks together in a very fluid way. Ideally what we would want in a concurrent program is the ability to not worry about number of threads, a pool to manage threads whilst having the ability to compose and chain tasks together.

RxJava is one such library that solves scenarios like this with ease. Though RxJava is not designed to solve problems involving concurrency, the underlying concepts that RxJava is based on, implicitly gives us an awesome way to develop concurrent applications.

RxJava is based on the Reactive Manifesto. Reactive manifesto primarily deals with four main traits as shown in the figure below.

Reactive manifesto traits

Reactive manifesto traits

Let’s not get deep into each one of these traits. But the reason RxJava provides easy concurrent programming inherently is due its message-driven trait.

According to the reactive manifesto:

Reactive Systems rely on asynchronous message-passing to establish a boundary between components that ensures loose coupling, isolation and location transparency. This boundary also provides the means to delegate failures as messages. Employing explicit message-passing enables load management, elasticity, and flow control by shaping and monitoring the message queues in the system and applying back-pressure when necessary.

RxJava leverages this message-driven trait in all its components. Hence, we could design a seamless message publish-subscribe kind of application that inherently gives you ability to change your implementation to an asynchronous very easily. We just have to specify if the task on hand is CPU intensive work or I/O bound. RxJava internally takes care of managing the concurrency for you.

Let’s see an example on what I meant.

Observable.fromArray(1, 2, 3, 4, 5)
    .observeOn(Schedulers.computation())
    .map(integer -> {
      System.out.println("Executing cpu intensive task on thread : "+Thread.currentThread().getName());
      return cpuIntensiveTask(integer);
    })
    .observeOn(Schedulers.io())
    .map(integer -> {
      System.out.println("Executing i/o bound task on thread : "+Thread.currentThread().getName());
      return ioBoundTask(integer);
    })
    .blockingSubscribe(integer -> System.out.println("Result = "+integer));

If you see the above code, all we had to specify was to tell if it is going to be a task that is cpu-intensive or i/o-intensive. This will output the following:

Screen Shot 2018-05-20 at 12.49.08 AM

The above code is very similar to a Java stream but, yet it is very different from what streams are. RxJava provides the fluidity that java streams provide along with the power of composing multiple asynchronous tasks similar to what we know about CompletableFutures.

There is lot more to RxJava than what we have talked about in this post. Lets get more hands on in future posts. The intent of this post was to share my perspective on RxJava and why it is one of the best programmer-friendly library out there. I would encourage you to definitely try out RxJava and let me know what you feel about this awesome library.

Standard
java, libraries

Lombok – A must have library to spice up your Java

Java, unfortunately, does have a lot of unwanted verbosity when it comes to creating classes. Whilst there are new languages on jvm competing with each other by having to write very less amount of boilerplate code, java still is not even close to these competitors.

While we sit and complain about the language’s inability to incorporate reduction of unwanted ceremony of code, ProjectLombok, has given us a work around to make our lives a little bit easier.

Alright, I am a Java programmer about to write a simple model class for my CRUD operations. I will have to go thru the following steps to create the model.

  1. Create the model-class.
  2. Define the attributes for the model with right scope. (Since its good practice to encapsulate attributes properly, I will have to set the access specifier to private. Personally I’m not a big fan of this).
  3. Create default constructor and parameterized-constructors based on my needs.
  4. Optionally, I also have to override toString(), equals() and hashCode() if needed.
  5. If I am done with the above stuff, I might think of have a nice builder pattern if needed, so that I can have a fluid way to populate the attributes.

This has to be repeated and could sometimes be a very painful thing, if we have to do it for many models and, things for sure will get annoying if the model class has to change. Clearly, we don’t have to do such things in modern languages like scala or groovy or kotlin. These languages give you getters, setters, etc., for free. It would be awesome if java would also come up with something like this to avoid unnecessary boilerplate code when instantiating classes. Well, Lombok exactly solves this thing for us. It silently generates all the boiler plate code by integrating with the build tool and also the IDE for you to focus just on specifying what you need and the business logic.

If you look at the above steps we followed to create a model class, except creating the class and the attributes (which we have to anyway in any language) everything else, starting from specifying access specifier, creating getters and setters for the same, having to override bunch of obvious methods could be avoided and Lombok provides an awesome way to achieve this thru annotations.

Below is a model where I used Lombok annotations in the Spring-Integration post.


package com.indywiz.springorama.springintegration.model;
import javax.persistence.Entity;
import javax.persistence.Id;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
@Data
@Entity
@Builder
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Person {
@Id
private Long personId;
private String personName;
private String personPhoneNumber;
}

view raw

Person.java

hosted with ❤ by GitHub

This is a very simple model where I have just three fields, couple of JPA annotations and a bunch of Lombok annotations. The interesting thing to see is what Lombok generated for me when compiling the class.


package com.indywiz.springorama.springintegration.model;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Person {
@Id
private Long personId;
private String personName;
private String personPhoneNumber;
public static Person.PersonBuilder builder() {
return new Person.PersonBuilder();
}
public Long getPersonId() {
return this.personId;
}
public String getPersonName() {
return this.personName;
}
public String getPersonPhoneNumber() {
return this.personPhoneNumber;
}
public void setPersonId(Long personId) {
this.personId = personId;
}
public void setPersonName(String personName) {
this.personName = personName;
}
public void setPersonPhoneNumber(String personPhoneNumber) {
this.personPhoneNumber = personPhoneNumber;
}
public boolean equals(Object o) {
if (o == this) {
return true;
} else if (!(o instanceof Person)) {
return false;
} else {
Person other = (Person)o;
if (!other.canEqual(this)) {
return false;
} else {
label47: {
Object this$personId = this.getPersonId();
Object other$personId = other.getPersonId();
if (this$personId == null) {
if (other$personId == null) {
break label47;
}
} else if (this$personId.equals(other$personId)) {
break label47;
}
return false;
}
Object this$personName = this.getPersonName();
Object other$personName = other.getPersonName();
if (this$personName == null) {
if (other$personName != null) {
return false;
}
} else if (!this$personName.equals(other$personName)) {
return false;
}
Object this$personPhoneNumber = this.getPersonPhoneNumber();
Object other$personPhoneNumber = other.getPersonPhoneNumber();
if (this$personPhoneNumber == null) {
if (other$personPhoneNumber != null) {
return false;
}
} else if (!this$personPhoneNumber.equals(other$personPhoneNumber)) {
return false;
}
return true;
}
}
}
protected boolean canEqual(Object other) {
return other instanceof Person;
}
public int hashCode() {
int PRIME = true;
int result = 1;
Object $personId = this.getPersonId();
int result = result * 59 + ($personId == null ? 43 : $personId.hashCode());
Object $personName = this.getPersonName();
result = result * 59 + ($personName == null ? 43 : $personName.hashCode());
Object $personPhoneNumber = this.getPersonPhoneNumber();
result = result * 59 + ($personPhoneNumber == null ? 43 : $personPhoneNumber.hashCode());
return result;
}
public String toString() {
return "Person(personId=" + this.getPersonId() + ", personName=" + this.getPersonName() + ", personPhoneNumber=" + this.getPersonPhoneNumber() + ")";
}
public Person() {
}
public Person(Long personId, String personName, String personPhoneNumber) {
this.personId = personId;
this.personName = personName;
this.personPhoneNumber = personPhoneNumber;
}
public static class PersonBuilder {
private Long personId;
private String personName;
private String personPhoneNumber;
PersonBuilder() {
}
public Person.PersonBuilder personId(Long personId) {
this.personId = personId;
return this;
}
public Person.PersonBuilder personName(String personName) {
this.personName = personName;
return this;
}
public Person.PersonBuilder personPhoneNumber(String personPhoneNumber) {
this.personPhoneNumber = personPhoneNumber;
return this;
}
public Person build() {
return new Person(this.personId, this.personName, this.personPhoneNumber);
}
public String toString() {
return "Person.PersonBuilder(personId=" + this.personId + ", personName=" + this.personName + ", personPhoneNumber=" + this.personPhoneNumber + ")";
}
}
}

view raw

Person.java

hosted with ❤ by GitHub

This is how the class would have looked if I had to write class manually without Lombok. With just 24 lines of code with Lombok, I get getters and setters, builder pattern, a constructor with all the three attributes, a default constructor and a toString() method that appends all the toString() of the class attributes. I could have gotten a lot more, by just adding bunch more Lombok annotations.

Installing Lombok:

Installing lombok is very straight-forward. You need to let the IDE and the build-tool know that you are using Lombok. Rest is all done for you by lombok.

Letting the IDE know:

  1. Download the Lombok jar from here.
  2. Either double-click on the downloaded jar file or run the following command from the location where you downloaded jar.
    java -jar lombok.jar
  3. Lombok will automatically scan your system to find the IDE installations and ask you permission to install Lombok plugin automatically for you. If it was not able to find the installations in their default locations, you also can specify the location where you have installed your IDE too. Screen Shot 2018-04-22 at 6.53.24 PM
  4. Then click on Install button and you are set.

Letting your build tool know:

For maven:

Add the following dependency to your pom file.


<dependencies>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.20</version>
<scope>provided</scope>
</dependency>
</dependencies>

For gradle:

Add the following to your build.gradle file.


lombok {
version = 1.16.20
sha256 = ""
}

And you are all set to use Lombok in your development environment. May you have all the power that Lombok annotations brings forth. To know what other annotations that Lombok offers take a look at the official documentation here.

Standard
asynchronous, java

CompletableFutures – Asynchronous programming made easy

Asynchronous programming is often not a very pleasant experience when it comes to Java. Java concurrency could be very challenging, there is an awesome book on this topic by Brian Goetz named “Java Concurrency in Practice“. It is quite extensive and often considered a definite read if you are working on projects involving Java or concurrency.

While there are many problems that threads, in general, could cause, my pick of the most annoying part is that when I want to chain parallel stuff together and pass down the result once I resolve a result in a pipeline kind of data-flow.

New languages like Scala, Javascript, etc., that have a good language design when it comes to writing concurrent programs. For example, Javascript provides an elegant solution for chaining asynchronous calls using promises. In my quest for something similar in Java realm, I was all excited when I first learned about java.util.concurrency.Future interface. While Futures were a good step towards a better future of Java, it did not catch up to the modern requirement of the Java community.

According to Oracle,

[1]A Future represents the result of an asynchronous computation. Methods are provided to check if the computation is complete, to wait for its completion, and to retrieve the result of the computation. The result can only be retrieved using method get when the computation has completed, blocking if necessary until it is ready. …

[1] https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html

If you focus on the official documentation of Future interface, it says one disappointing thing;  we will have to wait or manually check if the Future is done by callingisDone() method on the Future. So, if you want to use a Future you would have to keep polling the future to see if the future is complete.

Example:


package completablefutureexample;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class App {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//Future example
ExecutorService executorService = Executors.newFixedThreadPool(2);
Future<Integer> future = executorService.submit(() -> {
System.out.println("Executing a task.");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return new Random().nextInt(20);
});
while (!future.isDone()) {
System.out.println("Task not yet done…");
Thread.sleep(100);
}
System.out.println("The future is resolved. Value generated = " + future.get());
executorService.shutdown();
}
}

view raw

App.java

hosted with ❤ by GitHub

Also, if you think of how to chain subsequent calls, it can get really messy. We will have to check if the Future is done and handle the next Future. This is where Future interface fails to provide a fluent interface to chain calls and handling errors would open another can of worms.

Fortunately, Java 8 came to the party with a new update. Java 8 introduced a new class called CompletableFuture. CompletableFuture, in my opinion is the second best feature after Streams in Java 8. It is a type of Future which also implements CompletionStage interface. This interface would enable clean way of chaining and handling errors while writing asynchronous code.


package completablefutureexample;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class App {
public static void main(String[] args) {
CompletableFuture<Integer> completableFuture = new CompletableFuture<>();
//Define your flow
completableFuture.thenApply((integer) -> {
int randomNumber = 0;
try {
randomNumber = generateRandomNumber();
System.out.println("Adding " + integer + " to the random number " + randomNumber);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(
"Generated random number=" + randomNumber + " from thread : " + Thread.currentThread()
.getName());
return randomNumber + integer;
}).thenApplyAsync(integer -> {
System.out.println("Got result from the first thread.");
return integer + 500;
}).thenAccept(integer -> {
System.out.println("Added 500 to the result. Terminating the completable future.");
});
//Start the processing
completableFuture.complete(10);
}
private static int generateRandomNumber() throws InterruptedException {
int number = new Random().nextInt(100);
System.out.println("Sleeping for " + number + "ms");
Thread.sleep(number);
return number;
}
}

view raw

App.java

hosted with ❤ by GitHub

Lets now walk through what the above code is doing. We are defining a CompletableFuture where we start off by defining the flow, after which we call complete() method to pass in data to the pipeline to eventually pass the result of one operation nicely down the pipeline.

If you have not already observed, you can see that there are different flavors of thenApply method. CompletableFuture has two flavors of each of such methods, where the XXXAsync methods would run the operation on a different thread (By default if you do not specify any ForkJoinPool, it uses the ForkJoinCommonPool)

CompletableFuture also provides a variety of methods to compose, combine two or more CompletableFutures. This provides a very fluent, readable and maintainable asynchronous code.

We barely scraped the surface of CompletableFuture in this post. The motive of this post was to introduce CompletableFuture and see how different it is from Future interface. It would probably make sense to dedicate a whole new post to get more deeply into the capabilities of CompletableFuture. Let see that in a different post.

Standard
spring, Uncategorized

Why I started liking Spring framework?

My journey with Spring framework started not too long ago. It has been just about 6 months I started diving deep into spring, and since then, I have become a huge fan of Spring framework. I got introduced to spring about three years ago. To be honest, many people I talk to, were not inclined to use spring for the following reasons.

  • Initial learning curve
  • Too much XML code
  • Too much magic happening behind the scenes.
  • Unwanted complexity of a framework for solving a fairly simple problem.

Now, after I return back to spring after so long, I feel the spring community has done an awesome job in steering the framework to fit the needs of its users.

Lets go thru how spring has shaped itself over the past three years to overcome its so called deficiencies I listed above (Of course according to me).

Initial learning curve:

Spring boot has now all configurations ready to start running a project from the moment we import the project to our local development environment. You do not have to bother about setting up environment, include dependencies and figure out what version you need to use for your project. Everything you initially need, would be bundled together for you in your POM/gradle file. You can just start your development by defining all your components, and everything would wire up automatically for you. I feel spring boot has reduced the initial learning curve for getting started with a spring app.

Too much XML code:

Spring framework now has very good support for Java-config. They have heard the voice of its majority of its users to eradicate XML configs completely in their spring projects. This contributes to a better readability and make the configs and the classes that manage the configuration coupled to the project rather than having a separate file that defines the configs. This in my opinion is the biggest reason for considering to use spring for my project.

Too much magic happening behind the scenes:

Agreed, there is still lot of magic happening behind the scenes, but with a very active community and a rich documentation for spring framework, you would start realizing and appreciating the “MAGIC” that spring does to help you maintain your project.

Unwanted complexity:

It is very true that things like premature-optimizations, inculcating design patterns before the need arises are things that might over complicate a project. But there are a few qualities for a project that are good to have for maintaining the project and are often neglected when starting a project. Things like configs values being decoupled from your application, not instantiating unnecessary objects, dependency injection for better testing are a few things that are good to have right when you start your development. Spring provides many such niceties for you right when you start working on a project.

In my personal opinion, learning spring is not a big deal at all, but I feel one would be able to appreciate its benefits if they know the pain involved in maintaining and writing an enterprise application. More over, having a framework and the terminology used in the framework, would contribute a lot for anyone who is new to the project to quickly grasp the architecture and speed up the development. Spring has definitely done a great job in shaping itself as one of the best enterprise application framework and I would highly encourage anyone trying to start a project to give this awesome framework a though before deciding their project’s technology stack.

Standard