DEV Community

Cover image for Java Counter Culture - Cultural Javism
Fernando Ollé
Fernando Ollé

Posted on

Java Counter Culture - Cultural Javism

What is Cultural Javism?

Haven't you heard about Cultural Javism? It's terrible! đŸ˜±

For those unaware, here's a taste of it.

You know when all our peers are writting classes like this, and this point you're to afraid to ask "why?":
WARNING: Please don't waste time reading the complete code of EnterpriseAddress class.

public class EnterpriseAddress {
  private String street;
  private String number;
  private String zipCode;
  private String city;
  private String state;
  private String country;

  public EnterpriseAddress(String street, String number, String zipCode, String city, String state, String country) {
    Validator validator = (new ValidatorFactor).getValidator();

    this.street = street;
    this.number = number;
    this.zipCode = zipCode;
    this.city = city;
    this.state = state;
    this.country = country;
    validator.validate();
  }

  public String getStreet() {
    return street;
  }

  public void setStreet(String street) {
    this.street = street;
  }

  public String getNumber() {
    return number;
  }

  public void setNumber(String number) {
    this.number = number;
  }

  public String getZipCode() {
    return zipCode;
  }

  public void setZipCode(String zipCode) {
    this.zipCode = zipCode;
  }

  public String getCity() {
    return city;
  }

  public void setCity(String city) {
    this.city = city;
  }

  public String getState() {
    return state;
  }

  public void setState(String state) {
    this.state = state;
  }

  public String getCountry() {
    return country;
  }

  public void setCountry(String country) {
    this.country = country;
  }
}
Enter fullscreen mode Exit fullscreen mode

When you could have this:

public record Address (
  String street,
  String number,
  String zipCode,
  String city,
  String state,
  String country,
) {
  public Address {
    new Validator().validate();
  }
}
Enter fullscreen mode Exit fullscreen mode

Or even this if you don't have records, and don't mind/want mutability:

public class SimlpleAddress {
  public String street;
  public String number;
  public String zipCode;
  public String city;
  public String state;
  public String country;

  public SimlpleAddress(String street, String number, String zipCode, String city, String state, String country) {
    this.street = street;
    this.number = number;
    this.zipCode = zipCode;
    this.city = city;
    this.state = state;
    this.country = country;

    new Validator().validate();
  }
}
Enter fullscreen mode Exit fullscreen mode

And who has yet to see a Java app like this?

Image Java app with many many directories

When you could have a little app like this for the 25 users of your back office system:

Image Java app with very few directories

But what is Cultural Javism anyway?!

Where are we going with this?

This culture is like your company's legacy code base, only from Java distinguished Well Fargo's engineers.
It's a culture from when everything was grass hills; everything was more complicated, including Java.

Image Windows XP default grass hill wallpaper

But let's not bite the hand that used to feed us, right? At some point, somewhere, it was all useful; there were no simple tools to solve problems that are trivial today. As an illustrious friend says,

"Many stones have been broken in today's backend engineering."

Sadly, many small companies believe they need to set up an extremely scalable, decoupled environment, with clean arch, ports & adapters, super modern, 500 abstractions, and complex. Why?
So as to avoid having a legacy system with technical debts.

For that I say, when does a system become a legacy? :
The exact moment you deploy it.

As my illustrious wife says,

"When you git push, your code has already become legacy."

How to fight legacy

Note that legacy and technical debt are different things; code that was sent to prod without testing because the boss was demanding it can quickly generate a technical debt, while legacy is simply something that is in the said company's history.

But I believe that a good way to achieve LEAGACY OBLITERATION! is to deliver your code as quickly as possible, make it as simple as possible, and, of course, tested, you bastard!

After all, if it doesn't meet your requirements, you didn't spend 2 hours of your day just deleting example files from the company's clean arch template. If there's a problem, your flow isn't abstracted into 20 layers and spread over 3 superclasses and 5 interfaces, so changing it will be simple because you made your system simple.

