Packages with classes grouped by type, are like utility classes. This may not always be what you want.
This post is not specific to Android, or Java for that matter. Some other languages may offer similar features.
Packages are something we usually don’t give much thought. For that reason developers sometimes just use them to group classes together, for example classes that perform similar actions or share a common ancestor. I think packages can offer a lot more than just grouping similar classes and should be thought of as an OOP (Object Oriented Programming) concept. That’s why I say: “Packages are like classes”. Now let’s investigate what other possibilities of organizing code are available with packages, and how that relates to classes.
Packages in app-architecture
Like I said before, I consider packages an OOP concept, just like inheritance and delegates. Using packages as such will help you design better libraries and apps, because using these features will help you to hide the implementation details, clients don’t need to know about. (Clients being any code using your code, even in the same app)
Before diving deeper into this, let’s discuss how we organize code and how we use access modifiers to determine what methods should be visible.
The first building block is code. Your application consists of code. This code is grouped into methods. These methods are grouped into classes and the classes, in turn, are grouped into packages. And finally we use access modifiers to control the visibility of these methods. By doing so we can make them internal to the class or to their subclasses. Or private within the package. Package private is like protected, except that the methods and fields are not available to subclasses (in other packages). The full access table looks like this:
Now think about this for a moment, think how you usually use these various modifiers to hide certain methods from external clients or subclasses. Think about how private methods contain very specific implementation details you don’t want a client to use.
Now imagine, that you can also use these modifiers on your classes, as members of your package. Now think about grouping classes in a package “because they are all fragments or activities” or “because they are all helpers”. Think about them as if they were methods of a class, which ones would you like your clients to use, and which ones would you like to hide.
When you group your classes by type, you lose package private, and thereby the option to minimize the visibility of these classes. You can’t hide your implementation details because the class needs to be accessible from other packages as well, for example to create an instance.
Grouping by type
So what packaging by type really brings is the same thing static utility classes bring. They allow you to group a set of classes together. You can see this for example in Java’s collections framework. Most of the implementations are intentionally grouped in the java.util package. This is intentional because they are all supposed to be used by any client that needs them.
So spreading your implementation details over multiple packages leaks your implementation details to the client. If you are creating a library this is even worse. These implementation details are now part of your public API. You need to maintain it, and make sure it is keeps working for all consumers of your library. People will also start using it in ways you never intended and are going to start reporting bugs on those use-cases.
So next time you create a class, specifically for a single feature, think whether it is something that should be public or package private. And remember, you can always refactor your code if you are not satisfied with the result.