Java Packages

I was watching a video today where this topic was brought up and I was kind of surprised at how some people categorize the importance of packages in Java. I will go over two main reasons why packages are important. Before I got into details, let start by enumerating the two reasons I am discussing in this blog. The first, and most common reason, is for organization purposes. I am sure you have heard this many times. The second reason, and the one I believe is badly overlooked, is protection to restrict access to your classes and features.

Use packages to organize your classes and features

The first point you should know about packages is that packages are basically the folders where your classes reside. This concept should not be foreign to anyone. If you have used a computer at least once in your life, you should already be aware why folders are helpful in keeping your files organized.

If you are like me, you love to create folders to keep your files organized and to quickly navigate to the files you are looking for. So, in your computer you might find folders named "Pictures" or "My Documents" or even sub-folders like "Resumes" or "Camping Trip 2017". People do this to create a logical separation of files. Like folders in your Operating System, Java packages allow you to create logical compartments for your classes and the features they provide. This benefit really needs little to no explanation.

You should also know that, like naming of folders and directory structures, there is not really a strict rule when it comes to package creation. In theory, you can have as many packages and sub-packages as your system will allow. Unlike folders, there are stricter naming conventions imposed by the Java language. For instance, a package name cannot start with a number; even though packages are basically folders. There are, however, a number of industry-wide best practices when it comes to package names and structure. You can search the web for this topic and you will find a variety of suggestions. My personal preference is to break down your packages by features and sub-features. In my opinion, this is the most commonly accepted practice. At the end of the day, your organization or team (or even you) will decide what makes the most sense for what you are doing. That said, you should consider sticking with widely adopted practices. Why? Consider the directory structures of Operating Systems such as Windows. If I was to ask any Windows user what folder contains the installed programs on a PC or laptop, they will answer "Program Files" or "Program Files (x86)" without hesitation. Likewise, adopting a widely used convention will allow any person outside your project to have an idea where to go to access certain functions of your system. To summarize, commonly used package naming and structure helps keeping your code organized in a way that does not require intimate knowledge of the system in order to quickly find the desired set of classes and features.

Use packages to restrict access to your classes and features

This is, to me, the most important reason why to use packages. However, placing classes in packages alone does not provide any access restriction to the classes and features in a package. In order for such protection to be turned on, it must be used in conjunction with Java's default access modifier (no access modifier in the class or method declaration). The default access modifier in Java is also known as "package private." This means that a class, method, or data member with this level of protection is only visible internally to the other members of that package. There are some who believe that Java got it wrong by now allowing sub-packages to also be allowed access. I am not going to debate that point on this blog because it will be pointless because I sometimes feel that way and sometimes I do not. But, what it important is for me to explain to you why using packages in conjunction with the default access modifier is important.

Consider your typical ATM system. An ATM, from the external user perspective, has a very simple interface. When a card is inserted and the correct Personal Identification Number is provided, the user is presented a limited set of features. Typically, these features are limited to withdrawal, transfer funds, deposit, check balance, and exit. Each of these main menu functions have a strict workflow. For example, if the user select to withdraw money, most likely the user must provide first the type of account to withdraw from (for example savings or checking account) and then the amount. Assuming there are funds available, money is dispensed and eventually the transaction is over. But, is the process really that simple? We all know the answer is no.

In an ATM system, it is likely that there are dozens or even hundreds of functions that are not accessible by the user because are only meant to be for internal system use. For example, when the card is inserted in the card reader, the magnetic strip or chip is read, and this information is stored somewhere. Then, the user provides his or her Personal Identification Number which is used in conjunction with with the card information to authenticate the user. The user authentication process requires for a synchronous transaction to occur where the information is sent to the bank. Once the bank receives the information it validates the user and the validation message is sent back to the ATM. Again, when the type of account is selected and and amount, this information is again sent to the bank for verification of funds. Once the bank confirms that funds are available, the processor inside the ATM machine messages the vault to dispense the entered amount (which requires the mechanization of a lot of mechanical parts). The point is that the user does not have access to any of these functions nor the user cares to have access to them. Therefore, what would be the point of making these accessible the user? Imagine how complicated and error prone would be the process of getting money from an ATM if that was the case.

For the sake of the user, it is best to provide the user with the bare minimum set of features that he or she will need to do the job required. Following the ATM example, the only public methods required are "enter personal identification number", "withdrawal", "transfer funds", "deposit", "check balance", and "cancel transaction". There are other functions needed for navigation like "main menu", "back", and maybe "forward". Since functions like "authenticate user" and "check funds availability" should be made package private to restrict access. Likewise, any classes and data members that are not needed by the user should also be made package private.

Lastly, there could be good reasons to apply similar restrictions internally within the system. Listing examples to illustrate this point is not important. What is important is that just like you would want for the public Application Interface (API) to be as simple as possible, you would also want your internal API to be as simple as possible. To conclude, I will use a real life example where I took advantage of this approach. Many years ago, I was given the task of adding a status bar for an application. There was a status bar already in use in certain windows within the application. When I examined the code with hopes of reusing existing functionality, I found it to be incomprehensible. So, I decided to create my own status bar. Once I was done, I generated Javadoc for the status bar "widget" I created. The API consisted of something like 6 public methods or less. I created a new package called "widgets.statusbar" with many other sub-packages inside. The new status bar was so simple to use that anyone could have gone to the Javadoc or even the code itself and figure out how to use it and customize it as needed. Restricted visibility from outside the package made my widget more reusable than the alternative.

Comments

  1. Really show how important package is, especially when working with others. I'm curious on the sub-package debate, that the default access modifier doesn't grant access to the sub-package. Is it because protected or public already grant access to the sub-package, and thus default has no need to do so? Or that private is already restricted enough that default is not needed?

    ReplyDelete

Post a Comment

Popular posts from this blog

Combining State and Singleton Patterns to Create a State-Machine

The Beauty of the Null Object Pattern

Java Keywords (Part I): Creating Classes