(English follows Chinese)
上次參賽已經是好幾年前,除了選題障礙之外,連續三十天的寫作對我來說早已經證實並不是太過困難的挑戰。這次恰好在幾個月前看了一段由心目中景仰已久的大神Sandi Metz在RailsConf 2016所發表的分享「Get a Whiff of This」,裡面提到了「由氣味到重構」的概念相當打動我。而在簡報中,也分享了一張由Joshua Kerievsky在2005年所建立的對應表格,讓我興起了想要深度研究的興趣,所以才有了這次參加鐵人賽的契機。
Sandi在演講中提到了一個我認為相當重要的概念,有別於過去我們在Clean Code中所時常提及的程式碼中的壞氣味(Bad Smell),她主張氣味實際上是中性的,並不總是那麼糟糕。氣味(Smell)提供了資訊,幫助我們判斷與決策。如果你眼前的程式碼永遠不會更改,那麼這些氣味並沒有這麼糟糕,大可選擇放著不改動也無妨。
然而,在多數的情況下,改變與新需求總是接踵而來。在多數的軟體公司或者擁有開發單位的部門,公司是付錢給開發者維護軟體。正是因為內部或外部使用者成天想要改這改那,許願更多更好(?)的功能,程式碼不需要任何改變的情況幾乎不存在。
同時,即使是糟糕的氣味(Bad Smell)也稱不上是一種錯誤(Bugs)。壞氣味依然按照使用者的期望運行,並且符合軟體規格與測試結果。根據定義,重構是修改程式碼的內容,但卻不改變其運行結果。有鑑於此,「重構一個壞氣味」與「修復程式碼中的錯誤」,這兩種行為之間並不能輕易混為一談。畢竟我們期望重構後行為能保持一致,而不是得到不同的結果,即使可能因此可以修復錯誤。當然,許多重構技巧會大力推薦在修復錯誤或是撰寫新功能時也能夠同樣被參考使用。我們會期待能在程式碼撰寫的初始階段就可以考慮到各種避免造成壞氣味的可能,來降低日後需要改動的機會。
因為重構無法帶來結果的改變,換言之無法直接給最終使用者帶來價值(請注意是直接)。有些單位或產業,會習慣性抗拒單純為了氣味去修改程式碼。因為我們每次改動程式碼,總是無可避免地增加風險。
沒有壞就別動他! (If it ain’t broke, don’t fix it.)
有些人堅定的相信,程式碼只有在錯誤或是新需求到來時,才需要且被允許改動。否則的話,單純為了氣味而提交改動程式碼並因此發佈,只不過是一種無謂地增加軟體運作風險的不負責任行為。我可以理解這些考量,在某些產業背景之下或有其依據,但還請原諒我,無法完全打從心底認同這樣子的想法。我自然理解,在有些情境下,軟體穩定度是至高無上的首要原則,例如在銀行業或是任何與錢相關的軟體,特別容易出現這種抗拒改變的文化。甚至為了降低風險,還可能會設置下一些外人所難以理解的奇怪規定,違反最佳軟體實踐的程度足以讓軟體同業大開眼界,如同造訪了 (金融) 異世界。
為了改動程式碼可能增加的風險而緊張不安可以理解,但時常容易被忽略的部分是,經年累月忽視這些氣味而堆積造成的軟體品質腐化,同樣會帶來風險。除非軟體專案帶有明確的效期,例如單次活動網站或是電影中的視覺特效程式,存在很明確結束的使用時間,並且確定不會再次重複使用。否則的話,考慮到軟體的長期品質與可維護性,還有晚上能夠睡得安穩,我堅定相信單純為了氣味而修改程式碼是利大於弊。
為了更好的重構,我們首先需要了解何謂「程式碼氣味」。每種氣味擁有明確的名稱與定義,以及相對應如何去重構他的技巧。在氣味與重構之間存在固定的關係,正如同食譜一樣。當我們想要一份香腸炒飯,我們可以按照食譜準備食材,一步一步按照書上步驟操作。有了這些明文化的建議,每個開發者都可以輕鬆辨識出氣味,並且模仿「食譜上」的重構的技巧,針對程式碼中的氣味進行改善。
在日本文化中,工作職人與工作環境之間的關係是相當被重視的。職人被要求共同擔負起清潔周遭的工作環境的責任,而不僅僅只是依賴清潔人員,以此來展現對工作的尊重,同時也是一種對環境、團隊成員展現感恩的舉動。我認為軟體開發者需要維護的環境除了物理上實體的辦公環境以外,專案內的「開發環境」當然也是我們專業上需要顧及「整理、整頓、整潔、整齊」原則的地方。
甚至我認為,整潔的程式碼(Clean Code)比起桌面與環境的整潔,對於我們開發者來說更加重要。桌面一時髒亂或許有時還能睜隻眼閉隻眼,但是程式碼髒亂就是不行!這是我們身為開發者應有的專業矜持。
我無法確定這樣依照氣味去改善優化的步驟會有多快能夠被AI助理取代,但是即使是與AI協作,開發者依然必須具備有殷實的知識,否則開發者將無法在AI有禮貌且周延的胡說八道時指正出來,來展現我們把關的專業。
接下來我會粗略介紹程式碼氣味的五大類,各種氣味的細節與重構技法將在接續的日子中陸續提及:
比需要的還大,太多太大。
錯誤使用物件導向的概念。
會讓你很難修改的氣味。
物件通通黏在一起,很難單獨進行修改。
早該拿掉刪除的部分。
難以歸類為上述五類。
與多數的理論相同,不同人有不同的分類看法。這裡主要參考Sandi的觀點進行修正。
如果你對這樣的主題有興趣,歡迎訂閱收藏留言分享四連擊給作者一點實質鼓勵(?)。要說創作沒有野心是騙人的,希望能夠在挑戰後,能夠有出版社找上門討論集結出書的事宜(!),能成為職涯上一個里程碑。
感謝閱讀與支持。
It's the beginning of a series of articles discussing code smells and how we can refactor them. The series was inspired by the tech talk "Get a Whiff of This" given by Sandi Metz at RailsConf in 2016. I love this tech talk video so much that I watch it repeatedly. Therefore, I decided to explore every smell-refactoring pair mentioned in this talk and extend it as an individual blog post.
One of the important concepts I learned from this talk is that code smells are neutral; they are not always bad, but they provide information. If nothing ever changes, it is probably okay. However, in most cases, new requirements will keep coming, and that is why the company hires developers like us to maintain the project.
Nevertheless, even the bad smell is not a bug; it works just as we intended. Refactoring involves rearranging code without altering its behavior. Thus, refactoring a bad smell is not the same as fixing a bug because the behavior is expected to remain the same after refactoring. On the other hand, it is recommended to apply these refactoring techniques when fixing bugs or implementing new features.
Some people dislike refactoring because it doesn't add any new features or fix bugs, and may introduce additional risks into the stable old code.
If it ain’t broke, don’t fix it.
The saying goes that things should only be changed if they are wrong, not just because they have a bad smell, but I cannot fully agree with that. While I understand that in some cases, maintaining stable behavior is the top priority and there are few or no new features planned for the future, people tend to minimize changes to reduce the risk. Based on my personal experience, applications in the banking industry or accounting systems often mitigate risk by enforcing strict change rules.
Some people may feel nervous about the risks of changing code, but there are also some risks if we don't change it. Unless the project has a very specific expiration date and will not be used again soon, I believe it is always better to clean the code, considering the long-term prospects.
To gain a clearer understanding of what needs to be refactored, we first need to understand what constitutes "code smell". Each code smell has a specific name and definition, with corresponding solutions for improvement. As Sandi mentioned in her talk, each code smell can be remedied by a specific refactoring recipe. By following these recipes, we can systematically improve our code quality.
In Japanese culture, there is a significant emphasis on employees cleaning their own working environment instead of relying solely on a cleaner or someone else. This practice is not only about maintaining sanitation, but it is also a ceremony to express our discipline and appreciation for others, including the working environment.
As software developers, our code base is our working environment. Keeping the code tidy and clean is an essential part of our job duties, without a doubt.
I am not sure how quickly this process may be replaced by an AI assistant like Github Copilot, but one can only confirm the output if one understands the theory behind the scenes.
We can classify classic code smells into five main categories.
It doesn‘t need to be that big.
These are ideas that are available in object-oriented programming that you can misuse.
This is stuff that makes change hard.
It binds the objects together, you can’t ever reach in and get one out and use it in another context. They come as a bundle, all or nothing.
A dispensable is something unnecessary that, if removed, would make the code cleaner, more efficient, and easier to understand.
The categories for each code smell may differ depending on the author's perspective. For instance, in her talk, Sandi doesn't consider it appropriate to include "Comment" and "Dead Code" in the Dispensable category. However, following the Refactoring Guru's approach, I believe it's more suitable to group them together.
As a personal challenge, I will explain the details of each code smell with the corresponding refactoring recipe in the upcoming days. If you find this topic interesting, please feel free to leave any comments or feedback.
Get a Whiff of This, Sandi Metz https://youtu.be/PJjHfa5yxlU
Refactoring Guru https://refactoring.guru/refactoring/catalog
https://www.industriallogic.com/xp/refactoring/catalog.html
https://www.refactoring.com/catalog/
恭喜Bater開賽~ 臃腫怪 / 耦合怪翻譯得好可愛
關於討論臭臭程式碼和重構,Refacter Ruby是我們最近參加的讀書會在討論的書籍,這本也蠻有幫助的~
期待後續的文章,預祝完賽順利唷!
問題:這一套氣味與重構基本上幾乎限定於物件導向,不知道FP有沒有對應的知識框架。
發現:討論氣味與重構時,幾乎避不掉設計方法(Design Patterns),之後或許需要補上這塊。
氣味的其他分類方式:
相對的氣味::Large Class <-> Lazy Class
針對類別或方法,或其他的氣味
Very useful website.
https://luzkan.github.io/smells/
這裡面總共列出五十幾種氣味,如何抓氣味的範圍是個大問題
同時,他提出總共九種氣味分類,而不是五種。除了重複的五種之外,另外還有以下四種氣味分類: