DEV Community

Jan Wedel
Jan Wedel

Posted on • Edited on

Modern Java Development is Fast

Originally posted on return.co.de

Java Development is fast - and fun. Believe it or not.

I hear a lot of Java bashing in podcasts, mostly by developers that never did professional Java development and think about Java as the crappy Java browser plugin or ugly cross-platform desktop apps.

But that's not what I am talking about. What I mean is, you can nowadays write high quality production-ready code in Java in very little time. So here is an overview about the tools and frameworks I use every day.

This next section is a bit about my background and the issues I had with Java in the past. But feel free to skip it and jump to "A new Hope".

The XML Hell

A couple of years ago, I was almost done with Java. I did years of development with Java ME (Using Java 1.3 which is not fun at all) as well backend development in Java SE with Spring 2. Plus, there were some legacy system I had to maintain running struts for the front end.

<?xml version = "1.0" encoding = "UTF-8"?>

<beans xmlns = "http://www.springframework.org/schema/beans"
   xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation = "http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">

   <bean id = "helloWorld" class = "de.co.return.HelloWorld">
      <property name = "message" value = "Hello World!"/>
   </bean>
</beans>
Enter fullscreen mode Exit fullscreen mode

A true beauty, isn't it?

I was basically sick of Spring 2 and Struts with its pile of XML that made refactoring a hell and was hard to read.

So I started the next backend project with plain Java SE. I did it completely test-driven. I was pretty fast, using IntelliJ to generate all the boilerplate code. I really took the DI "thing" very serious an over-engineered it. I had an interface for almost every class even if there was only one implementation. I did not use any mocking framework because I had some bad experience, too - with EasyMock and even PowerMock (do not use that!) and wrote all mocks by implementing the interface in a test if I needed it. I also had huge master bootstrap class that actually created the production instances and did the actual injection. That was a 500loc monster.

MyConfiguration config = loadConfiguration();
FirstClass firstClass = new FirstClass(config);
SecondClass secondClass = new SecondClass(config, "someParam");
ThirdClass thirdClass = new ThirdClass(firstClass, secondClass);

(...)

OneHundredTwelfthClass oneHundredTwelfthClass = (...)
Enter fullscreen mode Exit fullscreen mode

Thanks to very good test coverage, this application was working from the first moment on after putting it into production. The only place that I did not cover and that therefore had bugs was the SQL queries which, you guessed it, I wrote using plain JDBC.

All manually. And all because I had such a bad experience in the past using any kind of Framework.

I learned a lot but I didn't want to do that the rest of my life. So I was looking for some niche jobs like Erlang Backend Developer (I still love that language). I actually rejected a pretty good offer for a Java Dev position because they they told me in the interview that they were doing Spring. Finally, I was hired by a big company that was set on Java.

A New Hope

I was part of a new team that could chose the technologies we wanted to work with. We experimented with plain Java, Camel, Java EE, vert.x and then there was Spring 4 and Spring Boot and some other amenities that opened my eyes.

Spring - The Magic is Happening

Spring Core

With Spring core, I was obviously able to replace such an ugly bootstrap class with its @Autowire magic and, most importantly, without any XML necessary:

@Service
public class FooService {

    private final FooRepository repository;

    @Autowired
    public FooService(FooRepository repository) {
        this.repository = repository
    }
}
Enter fullscreen mode Exit fullscreen mode

This is the core of Spring: Dependency Injection. It's practically the butler, that gets you all the stuff that you need on a silver plate. You just have to call for it. Spoiler: This gets even better with Lombok, see below.

I actually dropped my "interface for each class" pattern completely except for places where I needed more than one implementation.

Spring Web MVC - Gimme Some REST

I did not need any Webserver setup or configuration, I could easily write a @Controller that returns a Java class instance that gets serialized as JSON, no code necessary.

@Controller
@RequestMapping("/appointments")
public class AppointmentsController {

    private final AppointmentBook appointmentBook;

