
The unfortunate tale of a library developer
Meet Jack. He's a Java developer at a medium-sized enterprise organization. He's a part of a team that writes code to do data processing. One day, Jack wrote some Java code to sort a list of usernames in alphabetical order. His code worked well without any errors and Jack was proud of his work. Since this was something that could be used by other developers in the organization, he decided to build it as a reusable library and share it with his colleagues as a packaged JAR file. Here's the structure of Jack's library:
His code belonged to two packages--acme.util.stringsorter and acme.util.stringsorter.internal. The main utility class was StringSorterUtil with one method--sortStrings. The method in turn internally called and delegated the sorting responsibility to the BubbleSortUtil.sortStrings() class from a class in the acme.util.stringsorter.internal package. The BubbleSortUtil class used the popular Bubble Sort algorithm to sort a given list of Strings.
All that any developer had to do was to drop the jar in the classpath and call the StringSorterUtil.sortStrings() method by passing in an list of strings they needed sorting. And they did! Jack's little library became a hit! His colleagues loved the convenience that his library provided and they started using it to sort many things, such as names, tokens, addresses, and so on.
A few months later, Jack happened to talk to Daryl at the water cooler, and as usual, their conversation veered towards a discussion about their current favorite sorting algorithms. Daryl couldn't stop talking about his new-found love for hash sort. He said he found it performs much better than bubble sort, and it was unabashedly his new favorite algorithm! Jack was intrigued. He went to his desk and ran a few tests. Daryl was right! Hash sort outperformed bubble sort in most of his tests. Jack knew right then that he had to update his sorting utility to use hash sort. He added a new class, HashSortUtil in the acme.util.stringsorter.internal package and removed BubbleSortUtil.
The following is the structure of Jack's library after the change:

Thankfully, he had a separate internal class that did the sorting, so the process to invoke the StringSorterUtil.sortStrings() utility wouldn't change. Everyone could just drop in the newer version of the JAR and everything would work just fine.
But it didn't! A few of the code builds in his company started failing. It turned out the culprit was the newer version of Jack's library. Jack couldn't believe it. He didn't miss anything, did he? Well, no. All the projects that used just the StringSorterUtil class worked just fine. However, it turned out that some of the developers ended up using the BubbleSortUtil class in the internal package directly. It was available in the classpath, so they had just imported and used it. Now, since that class didn't exist in the new jar anymore, their code couldn't compile!
Jack sent out an email instructing everyone using BubbleSortUtil to update their code to use StringSorterUtil instead. However, it turned out the BubbleSortUtil class was being used in multiple places by that time, and it wasn't an easy task to change them all. "Couldn't Jack just put the BubbleSortUtil class back?" they asked. Jack yielded to their requests and the next version of the library had both the SortUtil classes (and would possibly do so well into the foreseeable future), even though it internally used only one of those two classes.
After the dust settled, Jack sat at his desk and wondered what had gone wrong. What could he have done to prevent this problem? Clearly, naming the package as internal did not prevent developers from using it. One solution would have been to write that internal bubble sort type as package-protected and move the external type to the same package. This way, he could leverage the third mechanism in the preceding encapsulation table. However, he liked the idea of separating the bubble sort class into its own type and package. Also, imagine if this were a bigger library and there was a common shared class that was supposed to be internal. In that case, pretty much all types in that library that need the internal type have to exist in the same package as that internal type! Wasn't there a better way to encapsulate the internal types?