Mark your safe zone!

Recently I was wondering which keyword in java is the most used by programmers. Is it final, return, class, or maybe something else?

Unluckily I haven’t found any broader statistic on the internet and even on GitHub, I didn’t find that option. I was so curious, that I wrote a simple file crawler and run it on several big projects found on GitHub. The outcome was horrible.

Three of the most used keywords in projects that I checked are public on first place, then a final and third is a return.

If I can agree that final and return are used almost in each method and class in our programs I cannot believe that the public is so common. I will say more – first place? No way.

Bell in my head rang – something is wrong. Why is public access modifier so heavily used? I checked projects one more time only for access modifiers:

– public 80%
– private 17%
– protected 3%

Unfortunately, I couldn’t check default scope, as it has no keyword, but based on a number of classes in projects I checked I can tell that default scope count will be similar to protected, so a very little. Too little!

What is it mean that almost everything is public in our code? Is it bad or is it good? Well, definitely it is not good. It is actually awful and can lead to many cases of abuse.

At first, we should consider why this problem occurs? My main guess is modern IDEs. Modern IDEs like IntelliJ or Eclipse are creating a new class by default with visibility public. But should they? Isn’t we already have default modifier which is no modifier? I think that the creators of java language tried to save our time of writing new classes by making that. If the majority of classes and methods will be default why do we need to put modifier for them? I guess that was the question which they asked when they were creating Java Language Specification.
Another option is that programmers actually don’t know how and why we should use default modifier. Which unfortunately leads to problems that static analyzers have the option to warn on the usage of default/protected modifier – really disgusting!

Ok, but why the public is wrong? Why can’t we just make everything public?

Because we should always respect the privacy of our code, same as we respect the privacy of our friends, colleagues and we want to keep our life private. It is simple like that.

But something needs to be public, right? Yes, there is a public thing in programming which is called API. API has to be public, parameters of API have to be public. Everything behind API has to be not public. Of course, I am not talking about the API of our whole application. I am talking about the feature.

What is the default modifier in Java? Default modifier is a package-private visibility, which means that nobody outside our package can directly use field, method or class with that modifier. This approach is commonly used in package-by-feature or hexagonal architecture in contrast to dividing code by layers or themes.

What steps need to be done to create a new feature?
– define public API of your feature
– write tests for public API
– implement public API using many, many internal classes and methods (with default or private modifier)

It make no difference if we are talking about service-oriented applications or object-oriented applications. Almost always we can break down.

An example: you want to expose a feature of using the SELECT clause on the SQL database. In a standard way, there will be a public driver which will have direct access to the database and with it, you can call anything from anywhere. Do you want to drop database directly from frontend? No problem.
In our way, you will have public API for the database which will expose only methods with SELECT. There won’t be an easy way to expose the whole database.

Anyone who will want to use your feature will have to access your public API to use that. Are you using database inside? No problem, nobody will be allowed to access it directly and corrupt your state. Are you calling external system inside your feature? Still no problem, nobody will have access to that.

What are the benefits of this approach?

You have a big control over your code, and as long as your public API will fulfill a contract that long you can do whatever you want inside. You can easily refactor your behind-API code, you can divide classes, extract additional methods, breaking down responsibilities and you will not need to think about the outside world.

Your code is easily testable, you wrote tests for your API and now you have big regression suite to avoid problems in the future. More – your tests are documentation how to use it. One note – nobody forbids writing tests for your nonpublic classes. It is all right to do it when it is needed. In an example when you have to test your super complicated algorithm or regex. It can be more complicated for testing it through API. Just remember to not attach to this class and test, at some point you can need to delete it and forget that you ever wrote it.

As your inside classes are not accessible by the outside world your whole solution is characterized by high cohesion. All you have to do is stick to a contract and you will be fine.

From a user perspective, all your features will be easily accessible and usable. Nobody will have to check all the codebase to know what is going on. Just look on packages and public APIs.

I don’t know why currently the majority of classes are public, but I know why it is a bad thing to do. Remember, once you expose all your classes it will be difficult to remove them from the system in the future, as everybody can use them directly. Next time, when you will be creating a new class, think before, if it is necessary to make it public.

  • Przemys┼éaw Sporysz

    Well written! I agree about the package-level isolation, especially in monolithic business apps which I entirely control. But I don’t think that it’s so great for plain libraries where it prevents the clients from reusing some internals in Your app e.g. to work-around the bug / add quick improvement. Similar thing with final modifiers on class level or other stuff in external libraries which prevents me from extending it without making a fork/contribution.