Question

I have a coding style related question. In my example it is java, but I think this can be a generic question regarding languages that are changing rapidly.

I'm working on a java code base which was mainly written targeting java 8. The code was migrated to java 12. By migration I mean the code can run on jdk12, so the necessary library changes/additions were done. However the new language features haven't been used yet (e.g. var keyword).

My question is, what should be the approach to introduce new language elements from readability point of view? How important is consistency?

I have a few possible approaches in my mind.

  1. New language features should be used only in new classes
  2. New language features can be used in newly added parts of existing classes (e.g. a new method), even if the rest of the class is not updated.
  3. When a new language features are added to new parts of existing classes, then the rest of the class should be updated too

I know this question is a bit hard to answer (as coding style questions in general), but still I hope there will be some conclusion.

Was it helpful?

Solution

When in Rome do as the Romans do.

It's nice if an entire code base follows one consistent style. However that will trap it's style in the past.

If you're enchanted by some new fangled style the worst thing you can do is scatter it randomly among code left in the old style.

This is why when you repaint a house a different color you don't just do it where the paint is damaged. You do it room by room.

It's better to make the change within some boundary. Those reading the code should find it easy to predict what style they will find in each place.

Changing the style of working code is a refactoring. Don't refactor without tests. And don't refactor everything at once. Do one room, step back, and ask others what they think.

When you can't do all that, stick with the old style. Only use new language features that blend well with the old style.

OTHER TIPS

I am working with C# since version 1.1 (around 2003), and I have first-hand experience how we introduced new language features into our grewing code base over the years. We simply introduced them whenever they were available, and everyone in the team started to use them in the area of the code where they were working on.

These features included

  • generic collections (instead of weakly typed collections)

  • improved property syntax

  • the var keyword

  • extension methods

  • functional tools like lambda expressions, closures etc.

  • Linq

  • async / await

(just to name a few examples).

Note, even in newly written code, each of these features is used in conjunction with older language features. You don't start replacing every possible loop with a Linq construct just because Linq is available. You don't start to use extension methods for every function just because "extension methods are available". And using var today for every variable declaration does not make your code more readable.

Hence actual experience was not so bad as the other answers might pretend - quite the opposite. In a larger code base, in case you do not want stick to old, clumsy constructs forever, you have to start to use the new constructs somewhere, but you cannot introduce them everywhere - and it would not even make sense to use them everywhere. You usually don't update working code sections to new language constructs when there is no other compelling reason. This automatically leads to some sections with more new language constructs, some with less and some without any, all working well and readable enough, side-by-side, often for years.

So my recommendation here is: don't overthink this. Readability of code where these features are mixed is very subjective, and in a team where everyone knows the old and the new language features well, this is less of a problem as one might think.

You are asking how to deal with technical debt. Assuming the critical things have been taken care of (updating the code to work with the new version of Java), the types of changes you are wanting to make don't have any direct impact to the user base. As a result, it is difficult to get product owners or management to agree to invest in that migration.

If you are managing an open source project, you don't have that management aspect to worry about. In that case, it's up to your community to determine how quickly you invest in the updates.

There are risks

  • Due to misunderstanding specifics of a new feature, you might introduce subtle bugs that are hard to detect
  • Some features may force you to rethink how your library/app/service is implemented--those targeted rewrites are very high risk as it will probably also change how it is tested
  • The end result may be less understandable than the code was beforehand--providing a negative benefit

Changing your working code without a healthy set of unit tests is like walking a tightrope without a net. If you are super careful it can be done, but when things go wrong they can go epically wrong.

It is always better to do what you can to mitigate risks when you are paying down technical debt.

3

If you are doing some other refactoring/modification in a class, bring the whole of the class to correspond to your current coding guidelines. Avoid having inconsistent styles in the same class. Classes should be small enough that you can do that easily and with low risk, and presumably the class will be tested anyway when you are changing it.

You could apply a change on the whole code base in one go if it can be applied mechanically. E.g. if you decide that var foo = Foo() is better than Foo foo = Foo() then you can reasonably safely apply this to the whole code base in one go with a refactoring tool.

There’s a difference between upgrading the code so that it can run on Java 12, and incorporating functionality so that it must run on Java 12. What version(s) are being used the user(s)?

This is especially true in your example - Java 12 is not an LTS (Long Term Support), unlike Java 8 - so 12 will likely stop being supported before 8.

Licensed under: CC-BY-SA with attribution
scroll top