官术网_书友最值得收藏!

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?

主站蜘蛛池模板: 吉安县| 太保市| 齐齐哈尔市| 响水县| 洛隆县| 开远市| 友谊县| 墨竹工卡县| 周口市| 通辽市| 原平市| 广饶县| 高要市| 蓝山县| 樟树市| 壶关县| 增城市| 江永县| 阜宁县| 德保县| 龙门县| 安化县| 武乡县| 望奎县| 连城县| 安陆市| 二手房| 永康市| 水城县| 新营市| 鄂尔多斯市| 汉中市| 岳西县| 邛崃市| 平邑县| 屯昌县| 西乡县| 边坝县| 兴业县| 罗山县| 长兴县|