Web Development Comparison: Spring Boot vs. Express.js
Has JavaScript become better for server-side development than Java? It might just depend on the app under development. I can hear the moans from the Java devs now...
Join the DZone community and get the full member experience.
Join For FreeA simple comparison of web development using the Spring Boot ecosystem and JavaScript with Express, from a Java developer's point of view.
The Goal of This Article
This is a not so technical comparison (you can find more specific tech comparisons elsewhere). I just wanted to outline how it feels to develop web applications in Node.js when you are a Java developer by trade.
So please remember, this article is full of personal opinions.
Before starting, I outline a few premises:
- I’m a software developer working in the Java language. I’ve been developing Java-based software for about 15 years.
- I’m currently learning JavaScript development (I’ve been writing front-end JavaScript since 2007, but server-side JavaScript has become its own beast).
What I'm Trying to Compare
I would like to highlight some of the differences that are perceived when developing an application based on the Node/Express stack compared to one based on Spring Boot.
Why I'm Comparing These
TL;DR: After completing a contracted project, I decided to test another ecosystem to check if it could avoid some of Java's most criticized points.
One of my last customers was a company that was creating a crypto exchange (yes, quite a common thing in today's market, but not so common for an Italian based company). They contracted me to join their teams (three different developing teams) and help them build their platform. I mainly developed microservices for authorization and authentication, core transactions processing, and other stuff like customers’ KYC microservices and code libraries shared among different microservices.
That was a big and interesting project.
But during discussions with other teams and people I often heard critiques of Java-based web development in favor of Python or Go. Some of the critiques on Java that the other languages seemed to not suffer from were:
- Java is verbose.
- Everything is interface-tangled in Java.
- The memory consumption of Java apps is overwhelming.
- Disk space consumption can also be overwhelming.
- Development requires a lot of time.
3. and 4. should be considered when spinning up hundreds of Docker-based microservices but I think that this scale problem may be nonsense, since, if you have hundreds of microservices running, your organization is probably fairly profitable and you can afford “expensive” instances to support memory-greedy Java applications.
I must be honest, sometimes I think that in 2019 all of the five points above are really reasonable critiques so I wanted to experiment with self-funded projects to test some other technologies.
Since I needed to do web development and not necessarily microservices-based projects, after a quick (really quick) look at GO, I decided against that language. I think it is a great language (from what I read) but it’s not the right tool for my current projects.
So I looked at Python and was starting in with Python but I needed to write some JavaScript code because I was going to use Puppeteer as a fundamental component for PricePaladin (a tool for price tracking and monitoring) and after reviewing a very good comparison of languages I decided to go with Node.js.
Comparison
Language
If you are a Java developer, you’ll find JavaScript is not so hard to learn. You’ll surely freeze when you deal with callbacks though. You’ll discover Promises and, at the end of the day, you’ll use the async-await syntactic sugar that brings everything back to normal.
That said, JavaScript will sound a little bit weird, but today’s JavaScript is definitely okay (as I said before, it’s not 2015’s JavaScript). It is simple, quite powerful and concise.
I leave to you all the observations regarding dynamic typing, which, in my opinion, isn’t a big deal.
Node.js Is Single-Threaded
Okay, this is one of the most “shocking” things for a Java developer. But the shock vanishes after a few moments. You should consider that everything runs on a single thread (on any Java web app you have multiple threads) and that callback functions (asynchronous functions) are queued and executed when it is better to execute them, but all the code runs on a single thread (the key to Node.js’s speed and low memory consumption). From a Java developer's point of view, this means:
- Don’t run CPU-time intensive code or everything will wait for the CPU to be free before executing a new queued function.
- If something goes wrong and Node.js crashes, then everything crashes: in the case of a web application serving multiple concurrent requests, all the requests crash. You don’t have the isolation that you have with a Java web application.
The JS Equivalent to the Spring Boot Ecosystem: Express.js, Passport.js, Sequelize
If we limit the comparison to the MVC web application part only, Spring Boot is definitely fabulous: light and fast, complete and extremely configurable. From this point of view, a Java developer does not feel any major shortcomings compared to what the counterpart of Express.js offers.
Express.js also offers the same potential. One thing that, depending on personal taste, can be more appreciated or not is the routing: instead of being defined at the level of Java annotation it is defined at the level of routing files.
More generally, Spring Boot indicates a very precise way to organize code into packages (models, services, controllers) while in an Express.js context there are no such guidelines. Nevertheless, it is possible to reapply a similar code structure and there are often projects where the code is structured in a similar way to a Spring Boot project.
For the authentication part, Spring Security is the “ultimate tool”…but it is also a “beast to tame” if used for some particularly complex cases. The JavaScript counterpart is Passport.js, which is very powerful but less structured and mature. Nevertheless, you have the feeling that it is able to handle the same cases and conditions as Spring Security. In any case, the development of common authentication mechanisms such as authentication by JWTs or other common auth mechanisms are also widely supported by this framework. The maturity of Spring Security has yet to be matched by Passport.js, but the perception I have had is that 80 percent of the features offered by Spring Security are implemented in Passport.js too, in a way that is sometimes simpler.
ORM in Java has always been, from my point of view, the Achilles heel of Java applications. The Java standard is roughly Hibernate (despite the various alternatives, however widespread, such as Jooq and MyBatis), while, for the JS world related to relational DBs, the most popular library is Sequelize.
Hibernate vs. Sequelize
TL;DR: Hibernate is still the most complete, mature, and versatile solution, but at a very high cost! Sequelize may cover 90% of your use cases.
I don’t hate Hibernate, but I surely don’t love it. It’s over engineered, slow, and complicated. It’s like an elephant. It can, however, do anything with any supported DB. On the contrary, Sequelize is small and simple but can’t manage all use cases.
Some of the things I discovered through the use of Sequelize:
- You’ll have a not so hard but definitely not so easy time trying to use snake case for a table’s fields. You can manually specify them one by one (but that is outrageous) or you can use some hack to convert names to snake case. That is a simple solution but it has the drawback in that it will break the migration command line tool. Anyhow, it is unacceptable that all the requests used to introduce flexibility to naming convention definitions were discarded and ignored.
- It doesn’t fully support composite keys. As clearly stated here, “While it is possible to create composite primary keys in Sequelize […] Sequelize doesn’t currently support composite foreign keys, so there is no way to reference a model/table which has composite primary keys.” Again, from my point of view, this is immaturity.
- You’ll have to do some nice tricks to manage date fields due to timezone interpretations (that was really unexpected).
- When adding instances to the fields that are related among two entities (such as Book and Author, for example), entities are immediately saved. This is not a big deal but shows that Sequelize is far less sophisticated than Hibernate, which has internal mechanisms to decide when to flush data.
There are also some things that I love in Sequelize, like the easiness to create queries at runtime (that’s a breeze, you can compose a JSON object at runtime and pass it to the query engine). Try to do it while creating a JPQL query or consider how overcomplicated it is to do with certain criteria. Honestly, using Hibernate and Spring Data JPA while trying to dynamically filter a query at runtime by some fields is a pain in the ass, while it is really easy (as it should be with any framework/language) to do in Sequelize.
Another aspect where Sequelize shines in respect to Hibernate is when you hit some hard cases and need to do a native query: both of them let you execute native queries, but, honestly, it is a lot simpler to convert the results to their models in Sequelize than in Spring Data JPA/Hibernate.
And I’m not talking about startup time: introducing Hibernate adds seconds to boot time, while Sequelize is quite immediate.
As a final consideration, it's quite obvious that:
Sequelize is a lot less mature than Hibernate,
Hibernate is capable of doing anything while Sequelize covers only 90% of use cases.
Sequelize is a lot less abstract, and definitely easier to work with.
This can be a great advantage, especially when you own the DB schema, don’t have to adapt to legacy DBs, and you don’t plan to migrate the DB engine one day (to be honest, I’ve seen only one case of DB migration in all my life and it was when two banks decided to merge and so it was decided to keep only one IT system and rewrite the code of the abandoned one to the other platform. There were thousands of store procedures to be rewritten, so code portability, in my opinion, when talking about ORMs, is a useless feature.)
Final Considerations
I’m currently using the described JavaScript stack for my current and so far I'm very happy with it. PricePaladin (a tool for price tracking and monitoring) was built using the above mentioned stack and is currently deployed to an inexpensive server due to its low memory footprint.
Working with JavaScript brings you a greater level of simplicity. It is ideal for scripting and standard web development, but I wouldn’t use it for complex projects (except for small dedicated and isolated microservices) nor would I use it for numeric applications or applications where numbers count (like a crypto exchange where Java and its BigDecimal
class are perfect for that scope).
Ultimately, the general feeling I have when developing server-side JavaScript is that everything is a bit simpler and less cumbersome than an equivalent Java-based app, although I have a strong perception that there is a lack of stability and maturity in respect to the libraries offered in Java (a lack that is real only if certain libraries are needed for the specific project, otherwise it makes no difference).
Another perception is that the JavaScript development cycle is about 20% faster. By this, I mean that due to more verbose code and over-engineered structure of Java applications that adhere to classic guidelines and time spent rebuilding the code, you spend a lot more time developing the same features in Java than in JavaScript.
Therefore, where the application does not provide calculations or blocking processing, and is concerned with the development of a classic, small web application, I would almost certainly opt for development with the JavaScript stack described, while in other cases I would base the application on the Spring Boot stack that, in the long run, in my opinion, offers greater maintainability.
Published at DZone with permission of Plebani Alberto. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments