Java’s default access

Mateusz (mat3e)
The Glovo Tech Blog
6 min readJun 1, 2022

Within my team, we like to challenge each other, question things and enforce a pragmatic, hands-on approach. Therefore, it was no surprise the following conversation started on Slack:

Just a bit side-off discussion — what kind of benefits does the package-private give? I mean more specific than “better encapsulation”. More like “what kind of problems you faced before that this strategy would mitigate/solve”?

I probably wrote too much, as teammates suggested converting it into a blog post…

The approach which provoked the discussion

Modularity

Why do we use private fields and methods when everything can be just public? List all the pros and most (if not all) of them would work at the package level. Then, at the module level, at the microservice level, etc.

High cohesion & encapsulation to put it simply. But it’s not all.

It’s all about making better abstractions and a more dev-friendly codebase. Reading code is more frequent than actual coding and it’s useful to have something like a table of contents to quickly verify if you look at the part that is worth reading at the moment. I see a proper usage of packages and package-private access as that.

Also, in that limited situations when you actually write code (😉), having much lower number of available classes/methods to choose from, makes it easier to choose a proper one. Less erroneous, and less likely to misuse that part of the codebase.

Enforcing package-by-feature approach

Still one can say, the world didn’t collapse because of not using package-private access. I think the same can be said about many other things, but is that our only metric?

How about organizing code using package-by-feature approach? It’s not as extreme as with package-private access, but I think most code I’ve seen was organized rather with package-by-type (a.k.a. package-by-layer) approach. Especially when counting in front-end codebases I worked with. Most code is organized like that, but it doesn’t mean it’s easier to work with such a code. See nice, thought-provoking examples at the end of this article: http://www.javapractices.com/topic/TopicAction.do?Id=205.

I think it’s obvious, but let me emphasize it

  • Package-by-feature helps to have package-private access
  • Using package-private access makes you think more in package-by-feature manner
  • Contrary, package-by-layer forces you to use public access to make classes from different packages visible to each other

Default

There is another reason people don’t use package-private access as much as they could. It was meant to be default access (Java design), but then IDEs and alternative JVM languages made public a default. My (educated) guess is they went that way because package-by-layer approach was encouraged by Java EE, Grails and other frameworks.

Taking a wonderful IntelliJ as an example, you have 3 places to override settings to encourage package-private access:

  1. Check Show Visibility Icons in Project Window -> Tree Appearance
  2. Modify File and Code Templates under Preferences
  3. Check a proper option under Code Style -> Java -> Code Generation

Because public is effectively a default, it’s in many articles, code examples, open source projects, etc. So fewer people think package-private access is useful, etc. And it drives itself.

Nevertheless, the original idea was to have a different default 🙂

Join the elite 😉

Despite the above, frameworks like Spring and JUnit 5 (fun fact: version 5 premiered in 2017) worked with Java’s default from the very beginning. So it’s not like no one was thinking about the package-private access. I’d even call these two Top Performers and I prefer taking the inspiration from them 😉

Implementing well-known patterns

There is a huge library of software design/integration/architecture patterns. You might not like package-private access, but willing to use e.g. Service Layer. My recommendation is to treat package-private access as a more convenient way of introducing the pattern. Treat it as an implementation detail and a helping technique.

Smarter code organization

One can still say packages should be used to organize the code and push towards package-by-feature approach and having 20+ package-private classes and one public Service or Facade class might not be the ideal organization.

My response is with Java’s default access as a default option you still use (sub)packages as the organizing structure, but you use them smarter 😄

  • REST API and DTOs can go to a separate subpackage. It’s even better because you ensure RestController doesn’t expose anything “internal” from the part of the system
  • Considering CQRS, a whole Query part can be a dedicated subpackage, containing just public classes
  • The whole infrastructure part created with Spring can be a dedicated subpackage (Spring works perfectly with package-private access, remember? 🙂)
  • Design patterns requiring class hierarchies can have their dedicated subpackages. E.g. strategy subpackage with a public interface and all package-private implementations

Thanks to promoting package-private access, you also discover files as a way of organizing your code. Something between the class and the package. I’d say it’s even encouraged with Java 16+ sealed classes, which can skip permits for same-file implementations.

Apart from files, I observed I started using Maven/Gradle modules better. E.g. you can extract adapters or api modules and use the same packages between them. So effectively you have like 20+ classes under a package but split into 2+ modules.

Real-life benefits

There are people much smarter than I who promote package-private access. I recommend taking a look at J. Bloch, Effective Java. Precisely, Item 15: Minimize the accessibility of classes and members. I also recommend watching

Packages as mid-sized building blocks

And my personal experiences connected with the above:

1. Not only I watched that talk 20+ times, but I also worked with the presented code for a moment, so I have some insight knowledge 😄

  • It was something called “team tourism” at the company I worked and the presenter was on vacation when I worked with his team
  • System was developed for a couple of years already and I was able to introduce a new, quite serious feature within a week. I mean from 0 to deploy it on production. I started working on Monday and the next Monday I got my first feedback from the end users (it was a back-office app)
I had to twit about this :D
  • There was a new team member there as well and he introduced a change, making one thing public. It was immediately caught by reviewers and comments were not like “rename this method”, but rather “is this a responsibility of that module”, “should this module know about that/expose that”, etc. Modularity was just a part of the team’s DNA. I see this as a side-effect of design, because looking at the team seniority, etc., it wasn’t a very experienced team

2. Closer to what is highlighted by Joshua Bloch — I guess you faced API versioning problems, didn’t you? When you have REST/events and there are already clients/other systems using them, you need to support old versions for almost forever 😄

  • In one team we decided to introduce service clients rather than public API. Then, package-private access was really handy to hide things. Similarly to what you do with limiting your REST services, but at the code level. I also used service clients later, in another company, and just interfaces were left public there
  • I also have some experience with autoconfigs, libraries and software plugins. Package-private access really makes these things easier to maintain. Contrary, what’s public has to be treated as “published” there

TL;DR

Modularity, ownership, security/confidence and freedom to change 😄

Part of the actual comment touching on the topic

--

--

Mateusz (mat3e)
The Glovo Tech Blog

Programmer and IT Designer focused on #Frontend and integration technologies, with a relevant #FullStack experience. #JavaScript, #Java, #AI, #Technology.