    @Autowired
    public AppointmentsController(AppointmentBook appointmentBook) {
        this.appointmentBook = appointmentBook;
    }

    @GetMapping
    public Map<String, Appointment> get() {
        return appointmentBook.getAppointmentsForToday();
    }

    @GetMapping("/{day}")
    public Map<String, Appointment> getForDay(@PathVariable @DateTimeFormat(iso=ISO.DATE) Date day, Model model) {
        return appointmentBook.getAppointmentsForDay(day);
    }

    @PostMapping
    public String add(@Valid Appointment appointment) {
        appointmentBook.addAppointment(appointment);
        return "redirect:/appointments";
    }
}
Enter fullscreen mode Exit fullscreen mode

The code above publishes a new rest endpoint /appointments as well as two GET endpoints to retrieve all appointments and all appointments for a day as well as a POSTendpoint to create a new appointment. The class Appointment might actually be a persisted entity that gets automatically serialized as JSON. You'll get path variables properly decoded and fed into types method parameters. No additional code necessary.

See here for reference.

Spring Data

For very simple CRUD interfaces, I could use Spring Data repositories and even Spring Data REST to directly create a REST interface for my entities.

public interface OrderRepository extends CrudRepository<Order, Long> { }
Enter fullscreen mode Exit fullscreen mode

For this repository, Spring Data REST exposes a collection resource at /orders. The path is derived from the uncapitalized, pluralized, simple class name of the domain class being managed. It also exposes an item resource for each of the items managed by the repository under the URI template /orders/{id}. *

*See here for reference.

Again, a lot of magic but but pretty cool though. While scanning the classpath for Spring managed classes, it finds the interface and creates an implementation for the repository on the fly, that you actually use to fetch entities from the data base (and all the CRUD operations as well) plus it will create a REST controller that will serve requests to that repository.

Spring Integration Tests

Using Mockito to mock objects in tests works like a a charm, AssertJ for test assertions and even all-set-up integration tests using @SpringBootTest with Real HTTP mock servers and in memory data bases running a complete application test without any external resources.

@RunWith(SpringRunner.class)
@SpringBootTest
public class MyTests {

    @MockBean
    private RemoteService remoteService;

    @Autowired
    private MyService service;

    @Autowired
    private MockRestServiceServer remoteServer;

    @Test
    public void exampleTest() {
        this.remoteServer.expect(requestTo("/greet/details"))
                .andRespond(withSuccess("hello", MediaType.TEXT_PLAIN));
        given(this.remoteService.someCall()).willReturn("world");

        String greeting = this.service.callRestService();

        assertThat(greeting).isEqualTo("hello world");
    }
}
Enter fullscreen mode Exit fullscreen mode

As you see, there is a lot happing in this code. First, an actual Web Server called is started MockRestServiceServerthat will respond once /greet/details is requested. Then the service RemoteService of you application is mocked which is assumed to be called by the class under test MyService. When the method someCallis called, it will return "world". At the end, a verification using AssertJ is done.

Spring Security

The only downside was using Spring Security which does authentication and autorization. It comes with a variety of ready to use implementations as well as the option to write your own AuthenticationProvider. Unfortunately, IMHO it is designed badly (from the usability perspective) and even worse documented. Once you're starting to customize it the slightest bit, It never works as you would expect and you'll end up spending hours and days fixing it by trial and error. Simply put, Spring security sucks most of the time. I hope there is some overhaul done soon.

Spring Boot

Spring Boot makes it easy to create stand-alone, production-grade Spring based Applications that you can "just run". We take an opinionated view of the Spring platform and third-party libraries so you can get started with minimum fuss. Most Spring Boot applications need very little Spring configuration.

  • See here for reference.

Spring boot puts together all bits an pieces, applies a sensible default configuration and your good to go.

If you want a very funny and very good live coding example, I highly recommend Josh Long's video "Bootiful" Applications with Spring Boot - Wow, such great!

JPA / Hibernate

When I once used Hibernate years ago, there was also that XML configuration hell I described earlier. But with recent JPA, you just do

