今天是第三十六天,這也是本系列介紹的最後一個程式碼氣味。明天總結出新版本的氣味對照重構表後,終於可以完成這次的鐵人賽挑戰。昨天剛巧看見龍哥分享資深工程師身上的N項特質一文,其中就有特別提到關於「輸出」一事,相當感同身受。
鐵人賽的文章不曉得能有多少人閱讀,但整個過程中收穫最多的始終是還是自己。希望整理出來的這些資訊與見解,能多少貢獻回饋中文開發者社群,算是職涯中累積的一點小回饋。
今日的軟體產業中,幾乎沒有開發者會是真正一行一行從頭開始寫到尾,或多或少都會引用各種便利的第三方套件來滿足我們的業務需求。業界也常提醒大家「避免重複造輪」,就是這樣的道理。俗話說站在巨人的肩膀上能看得更遠,要說今日的開發者們通通是站在社群大神的肩膀上也不為過。
然而,不論多麽方便的第三方開源套件,都不可能足以完全隨心所欲,總是會遇到那些「差一點點」的時刻,會希望這些便利的工具或外部資源能夠徹底滿足自己的需求。有些人會透過各種管道對作者許願,或是直接提交修改後的程式碼。但這些做法並不總是能如願,有時也是會遇到無法修改的情況,我們可以稱之為「不完美的外部套件(Incomplete Library Class)」。
這是一個相當特殊的程式氣味,無法被歸類之前介紹過的五種氣味類別之中,通常會被稱為「其他氣味」。
以下是為何不完美的程式庫可能被視為程式碼氣味的一些原因:
有些情況下我們無法直接修改不完美的外部套件,這時我們可以考慮建立額外的階層或引入外部方法來解決氣味問題:
當你發現目前的程式碼依賴於某些外部套件但是缺乏一些功能實作,同時我們無法直接修改外部套件時,我們可以考慮在呼叫端類別中新增所需的方法,將外部套件的方法作為參數傳入其中,藉此來擴充套件原本的功能,來達到客製化需求變更。
當我們遭遇不完美的外部套件,而且無法直接修改時,我們可以考慮在本地新增一個類別,透過繼承或包裝外部套件的方式,在專案內去複寫或擴充出客製化需要的實作。這個方法提供了高度靈活性,可以在不修改原有套件的情況下調整出我們所需要的功能。
Nowadays, developers rarely write code from scratch. In the software industry, there is a saying that encourages us not to reinvent the wheel repeatedly. There are numerous useful open-source frameworks or third-party libraries available that can help us code more efficiently on a daily basis. However, we eventually discovered that the libraries don't always perfectly meet our needs. Furthermore, the library author has refused to implement them or has simply ignored the pull request over the long time. In this case, we face the code smell called “Incomplete Library Class”.
This is a special code smell because it does not belong to any of the code smell catalogs. It is always listed under "other code smells.”
Here are some reasons why an incomplete library class can be considered a code smell:
Unfortunately, there are situations where it is not possible to directly modify the library. In such cases, it is necessary to address the issue by creating an additional layer or introducing a foreign method.
When you have code that uses the data and methods of a certain class but can't add or modify the class itself, such as when it is located in a read-only third-party library, you can consider adding the needed method to a client class. This involves passing an object of the library class as an argument to the client class.
When you encounter a situation where a library class lacks the necessary methods that you require, and you find yourself unable to add those methods to the class due to certain constraints or limitations, here is a solution. You can create a new class that extends the existing library class, thus incorporating the additional methods you need.
This approach allows you to either inherit from the utility class or wrap around it, providing you with the flexibility to seamlessly enhance its functionality according to your specific requirements locally.
https://refactoring.guru/smells/incomplete-library-class
https://luzkan.github.io/smells/incomplete-library-class
https://refactoring.guru/introduce-foreign-method
https://refactoring.guru/introduce-local-extension