That's right, buddy; you don't need an interface for every service on your spring-boot app. You're not going to change your database.

Image Pointing Akon meme saying

And anyway, how much will those abstractions help you in the very rare event that you have to change databases?
Wouldn't placing your methods separately in another file do the trick?

At this point, you might be thinking, "But how am I going to scale a system for 100 million users in a simple way?".
Yeah, you won't!

The point is that your ERP system, which serves 5 companies with 25 employees each, doesn't need to worry about having a multi-cloud system like Netflix.
Your cron-job, which takes 5 seconds to run and executes 3 times a day, doesn't need 3 layers of ports & adapters.

Back to the point: Cultural Javism.

We talked about getters and setters, clean arch, ports & adapters . . . something about multi-cloud and ERPs with cron-job. What's the point of all that?

In simple terms:
People think Java is verbose, slow, and old because of the Javistc culture surrounding most Java projects you see on the market.

But don't worry, here's the answer to all your problems:

Image Take on water tank meme image

Java, especially modern Java, can be super simple and concise.
And by the way, Java is modernizing faster than ever after 2018, with 2 versions per year and 1 LTS version every other year.

To prove this, here's an example of a service that parses dates on the required AWS Cognito's format, using only Java's native APIs. You don't need to use Spring Boot for everything:

import com.sun.net.httpserver.HttpExchange;
import com.sun.net.httpserver.HttpServer;

void main() throws Exception {
  var server = HttpServer.create(new InetSocketAddress(8080), 0);
  server.createContext("/", httpExchange -> cognitoParsedDate().ifPresentOrElse(
          date -> send(httpExchange, 200, date),
          () -> send(httpExchange, 500, "")));
  server.start();
}

Optional<String> cognitoParsedDate() {
  try {
    TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
    var dateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzzz yyyy", Locale.ENGLISH);
    return Optional.of(dateFormat.parse(new Date().toString()).toString());
  } catch (ParseException e) {
    return Optional.empty();
  }
}

void send(HttpExchange httpExchange, int code, String response) {
  try {
    httpExchange.sendResponseHeaders(code, response.length());
    var outputStream = httpExchange.getResponseBody();
    outputStream.write(response.getBytes());
    outputStream.close();
  } catch (Exception e) {
    throw new RuntimeException(e);
  }
}

Enter fullscreen mode Exit fullscreen mode

It's not even 50 lines long; it's a single file and requires no external dependencies.
And to prove this point even further, here's the same service in JavaScript:

const http = require("http");

function getFormattedTimestamp() {
  const date = new Date();

  const dayOfWeek = date.toLocaleString('en-US', {
    weekday: 'long',
    timeZone: 'UTC',
  });
  const month = date.toLocaleString('en-US', {
    month: 'long',
    timeZone: 'UTC',
  });
  const day = date.toLocaleString('en-US', { day: 'numeric', timeZone: 'UTC' });
  const year = date.toLocaleString('en-US', {
    year: 'numeric',
    timeZone: 'UTC',
  });

  const time = date.toLocaleTimeString('en-US', {
    hour: '2-digit',
    minute: '2-digit',
    second: '2-digit',
    hour12: false,
    timeZone: 'UTC',
    timeZoneName: 'short',
  });

  const [timeOnly, timeZone] = time.split(' ');

  const parsedDate = `${dayOfWeek} ${month} ${day} ${timeOnly} ${timeZone} ${year}`;
  console.log(parsedDate);

  return parsedDate;
}

const host = 'localhost';
const port = 6666;

const requestListener = function (req, res) {
  res.writeHead(200);
  res.end(getFormattedTimestamp());
};

const server = http.createServer(requestListener);
server.listen(port, host, () => {
  console.log(`Server is running on http://${host}:${port}`);
});
Enter fullscreen mode Exit fullscreen mode

Still, on the example's domain, a "Cognito Utils" service, would it be difficult for you to modularize this?
"Oh, there's no way to maintain that code! It's everything in one file!"

