C# developer going Java

DEVELOPMENT -️ December 24, 2022

What

I will be going over some of my experiences, observations and annoyances of having to switch to Java. These are opinions based on having worked with Java for more than 2 years, as well as having developed in C# for more than 3 years before that.

Disclaimer

I would like to add a minor disclaimer to this post to avoid misunderstandings. I will be stating both positives and negatives on the Java ecosystem which are my opinion, and my opinion only. These opinions are subjective, and might not align with your experiences, which is certainly a possibility.

I simply do not want this post to invoke a flame war, as I think this is a topic that can be talked about in a non-harming way.

The switch

The decision to switch was made due to company where I was employed not seeing the business value in continuing to develop applications in C#. This choice was also facilitated by the fact that there was an in-house framework written in Java that the business believed to be delivering more value for customers at the time.

Having written primarily C#, having to switch to Java was hard. I was forced to learn a lot of things from scratch, and leave C# behind.

I've always thought the language or framework with which you develop is merely the tool you make the product with. If the tool is the best tool to create this product, you should be using it. The problem here is that at the time I did not agree with the business' beliefs of having to drop C# due to X being better.

Language

I had 'learned' Java before in school, it's a common language to be taught in higher education, so generally I knew what I was getting into.

After a few weeks, there were quite a few things that were jarring to me which I will be explaining next.

Version

There's still so many projects in the wild on Java 8. Honestly, there's a big difference between Java 8 and for example Java 11 in terms of productivity.

  • Lack of static factory methods such as Set.of() which were mostly introduced in Java 9.
  • Lack of certain functional style functions which improve readability greatly such as the Optional.ifPresentOrElse() method

New projects were generally started on Java 11 due to compatibility reasons, even though Java 17 has been an LTS release since September 2021.

Syntax and syntactical sugar