@Entity
public class Customer {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  private Long id;

  private String firstname;
  private String lastname;

  // … methods omitted or replaced by Lombok
} 
Enter fullscreen mode Exit fullscreen mode

See here for reference.

and together with the Spring Data Repositories, you can access your entities easily. That means, that you're simply describing the data you are working with and you don't have to deal with how to get them.

The best thing is, you do not need to write any SQL. Hibernate is very good at creating optimized queries. It will pull the data from the database and maps it onto the @Entitiy class. If you you have some ugly names for tables or columns, you can simply annotate the fields. The above class expects a table CUSTOMER with columns ÌD,FISRTNAMEandLASTNAME`. You can customize everything you want if you need to access a legacy DB, e.g..

Lombok - No More Getters

When Java 8 came out, I was pretty impressed on how this old language was able to evolve. However, two things were missing from my point of view: Pattern Matching and a way to get rid of getters and setters.

We still do not have pattern matching (as e.g. in Erlang), but - and this is truly amazing - we can get rid of getters and setters by using a library. A lot of frameworks rely on the existence of getters and setter, Hibernate, Jackson and Spring itself.

When I first saw Lombok I thought this must be some code generation magic or - even worse - some runtime reflection trick. Plus, the website looked like it was from the 90ies. But when I checked it out, it turned out I was completely wrong. They are using a javac feature, compile-time annotations. So during compilation, Lombok's code is executed and generates additional byte code which generates no additional runtime overhead (compared to writing getters and setters manually) and no intermediate Java code.

Remember the FooServicefrom above. Using @AllArgsContructor, Lombok generates a constructor for all members.

`java
@Service
@AllArgsConstructor
@Sl4j
public class FooService {

private final FooRepository repository;
private final MyProperties properties;

public getUri(String path) {
    log.debug("Building uri from base Url {} and path {}", properties.getSomeUrl(), path)
    return properties.getSomeUrl() + path;
}
Enter fullscreen mode Exit fullscreen mode

}
`

Using @Sl4j, we get a free logger (instead of doing Logger.getLogger(...)) and there is more good stuff like generating @ToString and @EqualsAndHashcode.

With Spring 4.3, you can even drop @Autowire completely.

`java
@Configuration
@ConfigurationProperties(prefix = "my.app")
@Getter
@setter
public class MyProperties {

private String someUrl;
private Integer someTimeout;
Enter fullscreen mode Exit fullscreen mode

}
`

The above code can be used as spring properties to configure the application. You might argue that this snipped has more annotations than code and that's true. But I'd still prefer it over writing all the boiler-plate code myself.

It allows you to write a YAML file like the following an drop it next to the jar to change configuration:

yaml
my.app:
some-url: http://foo.bar
some-timeout: 5000

Yes, it will automatically allow you to use proper naming like some-timeout still know how to map that onto someTimeout. You'll get type safe configuration for you application for free. You can even add @Validated together with e.g. @Max(1000).

Maven

Maven is the library management tool. Ok, Maven is a lot of XML, ok but it just works like a charm. I've worked with Ant and it was so painful to get the same result.

I was looking forward to use Gradle in an Android project and oh my gosh, this really bad. You'll need to write executable scripts that can do anything (and do do anything, especially in cases where you don't want it). You never know if its a method you're calling or if its configuration. I ended up spending hours and days printf-debugging my build script until it did what I wanted.

Just because of XML, Maven is well-defined and and you're almost not able to break stuff in a way that was not intented. Maven is library dependencies done right, especially when you compare it to other "package manager" that are loading code, build it (XCode, Erlang) or crap like NPM and Bower. Maven is just an integrated part of you build process, there is no need to download a library upfront like in pip (Python), you'll always get the exact version of that lib for that very project you're building.

Java

As mentioned above, Java 8 comes with some functional features and Lambdas are pretty handy although they aren't necessarily functional. Streams look great at first but most of the time you'll end up with spaghetti code that no one (not even you after one week) can read. Most often, you're better off with a good old for loop.

But generally, it try to write functional code (which was possible since the first version of Java) as much as possible. That means, a method should always return a value (not void) and it should always return the same value for the same parameters. This requires to

  • Not use system calls (like currentTimeMillis())
  • No interaction with files, DBs etc.
  • Use class variables

Obviously, if you do that a 100%, you're application is completely worthless because you have neither a way to control it nor to get any output. So what I try is to keep my core business logic as clean as possible and move the side-effects as far outside as possible. This benefits testing a lot.

IDE

I actually transistioned through a lot of IDE in the past, starting from QBasic, Turbo Pascal, Visual Studio, Eclipse, NetBeans, XCode and even vim. But I lost my heart to IntelliJ IDEA which is just the single best IDE I've ever used. It starts with beeing beatiful and fast, supporting very good and intuitive keyboard short cuts, you can auto-type and auto-filter all menus, even context menus. It allows to use powerful refactorings and generating code for you. I supports very good debugging as well as showing code coverage in line.

You might be happy with your IDE right now, but you should have at least tried IDEA once and watch a video about the features.

Especially when I used XCode for an app project I did, I felt like in the stone age compared to IntelliJ. Unfortunately, even JetBrains AppCode still requires XCode for some things.

It's the Eco System

So, it's not about the language. Its not about the IDE or the build tool. It's every thing together that makes Java development fast and fun.

Top comments (11)

Collapse
 
martin profile image
Martin Beentjes

I currently work at a small company where we mostly work with Java 8 and Spring (Boot). I learned a lot in the eight weeks of development I did now.

The framework is really awesome in the way how they do things. Something like the Spring Data CrudRepository. I find it fascinating to see how I only define a method in an interface which then just works. Only issue: damnVeryLongMethodNamesWhereAColumnIsLikeVeryAwesomeButIWantToOrderWithThatAndThenDoThisAndThat();

But then just annotate a method. It is fun, and is really fun to explore and learn to work with the framework. I am loving my job and the way my career starts.

My personal goals currently are to get into Java and Spring. Just so I should be able to build a whole project by myself as a developer (with the designs from a designer). If that goal is reached, I want to start working on my knowledge on .NET Core as that is the 'other camp'.

For now: Using IntellJ + Java 8 + Spring = AWESOMENESS.

Collapse
 
bousquetn profile image
Nicolas Bousquet • Edited

So we use java 8 and lambda there. We don't really use lombok, but our data domain is generated and does more boilaplate generation than that. Lamda expressions are powerful if you don't stick to legacy java collection API. It make code much shorter lighter/readable if you don't abuse it. Don't do a 10 deep deep lambda expression in a one liner or in a single method like you wouldn't do a 10 folded loops neither.

We enforce absolutely itf/impl separation because that the most powerfull tool at our disposal to keep a multiperson project really modular. And for that we need both interfaces and impl in separate mvn projects. The impl project has scope runtime, so only spring with its classpath scanning actually see it. But then the itf are needed to access the impl. Pending Java9, or using even more complex OSGI, I don't know of a way to enforcing the rule that you do not access other modules implementation.

We ensure that most objects ref are never null in our business domain so we can alway do things like a.getB().getC().setD(ddd) without having to check if B/C/D exist and if there a collection in the middle we can then write a.flatMap(A::getB).flatMap(B::getC).forEach(c -> c.setD(xxx)) if we want to update everything deep in a complex object tree structure with a one liner.

Object relationnal mapping is nice, but from experience it is extremely easy to get very low performance out of it for any non trivial work. The generated DB is also hard to maintain and evolve in production, to write the migration scripts and all. I'd advise to design the DB completely separately from the code, to optimize it for the queries you need and check with you DBA how to get the most out of it. You'd map you data objects structures to the actual queries inputs/ouputs rather than tables. Because that's what matter. You'll get several order of magnitude better performance.

spring itself is really valuable as well as annotations but they tend to lead to subtle bugs on the occasion and quite subtle performance problem too. It is common from one person to strugle for 2 day to map a basic property file to a spring bean because it doesn't work for some reason while it is done in 5 minutes with getResource and the use of the proper parser of choice (JaxB, Jaxson...). We do use spring for dependency injection among service, it is our prefered choice for itf/impl pattern we use but we try to avoid it inside components. This make the code more straightforward and easier to understand, keep the number of beans to wire under control so that you server doesn't take 30 second just for spring initialization at boot time and slow your whole day to day dev activities too much.

I'd say in the end this depend a lot of your applications, your requirements and all. We are sentisitive to performance because basically a single client already ask for 6000TPS for our service and if this service is a success in the company, we will be soon at 15K-30Ktps, growing 50-60% a year. Soon the amount of servers to buy, replace and the power consumption requirement are costing much more than the easier dev practices that hurt performance too much.

But that depend of each project. What are the requirements, the size of team, the expected code size base, the kind of stuff you do and so on...

Collapse
 
stealthmusic profile image
Jan Wedel

Thanks for your reply.

I wonder what you mean by “multi person project”. We do work on projects in a scrum team with 3-6 developers. At that size, there is absolutely no issue with not having interfaces. Less interfaces means less code to maintain and less complexity when understanding and navigating through the code.

Same goes for JPA and performance, we’ve actually had very complex queries modeling a kind of hierarchy and using lazy loading, it was very fast and very handy.

So, basically, I would not start optimizing for theoretical modularity nor performance without actual issues or requirements.

Collapse
 
bousquetn profile image
Nicolas Bousquet • Edited

"So, basically, I would not start optimizing for theoretical modularity nor performance without actual issues or requirements."

And you are right. Because you don't need it, apparently.

On our side we have requirements for performance and scalability.

With the experience, you know what works and what don't.

So yes when I think about a multi person product I think dozen, hundred, not 3-6. Sure each team/project maybe 1-10 persons, but you may have 20 at the same time.

When a product is successful there, it means it is used wordwide by millions of end users. We need to be able to serve the internet. 10% decrease in performance means several millions euros for the machines, the electricity and so on.

That's the biggest issues of advices, what works, what not. But what are the circonstances ?

For you, all that fuss would make you less productive because you are a small team and there no req. for performance. You don't need modularity because the code base is small. For my company, your methods would work for a prototype, no more.

For a company like airbus or thales that design auto pilots au make lot of embedded devices software, your methods of mine would make absolutely no sense. Each line of code is validated and revalidated. The same product has several implementation running at the same time by different teams and languages so that if one autopilot fail, the other one can be used instead.

For many startups and geeks, using Java and so on would again make no sense. They would do it in haskell or lisp and would go 10 time faster than you, 100 time than my company.

That the whole argument about theses thing. Nothing absolute.

Collapse
 
adityasridhar profile image
Aditya Sridhar

Excellent article. Thanks for taking the time to write this. Lombok is something new to me :D

Collapse
 
stealthmusic profile image
Jan Wedel

Just saw the broken formatting starting at the Lombok section, now it’s fixed. 😉

Collapse
 
rnvdrs profile image
Rony Vidaur

I feel the same way, Java 8 and spring boot absolutely blew my mind, I used to have a closed mind towards Java due to previous experiences and now I am truly enjoying it, loved your post :)

Collapse
 
eliotpearson profile image
Eliot

Nice article. I see a small typo above. I believe 'boostrap' should be 'bootstrap'.

Collapse
 
stealthmusic profile image
Jan Wedel

Great, thanks for the feedback, I corrected the typo!

Collapse
 
matiasagnolin profile image
Matías

And what about the client side? JSTL? or what?

Collapse
 
stealthmusic profile image
Jan Wedel

We actually use Angular 4 with Typescript which pretty much looks like Java/Spring Code. If you don’t want to use rich clients, maybe Vaadin or Thymeleaf might be an option. Vaadin allows rapid prototyping but if you need to implement UX requirements and designs 100% accurately you might get in some trouble.