Just split it up a bit, put the endpoints in a file, separate the business logic by niche, a file for Dates (yes, Cognito uses dates in this terrible format), and one to deal with SRP; you can have a file to generate keys for SRP validation, another for the logic part, sprinkle some little interfaces here and there and you are good to go!
Do you really need a clean arch template for everything?

Take ways

For those who agree with the Rebellious nature of Javistc Counter Culture, that's it; you've got the point: get yourself into a startup. 👍

And for those who disagree, if you're a great lover of clean arch and clean code, I'd like to make a few proposals for you:

Make a simple version of what you do at work, using only what the latest Java has to offer. It won't be that difficult.

After that the next step would be:
Refactor the parts where the Java native APIs aren't "ergonomic", put in loose Spring packages or any lib from the maven repository and JitPack that you think is cool.

At this point, you've probably already been brainwashed by the JCounter Culture, so the last step toward true freedom from 90's conglomerate's way of life is:

Image Badass motorcycle dude riding its bike looking sideways

When you need to make a little script, for anything, that script for parsing a log, scraping data, even a CLI, in short, anything simple that you do with that interpreted lang, like JS or Python an so on, try to study it and do it with your friend, the little Java lang đŸ„č, you'll see that it's not that complicated, in some cases it may even be easier than with that interpreted lang.

Finally, for those who didn't get the point, call me on Xwitter, BlueSky, Github, Linkedin, Smoke Signal, or anywhere you want. Let's exchange ideas. <3
Thank you so much!

Continue reading about related topics:
Computaria: The lies you were told about OOP

Top comments (12)

Collapse
 
citronbrick profile image
CitronBrick

Speaking about counter-culture, as I fullstack developer I feel with ES6+ & Angular2+ especially,
JavaScript is trying to become like Java.

Collapse
 
lionelrowe profile image
lionel-rowe • Edited

If by "ES6+" you just mean the class keyword and the associated classical OOP features, I can see the argument. But most of the features since ES6 have nothing to do with classical OOP, so if anything it's just continuing to diverge further away from Java. Usually new TC39 proposals cite Java implementations as prior art only among a large number of other languages, and it rarely seems to be the biggest influence design-wise.

Collapse
 
lionelrowe profile image
lionel-rowe

Maybe I'm missing something as I don't know much Java, but how does validator know what it's validating when it's called as validator.validate()? Surely it needs to be validator.validate(this)?

Collapse
 
nandoolle profile image
Fernando Ollé

In this example, the validator only illustrates what you can do within the custom constructor of record; on a real code base, you would most likely need a different implementation for the validator. Or you can opt for an even more straightforward implementation without any validator.
I'm studying DOP lately, so I felt like a validator feat nicely on this example.

PS.: The validation can be done like this: new Validator.validate(), using reflection, but it's not a standard (nor a simple) way to do it. I strongly do not recommend the usage of reflection to do this.

Collapse
 
authbigvertex profile image
James Hogan III

I'm glad i'm not the only one confused by that

Collapse
 
seanevans profile image
Sean Evans

I worked on some projects with Kotlin until I discovered that I couldn't avoid NullPointerExceptions from third-party libraries.

Now, I use modern Java too.

Collapse
 
seanevans profile image
Sean Evans • Edited

I strongly agree with Fernando's point in this post, and I wrote a related short post: Get Started with Modern Java Today: A Concise Guide

Collapse
 
shrsv profile image
Shrijith Venkatramana

One often wonders how the JVM turned out so good, while its de facto language turned out so poor.

I've always been a spiritual member of the Java counter culture - so consider me part of the movement :)

Collapse
 
seanevans profile image
Sean Evans

Kotlin is a good JVM language (when using third-party libraries written in Kotlin)

Collapse
 
leonardorafaeldev profile image
Leonardo Rafael Dev

You are the only person in the world who makes Java good, big fan

Collapse
 
nandoolle profile image
Fernando Ollé

Thanks!! đŸ˜â€ïž

Collapse
 
felipe_falkiner profile image
Felipe Magosso Poveda

Awesome!