Having worked with C# there's some obvious things I missed in Java:

  • LINQ. Java's Stream's are LINQ's counterpart, but IMO with a less straight forward API. To me, it seems like most of LINQ's features can be converted to the Streams API, albeit being a bit more verbose.
  • Possibly a very nitpicky point, but why are lamda's written with a dash? ->. It took a while getting used to this as I was used to using => from C#, JS and TS.
  • Lack of operator support when using numerical values. Ever heard of the BigDecimal memes? It's true, the API feels clumsy to work with, as it forces you to chain a lot of methods to create simple calculations. The biggest problem with this is readability as it takes a while to understand what kind of calculation is actually happening. BigDecimal meme
  • Getters and setters. Don't get me wrong, getters and setters are needed for writing good encapsulated code, but it's obvious they are a problem in Java and add to Java's verbosity problem (more on this later). There's even an often used library called Lombok that hooks into your IDE and build tools to generate these getters and setters for you.
  • Lack of features such as:

    • No type erasure on generics (this one really tripped me over)
    • Pattern matching (I believe there's a beta for that in Java 17 though)
    • Simple asynchronous APIs and threading APIs (Project Loom anyone?)
    • Extension methods (Although I do understand that purists may not like them)
    • Properties instead of getters and setters
    • Nullability checking in an 'easy way' (think of the null-coalescing operator ?? or the is null construct)
    • Nullable safe type casting with as
    • Tuples
    • Deconstructor
    • Real String interpolation without public format APIs (I do believe there is a horrible looking proposal though https://openjdk.org/jeps/430)

Naming conventions

  • Java has it's own naming conventions. And that's a good thing, naming conventions make readability easier for every developer out there. There is however a big downside. Java class names tend to be very long. It's not uncommon to see interfaces and classes like: EntityViewElementBuilderService interface paired with the EntityViewElementBuilderServiceImpl implementation. Java long class names meme
  • The astute amongst you will have probably noticed that Java developers tend to, as a general rule (YMMV), add Impl to their classes when they implement a certain interface. This is however four letters you do not want for your already long class name.
  • Looking at this, I personally prefer the C# way of adding an I to the interface and not postfixing the implementation. The I prefixing also helps with searching directly on the interface, which comes in handy if you were planning on trying to search every implementation of this specific interface that you just found in an instant by looking for IHazCookiez.

Tooling

There's a ton of good tooling in the Java eco-system, let's get into it.

Build

Every project I have worked on used Maven. I am sure Gradle works just as well, but I haven't had any experience with it yet.

Maven has a lot of going for it, it uses a pom.xml which contains management declarations for dependencies, repositories and plugins. The pom.xml is very comparable to the .csproj files in C# projects, bar it being a bit more verbose.

The only annoyance I've had is you usually have to mvn clean to get a dependency change working or even have to use the IntelliJ refresh button for things to get picked up properly. IntelliJ refresh dependencies button

This might just be an IntelliJ thing so YMMV.

IDE

There's multiple Java IDEs out there. In a work setting I've only worked with Jetbrains' IntelliJ which has served me well. I have toyed around with Eclipse and Netbeans before but unfortunately they did not feel as complete als IntelliJ to me.

I've used Jetbrains' C# counterpart called Rider before and actually prefer it over Visual Studio for web development.

In general IntelliJ just works for everything you need in Java development. It truly is a product built by Java developers for Java developers, and it shows.

There's some quirks though:

  • Sometimes you get this issue where your projects go total foobar, the syntax highlighting is broken, compilation is broken, and the only thing left to do is to execute the nuke option: to restart and invalidate caches. Having to do this once in a while isn't the worst, but at the speed Java projects index, you might as well take a coffee or toilet break while IntelliJ is indexing your project. IntelliJ indexing
  • Updating is scary. I've had some minor updates breaking core functionality before. Since then I've been carefully using my colleagues as guinea pigs for the newest releases. Might not be the nicest thing to do, but it sure is effective 🤷‍♂️

Developer experience

Frameworks

Every Java project I have touched in a work setting was made with Spring Boot. This means I cannot form an opinion on other alternatives such as the more lightweight Jakarta EE or new 'cloud native (Darn it's easy slapping the cloud nomenclature on anything new) Quarkus'.

Spring Boot does a lot things. It allows you to get started REALLY quick. But there's a catch ... or two:

  • Spring (boot) encourages developers to use annotations to wire up 'components' in its Dependency Injection container. A developer slaps on an annotation, and the framework makes sure whatever just received this fancy annotation is managed by the DI container. It'll manage its lifecycle and lookup strategy. This sounds like a developers dream right? Write one word and get all of this functionality for free?

Maybe, but also maybe not. It's true that adding these annotations works fast, it feels like a fire-and-forget process. But there's two problems with this:

  • The framework has to scan all your classes with those fancy annotations for it to register the classes as Beans in its DI container. Scanning together with some reflection usage is slow, and hinders startup time.
  • When things get advanced, things get lost in the woods.

    • There's multiple ways to conditionally register Beans. It's just not fun having runtime errors of Beans that are missing on which you are depending.
    • Beans can be ordered. Debugging wrong ordering is a PITA.
    • The Spring magic issue, having this kind of registration makes it hard to click through to related Beans which inevitably makes 'trying to understand code you haven't written' harder.

Integration

There's a ton of integration libraries for Spring boot which allow you to get started really quickly. Most of them hook into your existing library with zero configuration (AutoConfiguration heh). This also means you yourself are not defining or directly calling an entrypoint for this library. Unfortunately, this makes it hard to understand the internals of the library, as you need to find the appropriate Configuration class in which the entry point is defined which then leads you to actual implementations that allow you to understand what the library is actually doing.

If it wasn't clear by now, I personally like methods such as .AddSomeIntegration(someIntegrationOptions) as you would see in your average C# web project. These kind of methods lets the developer click through and lets him/her access external code quickly.

My grievances with the Configuration and the way the DI works does not take away the fact that there's an entire ecosystem out there, ready to plug into your applications in a pretty seamless way.

Startup times

Bluntly said, the startup times of Java projects are pretty bad.

  • The Java Virtual Machine (JVM) takes a while to start up. This is also one of the reasons why Java is not that great in serverless solutions as cold starts feel extra cold.
  • Add some classpath scanning with reflection and you get event more time to wait on.

If you are a web developer and you are into trial and error development, you will not like developing in Java. I have had projects that took 5 minutes to build and run, which results into my attention span getting lost me going on a toilet or coffee break. Some of you might think I'm an impatient person, when it concerns having to wait to see my code changes, I am.

Debugging

Debugging Java projects is perfectly fine. You can follow the call stack, evaluate and manipulate variables during debugging.

The only mildly difficult thing in Spring projects in particular is the usage of AOP. AOP results in proxy objects which make debugging hard, as you usually have to unproxy them (if possible) to get the actual implementation.

Business standpoint

Java makes a ton of sense business-wise.

A Java LTS version usually gets 5 years+ support, this means limited support work (as in amount of times you need to upgrade) to upgrade to the next version. The way C# and .NET (Core) is evolving, you are forced into a faster update and maintenance cycle, as the support lifetime for an LTS release is only 3 years.

Java is known for being rock stable as it has been a staple in the industry for years. It's easy to hire for as it's a language that gets taught often, or apparently to migrate to.

Conclusion

Is it possible for a C# developer to become a Java developer?

  • Yes, it is certainly possible.

Is it a smart move for an organization to switch tech stacks or drop a certain tech stack?

  • It could be, if the underlying business reasons for this change have been thought out properly. Changes like this fall under the domain of change management, and has certain risks attached to it. It depends on the organization whether or not the change hurts the organization in the long run or not.

How did switching to Java influence me personally and professionally?

  • Working on Java projects allowed me to get in touch with other surrounding technologies, libraries and frameworks such as Liquibase, Maven, Spring Boot. Coincidentally I also had to get to work with AWS cloud services.
  • Many people say learning more technologies is never a bad thing, but I feel like it does put you in this 'jack of all trades, master of none' position. From an organizational standpoint I do think it makes sense as it allows for better employability/deployability (it's basically how the market has evolved and is why every organization is looking for full-stack engineers). Personally I think most software engineers would rather like to be an expert at one technology stack with some secondary aspects next to that single technology stack.
  • The first few weeks were rough. Childish notions such as 'with language X I could do Y faster' came up a lot and I am sure my teammates can attest to that. Later I understood this was just me trying to analyze on how to be more efficient using this new tech stack.

Would I recommend making a tech stack switch like this?

  • Not unless you have an other external motivation to learn the new tech stack. Planning on learning it or playing with it yourself would be the prime example of this kind of motivation. When you do not have this kind of motivation, your job quickly turns into something that simply pays the bills instead of something you enjoy.

Initializing...