<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:media="http://search.yahoo.com/mrss/">
  <channel>
    <title>設計模式｜林鼎淵 Dean Lin</title>
    <link>https://deanlin.net/tags/%E8%A8%AD%E8%A8%88%E6%A8%A1%E5%BC%8F/</link>
    <image><url>https://deanlin.net/images/author_hu_aa256fc934e9a932.jpg</url><title>設計模式｜林鼎淵 Dean Lin</title><link>https://deanlin.net/tags/%E8%A8%AD%E8%A8%88%E6%A8%A1%E5%BC%8F/</link><width>144</width><height>144</height></image>
    <description>林鼎淵（Dean Lin）的部落格：生成式 AI 企業內訓講師、外商資安公司軟體專家、7 本書作者。400 多篇文章用白話分享生成式 AI 實戰、Claude Code 與 Vibe Coding 教學、團隊合作與職場成長。</description>
    <generator>Hugo</generator>
    <language>zh-tw</language>
    <copyright>© 2020–2026 林鼎淵 Dean Lin</copyright>
    <lastBuildDate>Wed, 06 Oct 2021 08:38:32 +0800</lastBuildDate>
    <atom:link href="https://deanlin.net/tags/%E8%A8%AD%E8%A8%88%E6%A8%A1%E5%BC%8F/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>[面試][設計模式]Code Review 會注意哪些事？會依照什麼原則對程式做 Refactoring？</title>
      <link>https://deanlin.net/blog/202110/fullstack-career-notes-day-21/</link>
      <pubDate>Wed, 06 Oct 2021 08:38:32 +0800</pubDate>
      <guid>https://deanlin.net/blog/202110/fullstack-career-notes-day-21/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>「沒有最好的程式，只有更好的程式。」在完成功能後 Code Review 是非常重要的事情；不只看自己的程式碼，也要多觀摩其他人的程式碼，這個動作除了可以優化程式碼品質外，還可以幫助團隊了解彼此的工作進度。</description>
      <media:content url="https://deanlin.net/blog/202110/fullstack-career-notes-day-21/images/cover_hu_5ae278293ba548a2.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<blockquote>
<p>在功能穩定後，你對程式碼還有要求嗎？</p>
</blockquote>
<p>「<mark>沒有最好的程式，只有更好的程式。</mark>」在完成功能後 Code Review 是非常重要的事情；不只看自己的程式碼，也要多觀摩其他人的程式碼，這個動作除了可以<mark>優化程式碼品質</mark>外，還可以幫助團隊<mark>了解彼此的工作進度</mark>。</p>
<p>人無完人，很多時候第一時間想到的解法未必是最好的；<mark>解決問題的方法不只一種</mark>，可能有更簡潔的寫法或是更好的 Pattern 可以套用，只是開發者不具備這塊的知識儲備；此時 Code Review 就是<mark>提升團隊程式水平</mark>的方式。</p>
<p>找到需要改善的問題後，<code>Refactoring（重構）</code>就是另一個開始；如果為了盡快完成功能而埋頭狂寫，容易導致日後維護以及交接的困難性；專案越大這個問題會越明顯，所以在完成功能後對程式做 Refactoring 是必要的任務，它能<mark>提升你日後解決 Bug、需求變更時的工作效率</mark>。</p>
<h2 id="大綱">大綱<a class="h-anchor" href="#%e5%a4%a7%e7%b6%b1" aria-label="這個段落的連結"></a></h2>
<ol>
<li><strong>Code Review 會注意哪些事？會依照什麼原則對程式做 Refactoring？</strong>
<ul>
<li>1.1 面試官為什麼會問？</li>
<li>1.2 面試官想從答案確認什麼？</li>
<li>1.3 筆者提供的簡答</li>
</ul>
</li>
<li><strong>回答問題所需具備的知識</strong>
<ul>
<li>2.1 SOLID 原則</li>
<li>2.2 Design Pattern 是什麼？解決了什麼問題？</li>
</ul>
</li>
<li><strong>衍伸問題</strong>
<ul>
<li>3.1 有處理 Legacy Code 的經驗嗎？</li>
<li>3.2 有用什麼工具讓團隊有一致的 Coding Style</li>
</ul>
</li>
</ol>
<hr>
<h2 class="h-nomark" id="1-code-review-會注意哪些事會依照什麼原則對程式做-refactoring">1. Code Review 會注意哪些事？會依照什麼原則對程式做 Refactoring？<a class="h-anchor" href="#1-code-review-%e6%9c%83%e6%b3%a8%e6%84%8f%e5%93%aa%e4%ba%9b%e4%ba%8b%e6%9c%83%e4%be%9d%e7%85%a7%e4%bb%80%e9%ba%bc%e5%8e%9f%e5%89%87%e5%b0%8d%e7%a8%8b%e5%bc%8f%e5%81%9a-refactoring" aria-label="這個段落的連結"></a></h2>
<h3 class="h-nomark" id="11-面試官為什麼會問">1.1 面試官為什麼會問？<a class="h-anchor" href="#11-%e9%9d%a2%e8%a9%a6%e5%ae%98%e7%82%ba%e4%bb%80%e9%ba%bc%e6%9c%83%e5%95%8f" aria-label="這個段落的連結"></a></h3>
<p>只要是軟體工程師的職位，這題可以說是超級<mark>常見面試題</mark>；因為它能問得很淺也能夠問得很深，如果是相對資淺的職位，求職者只要能說出<mark>關鍵字並給出基本解釋</mark>就能過關；如果是資深的位置，除了關鍵字外，面試官會繼續詢問你在<mark>專案中是否有實踐</mark>。</p>
<hr>
<h3 class="h-nomark" id="12-面試官想從答案確認什麼">1.2 面試官想從答案確認什麼？<a class="h-anchor" href="#12-%e9%9d%a2%e8%a9%a6%e5%ae%98%e6%83%b3%e5%be%9e%e7%ad%94%e6%a1%88%e7%a2%ba%e8%aa%8d%e4%bb%80%e9%ba%bc" aria-label="這個段落的連結"></a></h3>
<ul>
<li>瞭解求職者 Code Review 會在意的點</li>
<li>有使用哪些方法對程式做 Refactoring</li>
<li>對 SOLID 原則有基礎認知</li>
<li>知道 Design Pattern 且能舉出實務上的應用</li>
<li>有用過什麼工具讓團隊有一致的 Coding Style</li>
</ul>
<hr>
<h3 class="h-nomark" id="13-筆者提供的簡答">1.3 筆者提供的簡答<a class="h-anchor" href="#13-%e7%ad%86%e8%80%85%e6%8f%90%e4%be%9b%e7%9a%84%e7%b0%a1%e7%ad%94" aria-label="這個段落的連結"></a></h3>
<p>我會先觀察<mark>變數與函式的命名</mark>是否符合團隊規範、<mark>變數的宣告</mark>是否合理（var/let/const 的使用時機）；然後看程式在設計上是否有<mark>符合 SOLID 原則</mark>；在功能完成後如果發現有合適的 <mark>Pattern 可以更好地解決問題</mark>，就會再對程式做 Refactoring。</p>
<hr>
<h2 class="h-nomark" id="2-回答問題所需具備的知識">2. 回答問題所需具備的知識<a class="h-anchor" href="#2-%e5%9b%9e%e7%ad%94%e5%95%8f%e9%a1%8c%e6%89%80%e9%9c%80%e5%85%b7%e5%82%99%e7%9a%84%e7%9f%a5%e8%ad%98" aria-label="這個段落的連結"></a></h2>
<p>其他章節的知識，可能換一個時空背景就用不到了；但今天這個章節的內容，是每位開發人員都需要<mark>將其內化成為本能的</mark>。</p>
<h3 class="h-nomark" id="21-solid-原則">2.1 SOLID 原則<a class="h-anchor" href="#21-solid-%e5%8e%9f%e5%89%87" aria-label="這個段落的連結"></a></h3>
<p>SOLID 是一個<mark>物件導向</mark>的設計原則，核心目標是為了讓程式碼更乾淨、易讀、好維護，讓程式朝著 <code>Clean Code</code>（無瑕的程式碼）的方向前進。</p>
<ul>
<li>
<p><strong>S（Single Responsibility Principle）單一責任原則</strong><br><mark>一次只做好一件事</mark>；如果把系統比喻成樂高，那單一責任原則就是樂高的每一塊積木。</p>
</li>
<li>
<p><strong>O（Open-Closed Principle）開放封閉原則</strong><br>程式的架構要容易擴充功能；而這個<mark>功能的擴充是新增程式，而非修改過去的程式</mark>，這麼做可以維持原有程式的穩定性。</p>
</li>
<li>
<p><strong>L（Liskov Substitution Principle）里氏替換原則</strong><br>在繼承中衍生的子類別，要能<mark>完全繼承父類別的功能</mark>；實作時還需顧慮到單一責任原則，<mark>避免日後功能拆分或刪減時的困擾</mark>。<br>以軟體的角度來說，使用者期待<code>版本從 1.0 ➞ 1.1 時行為是一致的，不會更新完舊功能就壞掉</code>。</p>
<blockquote>
<p><strong>子類別 Override 時要注意</strong></p>
<ul>
<li><strong>不可改變父類別先決條件</strong><br>假設籃球比賽的參與者年齡限制在 15~80 歲；裡面可能區分為青年組、中年組、老年組，青年組的年齡「可以是 15~30」；但「不可以是 14~30」。</li>
<li><strong>子類別的後置條件不該被削弱</strong><br>籃球的得分有「2」分球、「3」分球，都是數字；如果某個比賽改用「三分球」這個字串紀錄得分就是不可以的。</li>
</ul>
</blockquote>
</li>
<li>
<p><strong>I（Interface Segregation Principles）介面隔離原則</strong><br>設計程式時不應該預設使用者一定會使用到介面中的多個功能，我們應該盡量讓介面的功能單一；以後端 API 來舉例，我們<mark>不要讓一個 API 可以做好多事情，但做每件事情時只用到其中幾個參數</mark>。</p>
</li>
<li>
<p><strong>D（Dependency Inversion Principle）依賴反轉原則</strong><br><mark>子類別一定會依賴父類別</mark>，這樣單向的關係是乾淨的；如果是雙向的依賴就會導致程式碼邏輯難以追蹤。</p>
</li>
</ul>
<hr>
<h3 class="h-nomark" id="22-design-pattern-是什麼解決了什麼問題">2.2 Design Pattern 是什麼？解決了什麼問題？<a class="h-anchor" href="#22-design-pattern-%e6%98%af%e4%bb%80%e9%ba%bc%e8%a7%a3%e6%b1%ba%e4%ba%86%e4%bb%80%e9%ba%bc%e5%95%8f%e9%a1%8c" aria-label="這個段落的連結"></a></h3>
<p><code>Pattern</code> 是指在不同場景下的解釋，包含 Context（情境敘述）、Problem（問題）、Solution（解決方案）。</p>
<p>而 <code>Design Pattern</code> 就是過去人們發現解決問題的套路；學習越多 Design Pattern 在遇到問題時可以有更多的思路，並縮短與其他工程師討論的時間，因爲 Pattern 本身就包含了對問題的基礎解決方案，可以省下說明的時間。</p>
<p>下面分享一些常見的 Design Pattern 幫大家建立基礎概念，在看完後讀者也許會恍然大悟，原來我一直都有在使用 Pattern！</p>
<ul>
<li>
<p><strong>Factory Method 工廠方法</strong><br><strong>簡述</strong>：<mark>工廠負責生產客戶需要的產品</mark><br>假設今天有一個飲料<code>工廠</code>，他會生產很多種類的<code>產品</code>，像是「紅茶、綠茶、烏龍茶」；也許這些飲料的製作過程很複雜，但對客戶來講只要說出自己想要什麼口味的飲料就好了。</p>
</li>
<li>
<p><strong>Strategy 策略</strong><br><strong>簡述</strong>：<mark>一個策略介面底下有很多靈活的方法供選擇</mark><br>把計算機的<code>計算</code>當成一個介面，這個介面提供<mark>加減乘除</mark>的方法；如果想加入<mark>次方、開根號</mark>的功能也能夠輕鬆擴充。</p>
</li>
<li>
<p><strong>Factory Method 與 Strategy 混合運用</strong><br><strong>簡述</strong>：<mark>有時解決方案是多個 Pattern 的組合</mark><br>假設今天開一間飲料店，飲料會分成茶類、咖啡；每杯飲料又有冰量、甜度的選擇，這裡我們可以用 <code>Factory Method</code> 來建立產品；而飲料在販售時，不同組合有對應的折扣，這裡就可以用 <code>Strategy</code> 提供對應的方法來計算總金額。</p>
</li>
<li>
<p><strong>Singleton 單例</strong><br><strong>簡述</strong>：<mark>希望在程式每個位置都能呼叫統一的 Instance</mark><br>在寫程式時會希望某些資源可以<mark>重複利用</mark>，並且在不同檔案引用時這些資料是<code>一致</code>的，像是共用的計時器、資料庫等物件。</p>
</li>
<li>
<p><strong>Decorator 裝飾</strong><br><strong>簡述</strong>：<mark>將需求獨立，依據實際需求取得動態的結果</mark><br>假設一間餐廳提供三種餐點</p>
<ul>
<li>商業午餐（主餐）</li>
<li>簡餐（主餐 + 飲料）</li>
<li>套餐（主餐 + 飲料 + 甜點）</li>
</ul>
<p>我們發現上面餐點是有疊加性的，所以可以用繼承的方式來撰寫餐點間的關係；但如果今天老闆想要更換簡餐的內容組合（ex：贈送水果），而不想改變套餐的內容，就會導致程式必須改寫。<br>面對這個問題，我們可以用 <code>Decorator</code> 作為解決方案，將主餐、飲料、甜點、水果各自獨立，依據商業午餐、簡餐、套餐實際的內容來做組合；這樣就能減少耦合性的問題。</p>
</li>
<li>
<p><strong>Observer 觀察者</strong><br><strong>簡述</strong>：<mark>觀察者要能掌握被觀察者的狀態改變，較常用於 GUI 的設計</mark><br>像是 Vue.js 的 watch 就是用來監聽一個「值」的變化去做一系列的事情（ex：UI 上的調整）。</p>
</li>
<li>
<p><strong>Command 命令</strong><br><strong>簡述</strong>：<mark>將請求的物件和執行的物件分開</mark><br>路邊攤的老闆通常是一個人負責備料、點餐、料理、清潔…等到生意做起來有店面了，他才會考慮雇用一些人手來幫忙內場、外場，如果把這個解決方案用 Command 來舉例：</p>
<ul>
<li><strong>客人（Client）</strong>：跟服務生說自己想點什麼餐（Concrete Command）。</li>
<li><strong>服務生（Invoker）</strong>：紀錄客人的餐點（Concrete Command），並呼叫命令。</li>
<li><strong>廚師（Receiver）</strong>：收到命令後，開始料理餐點（Concrete Command）。</li>
</ul>
</li>
<li>
<p><strong>Builder 建造者</strong><br><strong>簡述</strong>：<mark>依照自己的需求客製化產品</mark><br>一台筆電是由許多零件組裝而成，你可以選擇<code>標配</code>也能夠用<code>選配</code>來客製化它；為了讓選配的零件規格有彈性，<code>Builder</code> 就是一個很棒的解決方案；它讓你先選完自己所需的零件後，再產生最後的產品。</p>
</li>
</ul>
<blockquote>
<p><strong>備註</strong>：如果你熟悉的 Pattern 剛好能解決目前遇到的問題那是皆大歡喜；<mark>萬一沒有合適的 Pattern 可以套用，千萬不要為了設計而設計</mark>；開發人員的目標應該是想透過 Pattern 解決問題，而不是從 Pattern 出發去設計問題。</p>
</blockquote>
<hr>
<h2 class="h-nomark" id="3-衍伸問題">3. 衍伸問題<a class="h-anchor" href="#3-%e8%a1%8d%e4%bc%b8%e5%95%8f%e9%a1%8c" aria-label="這個段落的連結"></a></h2>
<h3 class="h-nomark" id="31-有處理-legacy-code-的經驗嗎">3.1 有處理 Legacy Code 的經驗嗎？<a class="h-anchor" href="#31-%e6%9c%89%e8%99%95%e7%90%86-legacy-code-%e7%9a%84%e7%b6%93%e9%a9%97%e5%97%8e" aria-label="這個段落的連結"></a></h3>
<blockquote>
<p>除非是新創團隊或是接案類型的公司；不然絕大多數新人入職後都要接手前人遺留的程式碼（Legacy Code），如果求職者只有從零開始的經驗，在一開始會有陣痛期。</p>
</blockquote>
<p><mark>考點：了解求職者是否接觸過 Legacy Code、碰到時如何快速掌握</mark></p>
<p>之前有因為<mark>專案擴編</mark>而去支援的經驗，因為當時有時程上的壓力；所以我在加入團隊後除了重點了解<mark>自己要負責的 Feature、團隊的 Coding Style</mark> 外，會主動向<mark>定下這些需求的 PM 討論</mark>，以此了解因果關係並快速融入團隊。</p>
<p>也曾接手過要<mark>維護及擴充的專案</mark>，因為當時沒有相關文件可以參考，為了快速掌握專案，我一邊操作系統一邊畫<code>心智圖</code>幫助自己釐清功能；了解系統架構後再去找<mark>合作窗口確認需求</mark>，避免實作方向與客戶需求不同。</p>
<p>在修改 Legacy Code 時，我會特別注意前人是否有<mark>撰寫測試案例</mark>，在程式能有效測試的狀態下才能安心的修改與擴充。</p>
<p>以正在運行的專案來說，我會希望<mark>建立團隊 Code Review 機制</mark>，讓每個人熟悉彼此的程式、使用共同的 Coding Style，<mark>當知識共享與風格統一後，就能減少 Legacy Code 的產生</mark>。</p>
<hr>
<h3 class="h-nomark" id="32-有用什麼工具讓團隊有一致的-coding-style">3.2 有用什麼工具讓團隊有一致的 Coding Style<a class="h-anchor" href="#32-%e6%9c%89%e7%94%a8%e4%bb%80%e9%ba%bc%e5%b7%a5%e5%85%b7%e8%ae%93%e5%9c%98%e9%9a%8a%e6%9c%89%e4%b8%80%e8%87%b4%e7%9a%84-coding-style" aria-label="這個段落的連結"></a></h3>
<p><mark>考點：是否有善用工具解決問題</mark></p>
<p>我在 VSCode 有安裝一個 <a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode">Prettier</a> 的外掛，靠它就能非常有效的將程式碼格式化；不過有時為了保證團隊的 Coding Style 會導入 ESLint 來統一風格，但 Prettier 與 ESLint 一起使用時會遇到衝突，所以我有再安裝一個 <a href="https://marketplace.visualstudio.com/items?itemName=rvest.vs-code-prettier-eslint">Prettier ESLint</a> 的外掛來解決這個問題；讓程式不僅符合團隊的 Coding Style，還可以透過快速鍵將程式碼格式化。</p>
<hr>
<p>寫完這篇文章時，我的心裡突然冒出一段話：「一開始我們在追求問題的解答；到後來，我們在學習解決問題的方法。」</p>
<p>感謝大家的閱讀，如果喜歡我的文章可以<code>訂閱</code>接收通知；如果有幫助到你，按<code>Like</code>可以讓我更有寫文的動力，我們明天見～</p>
<h3 id="參考資源">參考資源<a class="h-anchor" href="#%e5%8f%83%e8%80%83%e8%b3%87%e6%ba%90" aria-label="這個段落的連結"></a></h3>
<ol>
<li><a href="https://wyattkidd.medium.com/fca4e2e16752">【翻譯】JavaScript 設計模式</a></li>
<li><a href="https://ithelp.ithome.com.tw/articles/10234830">什麼是 Design Pattern?</a></li>
<li><a href="https://ithelp.ithome.com.tw/articles/10201706">我為什麼想學設計模式 ( Design Pattern )</a></li>
<li><a href="https://web.archive.org/web/20210226100242/http://www.andrewchen.tw/2017/04/09/20170409_NOTE_%E8%A8%AD%E8%A8%88%E6%A8%A1%E5%BC%8F%E4%BA%94%E5%A4%A7%E5%9F%BA%E6%9C%AC%E5%8E%9F%E5%89%87SOLID/" title="原網頁已失效，連到網際網路檔案館的存檔">設計模式五大基本原則 SOLID</a></li>
</ol>
<hr>
<hr>
<blockquote>
<p><img src="https://deanlin.net/blog/202110/fullstack-career-notes-day-21/images/fullstack-career-notes-day-21-01.webp" width="1024" height="233" alt="參考資源（圖 1）" fetchpriority="high" decoding="async"></p>
<p>在許多人的幫助下，本系列文章已成功出版，除了添加新的篇章，更完善了每個案例的應對進退；如果對現在的職涯感到迷茫，也許這本書能帶給你不一樣的觀點～</p>
<p><strong>天瓏書局：</strong> <a href="https://www.tenlong.com.tw/products/9786263334571">https://www.tenlong.com.tw/products/9786263334571</a></p>
</blockquote>
]]></content:encoded>
    </item>
  </channel>
</rss>
