<?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/%E5%BE%8C%E7%AB%AF%E9%9D%A2%E8%A9%A6/</link>
    <image><url>https://deanlin.net/images/author_hu_aa256fc934e9a932.jpg</url><title>後端面試｜林鼎淵 Dean Lin</title><link>https://deanlin.net/tags/%E5%BE%8C%E7%AB%AF%E9%9D%A2%E8%A9%A6/</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>Thu, 30 Sep 2021 08:46:20 +0800</lastBuildDate>
    <atom:link href="https://deanlin.net/tags/%E5%BE%8C%E7%AB%AF%E9%9D%A2%E8%A9%A6/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>[面試][後端]在正式 API 完成前，如何讓要串接的工程師不要空等？</title>
      <link>https://deanlin.net/blog/202109/fullstack-career-notes-day-15/</link>
      <pubDate>Thu, 30 Sep 2021 08:46:20 +0800</pubDate>
      <guid>https://deanlin.net/blog/202109/fullstack-career-notes-day-15/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>建立 Mock Server 後，前端工程師就失去耍廢時間不需要等後端做好才能串接。</description>
      <media:content url="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/cover_hu_a68742a0a8bf2016.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<p>建立 Mock Server 後，前端工程師就<del>失去耍廢時間</del>不需要等後端做好才能串接。</p>
<blockquote>
<p>前端工程師心裡 OS：「其實我是想要空等的。」</p>
</blockquote>
<h2 id="大綱">大綱<a class="h-anchor" href="#%e5%a4%a7%e7%b6%b1" aria-label="這個段落的連結"></a></h2>
<ol>
<li><strong>在正式 API 完成前，如何讓未來要串接的工程師不要空等？</strong>
<ul>
<li>1.1 面試官為什麼會問？</li>
<li>1.2 面試官想從答案確認什麼？</li>
<li>1.3 筆者提供的簡答</li>
</ul>
</li>
<li><strong>回答問題所需具備的知識</strong>
<ul>
<li>2.1 Mock Server 是什麼？學它有什麼好處？</li>
<li>2.1 用 Postman 建立 Mock Server</li>
<li>2.3 設計 Mock Server Response</li>
<li>2.4 設定 Environment 讓你快速切換執行環境</li>
<li>2.5 匯出 API documentation 給同事使用指引</li>
<li>2.6 讓 Mock Server 變成私有的</li>
</ul>
</li>
</ol>
<hr>
<h2 class="h-nomark" id="1-在正式-api-完成前如何讓要串接的工程師不要空等">1. 在正式 API 完成前，如何讓要串接的工程師不要空等？<a class="h-anchor" href="#1-%e5%9c%a8%e6%ad%a3%e5%bc%8f-api-%e5%ae%8c%e6%88%90%e5%89%8d%e5%a6%82%e4%bd%95%e8%ae%93%e8%a6%81%e4%b8%b2%e6%8e%a5%e7%9a%84%e5%b7%a5%e7%a8%8b%e5%b8%ab%e4%b8%8d%e8%a6%81%e7%a9%ba%e7%ad%89" 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>，因為許多專案都採取前後端分離的架構，前端常常要等後端完成後才能串接，如果後端提供的服務不穩定，又或是沒按造需求規格開發就容易導致前端空等。</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>你現在工作時，前端與後端是如何協作的</li>
<li>你有用什麼工具，讓前端不用等你寫完 API 就能提前串接</li>
<li>你有提供什麼文檔供前端串接時參考</li>
<li>如果回答的是某個工具（ex：Postman），會再詳細詢問有使用到工具的哪些功能</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>，同時使用第三方驗證工具「<code>Postman</code>」建立 <code>Mock Server</code>，並根據 Request 的參數給予對應的 Result 結果，讓前端不需要等後端 API 完成後才能開始串接的作業。</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>市面上提供 Mock Server 以及產生 API doc 的工具很多，不過「Postman」是筆者用起來最順手的；Postman 除了 API 的基礎測試外，還有許多加速工作效率的功能，就讓我們透過這篇文章讓自己的 Postman 更專業吧！</p>
<h3 class="h-nomark" id="21-mock-server-是什麼學它有什麼好處">2.1 Mock Server 是什麼？學它有什麼好處？<a class="h-anchor" href="#21-mock-server-%e6%98%af%e4%bb%80%e9%ba%bc%e5%ad%b8%e5%ae%83%e6%9c%89%e4%bb%80%e9%ba%bc%e5%a5%bd%e8%99%95" aria-label="這個段落的連結"></a></h3>
<p>在前後端分離的架構下，前端在完成網頁版面佈局後，需等待後端完成 API 才能做後續的開發；為了不讓前端在這段時間<del>偷懶</del>苦等，Mock Server 應運而生！<mark>它能回傳自訂的資料結構供前端使用</mark>，等後端完成 API 後，前端只需要切換網址就能使用真實資料。</p>
<p>除了上面的原因外，如果你開發環境的後端 Sever 不太穩定常常罷工，Mock Server 也能保證你的工作效率不受影響，畢竟不可能每次都等到 Server 修好後再工作吧？</p>
<hr>
<h3 class="h-nomark" id="22-用-postman-建立-mock-server">2.2 用 Postman 建立 Mock Server<a class="h-anchor" href="#22-%e7%94%a8-postman-%e5%bb%ba%e7%ab%8b-mock-server" aria-label="這個段落的連結"></a></h3>
<blockquote>
<p>Postman 改版非常快速，你看到的畫面可能跟我有些許不同</p>
</blockquote>
<ul>
<li><strong>STEP 1</strong>： 建立 Mock Server
<ol>
<li>
<p>New &gt; Mock Server</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-01.webp" width="1024" height="560" alt="2.2 用 Postman 建立 Mock Server（圖 1）" fetchpriority="high" decoding="async"></p>
</li>
<li>
<p>Create a new Collection &gt; input url &gt; Next<br>如果不是選擇已經存在的 API Collection，就需要<mark>至少填寫一個 Request URL</mark> 讓 Collections 有初始化的 API Request</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-02.webp" width="1024" height="682" alt="2.2 用 Postman 建立 Mock Server（圖 2）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>給 Mock Server 取個名字，並建議你勾選<mark>儲存 mock server URL 到環境變數</mark>的選項。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-03.webp" width="1024" height="669" alt="2.2 用 Postman 建立 Mock Server（圖 3）" loading="lazy" decoding="async"></p>
</li>
</ol>
</li>
<li><strong>STEP 2</strong>： 檢查 Mock Server 是否建立成功
<ol>
<li>
<p>建立成功後便可以在「Mock Servers」的分頁中看到剛剛建立的 Server，點進去後能看到這個 Sever 的網址。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-04.webp" width="1024" height="454" alt="2.2 用 Postman 建立 Mock Server（圖 4）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>接著我們到「Environments」的分頁確認，mock server URL 是否有儲存到環境變數，</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-05.webp" width="1024" height="367" alt="2.2 用 Postman 建立 Mock Server（圖 5）" loading="lazy" decoding="async"></p>
</li>
</ol>
</li>
</ul>
<hr>
<h3 class="h-nomark" id="23-設計-mock-server-response">2.3 設計 Mock Server Response<a class="h-anchor" href="#23-%e8%a8%ad%e8%a8%88-mock-server-response" aria-label="這個段落的連結"></a></h3>
<p>在 Mock Server 建立後，我們要設計不同 API Request 回傳的資料結構。</p>
<ul>
<li><strong>STEP 1</strong>：先用 Request 的 Default example 來了解使用方式
<ol>
<li>
<p>到「Collections」的分頁找到剛剛初始化的 Request， <code>{{url}}</code>會帶入環境變數所以右上角請選擇剛剛建立的「Mock_User」，按下「Send」後你會發現下面的 Response 一片空白，這是因為我們還沒設定 Mock Server Response。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-06.webp" width="1024" height="479" alt="2.3 設計 Mock Server Response（圖 6）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>在左側 Request 下面有一個「Default」，<mark>它就是用來自訂 Response 資料結構的 example</mark>，這邊我們用 JSON 格式寫個簡單的 Response example 後按「Save」。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-07.webp" width="1024" height="569" alt="2.3 設計 Mock Server Response（圖 7）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>回到剛剛的 Request，按下「Send」後會發現 Response 的資料結構跟剛剛填寫的範例相同。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-08.webp" width="1024" height="569" alt="2.3 設計 Mock Server Response（圖 8）" loading="lazy" decoding="async"></p>
</li>
</ol>
</li>
<li><strong>STEP 2</strong>：新增其他的 Response example
<ol>
<li>
<p>除了最初的 Default 外，我們還可以<mark>自己新增其他的 Response example</mark>。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-09.webp" width="1024" height="569" alt="2.3 設計 Mock Server Response（圖 9）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>可以透過<mark>加入 Params 讓這個 Request 有不同的 Response</mark>，這裡我們新增「error」、「correct」這兩個 example 並加入「control_res」這個 Params 來做示範。</p>
<blockquote>
<p>在「DESCRIPTION」填寫的資訊會顯示在 API 文件上，寫清楚一點不但方便自己記憶，也更容易讓合作者了解。</p>
</blockquote>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-10.webp" width="1024" height="569" alt="2.3 設計 Mock Server Response（圖 10）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-11.webp" width="1024" height="569" alt="2.3 設計 Mock Server Response（圖 11）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>回到剛剛的 Request ，我們在「control_res」填入不同的 VALUE，按下「Send」就會看到對應的 Response 嚕～</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-12.webp" width="1024" height="569" alt="2.3 設計 Mock Server Response（圖 12）" loading="lazy" decoding="async"></p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-13.webp" width="1024" height="569" alt="2.3 設計 Mock Server Response（圖 13）" loading="lazy" decoding="async"></p>
</li>
</ol>
</li>
</ul>
<hr>
<h3 class="h-nomark" id="24-設定-environment-讓你快速切換執行環境">2.4 設定 Environment 讓你快速切換執行環境<a class="h-anchor" href="#24-%e8%a8%ad%e5%ae%9a-environment-%e8%ae%93%e4%bd%a0%e5%bf%ab%e9%80%9f%e5%88%87%e6%8f%9b%e5%9f%b7%e8%a1%8c%e7%92%b0%e5%a2%83" aria-label="這個段落的連結"></a></h3>
<p>這是 Postman 重要的功能之一，它可以加快開發速度，讓你<mark>不用為每個環境都建立一個 Request</mark>。</p>
<ul>
<li>
<p><strong>如果沒設定會發生什麼蠢事？</strong></p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-14.webp" width="547" height="421" alt="2.4 設定 Environment 讓你快速切換執行環境（圖 14）" loading="lazy" decoding="async"></p>
<p>有沒有覺得上面這張圖片看起來很蠢，在了解 Environment 怎麼設定前，我的 Collections 就是這麼的複雜；<mark>因為開發時通常環境會分成：「Local、Dev、QA、Prod」</mark>，如果每新增一個環境你就複製一份，到最後你會無法進行妥善管理。</p>
</li>
<li>
<p><strong>STEP 1</strong>：新增 Environment<br>之前在建立 Mock Server 時其實就已經用到了 Environment，這裡我再詳細的跟大家說這個東西的好處。<br>請先到「Environments」的分頁按下「＋」的按鈕，接著輸入名稱來新增環境（我用 local_server 做示範）。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-15.webp" width="1024" height="399" alt="2.4 設定 Environment 讓你快速切換執行環境（圖 15）" loading="lazy" decoding="async"></p>
</li>
<li>
<p><strong>STEP 2</strong>：設定常用的 Environment variables</p>
<ul>
<li>
<p><strong>url</strong><br>這個是最實用的環境變數，讓你只需要調整 Request 的 Environment 就快速切換網址做測試。</p>
</li>
<li>
<p><strong>login_user、login_password</strong><br>每個環境的使用者登入資訊通常略有不同，且大部分的 API 都需要透過登入取得 token 才能使用，把他們加入環境變數可以加速你的測試。</p>
<blockquote>
<p><strong>警告</strong>：<mark>不建議把正式機的 password 加入環境變數，且測試機的 password 不要用平常自己會用的密碼</mark>，不然資安很危險的，都已經可以偷懶用 Environment，密碼自己去產生一組吧。</p>
</blockquote>
</li>
</ul>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-16.webp" width="1024" height="371" alt="2.4 設定 Environment 讓你快速切換執行環境（圖 16）" loading="lazy" decoding="async"></p>
</li>
<li>
<p><strong>STEP 3</strong>：在 Request 使用 Environment variables<br>想在 Request 中使用 Environment variables 只需要用 <code>{{your_env_var}}</code> 包起來就好，另外右上角記得要切換到正確的 Environment 才會帶入相應的資料喔！</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-17.webp" width="1024" height="435" alt="2.4 設定 Environment 讓你快速切換執行環境（圖 17）" loading="lazy" decoding="async"></p>
</li>
</ul>
<hr>
<h3 class="h-nomark" id="25-匯出-api-documentation-給同事使用指引">2.5 匯出 API documentation 給同事使用指引<a class="h-anchor" href="#25-%e5%8c%af%e5%87%ba-api-documentation-%e7%b5%a6%e5%90%8c%e4%ba%8b%e4%bd%bf%e7%94%a8%e6%8c%87%e5%bc%95" aria-label="這個段落的連結"></a></h3>
<p>相信後端工程師有一個共同經驗，無論你的 API 文件寫得再清楚、功能執行的再穩定；到了同事手中卻常常被說不能 Work，緊張的你檢查很多遍也找不出問題，百思不得其解的抵達同事座位後，才發現他原來<mark>漏了某個參數</mark>。</p>
<p>如果你有這樣的經驗，Postman 內建的 API documentation 能拯救你，讓你在 Publish 文件後可以跟同事幸福快樂的生活。</p>
<ul>
<li>
<p><strong>STEP 1</strong>：View documentation<br>選擇想要產生文檔的 Collection，按下「View documentation」後文檔就會顯示在右側，你可以透過切換右上角的環境變數來檢視文檔。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-18.webp" width="1024" height="688" alt="2.5 匯出 API documentation 給同事使用指引（圖 18）" loading="lazy" decoding="async"></p>
</li>
<li>
<p><strong>STEP 2</strong>：Publish documentation</p>
<ol>
<li>
<p>當你確定文檔內容都沒問題後按「Publish」。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-19.webp" width="1024" height="234" alt="2.5 匯出 API documentation 給同事使用指引（圖 19）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>接著會要你調整一些參數，調整完後建議先用左側的「Preview Documentation」自己確認看看是否符合。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-20.webp" width="1024" height="770" alt="2.5 匯出 API documentation 給同事使用指引（圖 20）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>確認一切都沒問題後按下「Publish Collection」就發布出去嚕～</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-21.webp" width="1024" height="450" alt="2.5 匯出 API documentation 給同事使用指引（圖 21）" loading="lazy" decoding="async"></p>
</li>
</ol>
</li>
<li>
<p><strong>STEP 4</strong>：Share API Doc URL<br>你可以將 URL 複製起來分享給你的合作夥伴，如果你想把這份文檔下架，按「Unpublish」即可。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-22.webp" width="1024" height="521" alt="2.5 匯出 API documentation 給同事使用指引（圖 22）" loading="lazy" decoding="async"></p>
</li>
</ul>
<hr>
<h3 class="h-nomark" id="26-讓-mock-server-變成私有的">2.6 讓 Mock Server 變成私有的<a class="h-anchor" href="#26-%e8%ae%93-mock-server-%e8%ae%8a%e6%88%90%e7%a7%81%e6%9c%89%e7%9a%84" aria-label="這個段落的連結"></a></h3>
<p>前面在建立 Mock Server 時，不知道有沒有人注意到「<code>Make mock server private</code>」的選項，在做這個設定前 Mock Server 的 URL 都是公開的，如果你想為自己的 Mock Server 多一層防護可以跟著下面步驟操作：</p>
<ul>
<li>
<p><strong>STEP 1</strong> : 編輯 Mock server</p>
<ol>
<li>
<p>在「Mock Servers」分頁打開之前創建的 Server，按下「Edit」。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-23.webp" width="1024" height="386" alt="2.6 讓 Mock Server 變成私有的（圖 23）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>將「Make mock server private」打勾並按下「Save changes」。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-24.webp" width="1024" height="679" alt="2.6 讓 Mock Server 變成私有的（圖 24）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>回到之前的 Request，你會發現按下「Send」後會回傳錯誤訊息，這是因為現在 <mark>Mock Server 都需要添加 API key 到 Request 的 Header 才能使用</mark>。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-25.webp" width="1024" height="522" alt="2.6 讓 Mock Server 變成私有的（圖 25）" loading="lazy" decoding="async"></p>
</li>
</ol>
</li>
<li>
<p><strong>STEP 2</strong> : 產生 Postman API key</p>
<ol>
<li>
<p>進去這個 <a href="https://go.postman.co/settings/me/api-keys">網址</a> ，點擊「Generate API key」。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-26.webp" width="1024" height="425" alt="2.6 讓 Mock Server 變成私有的（圖 26）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>填上用來識別這個 API key 的名稱後按下「Generate API key」。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-27.webp" width="1024" height="457" alt="2.6 讓 Mock Server 變成私有的（圖 27）" loading="lazy" decoding="async"></p>
</li>
<li>
<p>接著<mark>請複製這個 API key</mark>，上面已經警告你這是唯一見到它的機會了。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-28.webp" width="1024" height="482" alt="2.6 讓 Mock Server 變成私有的（圖 28）" loading="lazy" decoding="async"></p>
</li>
</ol>
</li>
<li>
<p><strong>STEP 3</strong>：將 API key 加入 Environment<br>因為日後 Mock Server 的所有 Request 都需要這個 API key，所以我們把他加入 Environment，變數名稱為「x-api-key」。</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-29.webp" width="1024" height="394" alt="2.6 讓 Mock Server 變成私有的（圖 29）" loading="lazy" decoding="async"></p>
</li>
<li>
<p><strong>STEP 4</strong>：在 Request 的 Header 加上 x-api-key<br>最後回到 Request，在 Headers 的分頁下加入「x-api-key」這個參數並將環境變數 <code>{{x-api-key}}</code> 作為值，最後按下「Send」就能看到正確的 Response 回傳嚕！</p>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-30.webp" width="1024" height="456" alt="2.6 讓 Mock Server 變成私有的（圖 30）" loading="lazy" decoding="async"></p>
</li>
</ul>
<hr>
<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://medium.com/dean-lin/afc5c04742e0">讓你的 Postman 更專業(筆者部落格)</a></li>
</ol>
<hr>
<hr>
<blockquote>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-15/images/fullstack-career-notes-day-15-31.webp" width="1024" height="233" alt="參考資源（圖 31）" loading="lazy" 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>
    <item>
      <title>[面試][後端]請簡述 Node.js 的 Event Loop</title>
      <link>https://deanlin.net/blog/202109/fullstack-career-notes-day-14/</link>
      <pubDate>Wed, 29 Sep 2021 08:46:22 +0800</pubDate>
      <guid>https://deanlin.net/blog/202109/fullstack-career-notes-day-14/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>這是一個在了解後，無論面試還是工作，CP 值都很高的題目，建議讀者要真的融會貫通。</description>
      <media:content url="https://deanlin.net/blog/202109/fullstack-career-notes-day-14/images/cover_hu_579b7f5274d9e2b1.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<blockquote>
<p>熟悉的起手式：「我方便問你一個 Node.js 核心的問題嗎？」</p>
</blockquote>
<p>這是一個在了解後，無論面試還是工作，CP 值都很高的題目，建議讀者要真的融會貫通。</p>
<h2 id="大綱">大綱<a class="h-anchor" href="#%e5%a4%a7%e7%b6%b1" aria-label="這個段落的連結"></a></h2>
<ol>
<li><strong>請簡述 Node.js 的 Event Loop</strong>
<ul>
<li>1.1 面試官為什麼會問？</li>
<li>1.2 面試官想從答案確認什麼？</li>
<li>1.3 筆者提供的簡答</li>
</ul>
</li>
<li><strong>回答問題所需具備的知識</strong>
<ul>
<li>2.1 Event Loop 執行的邏輯</li>
<li>2.2 用 Node.js 範例程式確認自己是否理解 Event Loop</li>
<li>2.3 解析 Node.js 範例程式執行順序</li>
</ul>
</li>
<li><strong>衍伸問題</strong>
<ul>
<li>3.1 可以簡述 Node.js 跟 JavaScript 的差異嗎？</li>
<li>3.2 readFile 和 createReadStream 函式的差異？</li>
<li>3.3 REPL 是什麼？</li>
</ul>
</li>
</ol>
<hr>
<h2 class="h-nomark" id="1-請簡述-nodejs-的-event-loop">1. 請簡述 Node.js 的 Event Loop<a class="h-anchor" href="#1-%e8%ab%8b%e7%b0%a1%e8%bf%b0-nodejs-%e7%9a%84-event-loop" 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>只要你的<code>履歷上有 Node.js</code>，10 間公司至少有 3 間會問這個<mark>常見面試題</mark>；而且問題的起手式出奇的一致：「我方便問你一個 Node.js 核心的問題嗎？」</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>你了解 Event Loop 對 Node.js 的重要性</li>
<li>你能大概說明 Event Loop 每個階段的任務</li>
<li>如果出白板題要你解釋程式執行的順序，你可以正確回答</li>
</ul>
<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><code>Node.js 之所以高效，是因為採取單執行緒與 Event Loop 的概念</code>；將所有需要等待結果、請求外部資源的函式，全部丟到 Event Loop 中等待；而 Event Loop 的邏輯是 Node.js 底層用 C 語言撰寫的 libuv 庫來運行的。</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>
<h3 class="h-nomark" id="21-event-loop-執行的邏輯">2.1 Event Loop 執行的邏輯<a class="h-anchor" href="#21-event-loop-%e5%9f%b7%e8%a1%8c%e7%9a%84%e9%82%8f%e8%bc%af" aria-label="這個段落的連結"></a></h3>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-14/images/fullstack-career-notes-day-14-01.webp" width="1024" height="579" alt="2.1 Event Loop 執行的邏輯（圖 1）" fetchpriority="high" decoding="async"></p>
<ul>
<li><strong>了解 MacroTask 的 6 個階段</strong>
<ul>
<li><strong>Timer</strong><br>等計時器（setTimeout、setInterval）的時間一到，會把他們的 callback 放在這裡等待執行。</li>
<li><strong>Pending callbacks</strong><br>作業系統層級使用（ex：TCP errors、sockets 連線被拒絕）。</li>
<li><strong>Idle, Prepare</strong><br>內部使用。</li>
<li><strong>Polling：</strong>
<ul>
<li>如果 Queue 不為空，依次取出 callback 函數執行，直到 Queue 為空或是抵達系統最大限制。</li>
<li>如果 Queue 為空但有設置「setImmediate」就進入 Check 階段。</li>
<li>如果 Queue 為空但沒有設置「setImmediate」就會在 Polling 階段等待，直到 Queue 有東西或是 Timer 時間抵達。</li>
</ul>
</li>
<li><strong>Check</strong><br>處理 setImmediate 的 callback。</li>
<li><strong>Close callbacks</strong><br>處理關閉連線、檔案的 callback。</li>
</ul>
</li>
</ul>
<p><mark>Macrotask Queue 在 Evevnt Loop 優先層級較低，接下來介紹優先層級更高的兩個 Queue。</mark></p>
<ul>
<li>
<p><strong>NextTick Queue 優先層級最高</strong><br>「process.nextTick()」的 callback 可以隨意插隊；只要這個 Queue 有東西就會優先執行。</p>
</li>
<li>
<p><strong>MicroTask Queue 優先層級次高</strong><br>「Promise」的狀態從 pending 轉變為 resolve 或 reject 時，執行的 callback 會進入這個 Queue。</p>
<blockquote>
<p><strong>注意</strong>：<mark>Promise 在創建時是同步的</mark>，不會進入 Event Loop。</p>
</blockquote>
</li>
</ul>
<hr>
<h3 class="h-nomark" id="22-用-nodejs-範例程式確認自己是否理解-event-loop">2.2 用 Node.js 範例程式確認自己是否理解 Event Loop<a class="h-anchor" href="#22-%e7%94%a8-nodejs-%e7%af%84%e4%be%8b%e7%a8%8b%e5%bc%8f%e7%a2%ba%e8%aa%8d%e8%87%aa%e5%b7%b1%e6%98%af%e5%90%a6%e7%90%86%e8%a7%a3-event-loop" aria-label="這個段落的連結"></a></h3>
<p>大家可以先用紙筆模擬看看下面程式的執行順序：</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>console.log(<span style="color:#a5d6ff">&#34;start&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>process.nextTick(<span style="color:#ff7b72">function</span> () {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;nextTick1&#34;</span>);
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>setTimeout(<span style="color:#ff7b72">function</span> () {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;setTimeout&#34;</span>);
</span></span><span style="display:flex;"><span>}, <span style="color:#a5d6ff">0</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">new</span> Promise(<span style="color:#ff7b72">function</span> (resolve, reject) {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;promise&#34;</span>);
</span></span><span style="display:flex;"><span>  resolve(<span style="color:#a5d6ff">&#34;resolve&#34;</span>);
</span></span><span style="display:flex;"><span>}).then(<span style="color:#ff7b72">function</span> (result) {
</span></span><span style="display:flex;"><span>  console.log(result);
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#ff7b72">async</span> <span style="color:#ff7b72">function</span> () {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;async&#34;</span>);
</span></span><span style="display:flex;"><span>})();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>setImmediate(<span style="color:#ff7b72">function</span> () {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;setImmediate&#34;</span>);
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>process.nextTick(<span style="color:#ff7b72">function</span> () {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;nextTick2&#34;</span>);
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>console.log(<span style="color:#a5d6ff">&#34;end&#34;</span>);
</span></span></code></pre></div><p>如果答案跟下面結果一樣，那代表你很了解 Node.js 的 Event Loop 邏輯：</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>start
</span></span><span style="display:flex;"><span>promise
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">async</span>
</span></span><span style="display:flex;"><span>end
</span></span><span style="display:flex;"><span>nextTick1
</span></span><span style="display:flex;"><span>nextTick2
</span></span><span style="display:flex;"><span>resolve
</span></span><span style="display:flex;"><span>setTimeout
</span></span><span style="display:flex;"><span>setImmediate
</span></span></code></pre></div><hr>
<h3 class="h-nomark" id="23-解析-nodejs-範例程式執行順序">2.3 解析 Node.js 範例程式執行順序<a class="h-anchor" href="#23-%e8%a7%a3%e6%9e%90-nodejs-%e7%af%84%e4%be%8b%e7%a8%8b%e5%bc%8f%e5%9f%b7%e8%a1%8c%e9%a0%86%e5%ba%8f" aria-label="這個段落的連結"></a></h3>
<ul>
<li><strong>SETP 1：</strong> 順序執行，先把同步函式解決。
<ol>
<li>
<p>因為 <code>Promise</code> 在創建時是同步的，所以會先執行。</p>
</li>
<li>
<p>在 function 前面加上 async 宣告為異步函式，執行時會被轉換為 Promise。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>console.log(<span style="color:#a5d6ff">&#34;start&#34;</span>);
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#ff7b72">new</span> Promise(<span style="color:#ff7b72">function</span> (resolve, reject) {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;promise&#34;</span>);
</span></span><span style="display:flex;"><span>  resolve(<span style="color:#a5d6ff">&#34;resolve&#34;</span>);
</span></span><span style="display:flex;"><span>}).then(<span style="color:#ff7b72">function</span> (result) {
</span></span><span style="display:flex;"><span>  console.log(result);
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>(<span style="color:#ff7b72">async</span> <span style="color:#ff7b72">function</span> () {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;async&#34;</span>);
</span></span><span style="display:flex;"><span>})();
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>console.log(<span style="color:#a5d6ff">&#34;end&#34;</span>);
</span></span></code></pre></div></li>
</ol>
</li>
<li><strong>STEP 2：</strong> 進入 Event Loop。
<ol>
<li>
<p>如果執行過程中遇到 <code>NextTick Queue</code> 就優先執行。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>process.nextTick(<span style="color:#ff7b72">function</span> () {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;nextTick1&#34;</span>);
</span></span><span style="display:flex;"><span>});
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span>process.nextTick(<span style="color:#ff7b72">function</span> () {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;nextTick2&#34;</span>);
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div></li>
<li>
<p>在處理完最高優先層級後，如果執行過程中遇到 <code>MicroTask Queue</code> 就執行。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#ff7b72">new</span> Promise(<span style="color:#ff7b72">function</span> (resolve, reject) {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;promise&#34;</span>);
</span></span><span style="display:flex;"><span>  resolve(<span style="color:#a5d6ff">&#34;resolve&#34;</span>);
</span></span><span style="display:flex;"><span>}).then(<span style="color:#ff7b72">function</span> (result) {
</span></span><span style="display:flex;"><span>  console.log(result);
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div></li>
<li>
<p>在前兩個高優先層級的 Queue 清空後，返回 Event Loop 繼續執行，<code>setTimeout</code> 設定的時間已到先執行。</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>setTimeout(<span style="color:#ff7b72">function</span> () {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;setTimeout&#34;</span>);
</span></span><span style="display:flex;"><span>}, <span style="color:#a5d6ff">0</span>);
</span></span></code></pre></div></li>
<li>
<p>接著再在「Check」 階段執行 <code>setImmediate</code></p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span>setImmediate(<span style="color:#ff7b72">function</span> () {
</span></span><span style="display:flex;"><span>  console.log(<span style="color:#a5d6ff">&#34;setImmediate&#34;</span>);
</span></span><span style="display:flex;"><span>});
</span></span></code></pre></div></li>
</ol>
</li>
</ul>
<p>以上步驟執行完成後就是範例程式的解答啦～希望對大家理解 Event Loop 有幫助。</p>
<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-可以簡述-nodejs-跟-javascript-的差異嗎">3.1 可以簡述 Node.js 跟 JavaScript 的差異嗎？<a class="h-anchor" href="#31-%e5%8f%af%e4%bb%a5%e7%b0%a1%e8%bf%b0-nodejs-%e8%b7%9f-javascript-%e7%9a%84%e5%b7%ae%e7%95%b0%e5%97%8e" aria-label="這個段落的連結"></a></h3>
<p><mark>考點：確認求職者是否理解自己天天使用的工具</mark></p>
<p>JavaScript 是程式語言，可以在合適的瀏覽器中運行；而 Node.js 是一個能執行JavaScript 的環境，它以 Chrome V8 引擎為核心，再加上 C/C++套件，讓 Sever 端也可以執行 JavaScript。</p>
<hr>
<h3 class="h-nomark" id="32-readfile-和-createreadstream-函式的差異">3.2 readFile 和 createReadStream 函式的差異？<a class="h-anchor" href="#32-readfile-%e5%92%8c-createreadstream-%e5%87%bd%e5%bc%8f%e7%9a%84%e5%b7%ae%e7%95%b0" aria-label="這個段落的連結"></a></h3>
<p><mark>考點：判斷求職者過去專案中使否使用過這類函式，並理解差異</mark></p>
<p><code>readFile</code> 函式會將讀取到的完整內容<mark>存在記憶體</mark>後傳給使用者，而 <code>createReadStream</code> 函式則是<mark>逐塊讀取</mark>檔案，不是全部存在記憶體中；因此要讀取較大的檔案時，建議使用 createReadStream ，利用其逐塊讀取的特性能減少使用者等待時間。</p>
<hr>
<h3 class="h-nomark" id="33-repl-是什麼">3.3 REPL 是什麼？<a class="h-anchor" href="#33-repl-%e6%98%af%e4%bb%80%e9%ba%bc" aria-label="這個段落的連結"></a></h3>
<p><mark>考點：對專有名詞是否熟悉，能否解釋</mark></p>
<p>REPL（Read Eval Print Loop）是一個用來<mark>執行程式語言的虛擬環境</mark>。</p>
<p>就像是我們在瀏覽器的 Console 可以執行 JavaScript 程式碼；在安裝完 Node.js 後，新增一個 JavaScript 檔，在終端機輸入<code>node xxx.js</code>便可以執行它。</p>
<hr>
<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://medium.com/dean-lin/c7129063d0f4">Node.js 的 Event Loop (事件輪詢)到底在做什麼？(筆者部落格)</a></li>
<li>15 個常見的 Node.js 面試問題及答案</li>
<li><a href="https://ithelp.ithome.com.tw/articles/10230126">你有沒有想過，到底 Server 是如何「同時處理多個 requests」的？ - Node.js 篇</a></li>
</ol>
<hr>
<hr>
<blockquote>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-14/images/fullstack-career-notes-day-14-02.webp" width="1024" height="233" alt="參考資源：（圖 2）" loading="lazy" 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>
    <item>
      <title>[面試][後端]你會的後端框架不只一個，可以說明一下它們之間的差異嗎？</title>
      <link>https://deanlin.net/blog/202109/fullstack-career-notes-day-13/</link>
      <pubDate>Tue, 28 Sep 2021 08:52:51 +0800</pubDate>
      <guid>https://deanlin.net/blog/202109/fullstack-career-notes-day-13/</guid>
      <dc:creator>林鼎淵</dc:creator>
      <category>職涯成長</category>
      <description>工程師真的很難，會得不多會被問為什麼沒學，會得很多還要被質疑專業程度；這種比較類型的問題，除非你有事先做功課，不然就算你都會用也未必能在現場對答如流。</description>
      <media:content url="https://deanlin.net/blog/202109/fullstack-career-notes-day-13/images/cover_hu_fd19aa6d1c00a16c.jpg" medium="image" type="image/jpeg" width="1200" height="675" />
      <content:encoded><![CDATA[<blockquote>
<p>你是十八般武藝樣樣精通，還是樣樣通樣樣鬆？</p>
</blockquote>
<p>工程師真的很難，會得不多會被問為什麼沒學，會得很多還要被質疑專業程度；這種比較類型的問題，除非你有事先做功課，不然就算你都會用也未必能在現場對答如流。</p>
<h2 id="大綱">大綱<a class="h-anchor" href="#%e5%a4%a7%e7%b6%b1" aria-label="這個段落的連結"></a></h2>
<ol>
<li><strong>你會的後端框架不只一個，可以說明一下它們之間的差異嗎？</strong>
<ul>
<li>1.1 面試官為什麼會問？</li>
<li>1.2 面試官想從答案確認什麼？</li>
<li>1.3 筆者提供的簡答</li>
</ul>
</li>
<li><strong>回答問題所需具備的知識</strong>
<ul>
<li>2.1 PHP VS Node.js</li>
<li>2.2 用 supervisor 讓 Node.js 熱更新</li>
<li>2.3 不一定要拼個誰輸誰贏</li>
</ul>
</li>
<li><strong>衍伸問題</strong>
<ul>
<li>3.1 既然你先學了 Node.js 的框架，為何後來改用 PHP 的框架？</li>
<li>3.2 使用框架有什麼好處跟壞處？</li>
</ul>
</li>
</ol>
<hr>
<h2 class="h-nomark" id="1-你會的後端框架不只一個可以說明一下它們之間的差異嗎">1. 你會的後端框架不只一個，可以說明一下它們之間的差異嗎？<a class="h-anchor" href="#1-%e4%bd%a0%e6%9c%83%e7%9a%84%e5%be%8c%e7%ab%af%e6%a1%86%e6%9e%b6%e4%b8%8d%e5%8f%aa%e4%b8%80%e5%80%8b%e5%8f%af%e4%bb%a5%e8%aa%aa%e6%98%8e%e4%b8%80%e4%b8%8b%e5%ae%83%e5%80%91%e4%b9%8b%e9%96%93%e7%9a%84%e5%b7%ae%e7%95%b0%e5%97%8e" 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>中顯示求職者會如下的後端（Backend）框架：</p>
<ul>
<li>PHP：Laravel</li>
<li>Node.js：Express.js、AdonisJS</li>
</ul>
<p>當你會的東西多，面試官就會想了解你是每個都學一點，還是真的了解它。</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>能否簡單敘述 PHP 與 Node.js 的差異</li>
<li>舉例過去用這些框架做過哪些專案或是功能</li>
<li>為什麼會學習新的框架</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>之前使用 <code>PHP 的 Laravel 框架</code>開發過內部管理系統，也曾用 <code>Node.js 的 Express.js 框架</code>完成過餐廳點餐系統。</p>
<p>兩者的<mark>差異主要因為程式語言</mark>而產生的，PHP 是同步語言、多執行緒，Node.js 是一個能執行 JavaScript 的環境，支援非同步，為單執行緒。</p>
<p>如果專案要求<mark>穩定一致的效能</mark>，我會偏向使用 PHP 框架；而如果要<mark>承接高流量</mark>，我會選擇 Node.js 框架。</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>
<h3 class="h-nomark" id="21-php-vs-nodejs">2.1 PHP VS Node.js<a class="h-anchor" href="#21-php-vs-nodejs" aria-label="這個段落的連結"></a></h3>
<p>如果面對一個問題只有<mark>一種解決方案</mark>時，面試官會<mark>深入詢問</mark>這個技術；但如果面對問題有<mark>兩個以上的解決方案</mark>，他就會問你在<mark>不同情境</mark>下該使用什麼技術，每個技術都有各自的優勢，這邊我們就從不同的角度來做分析吧～</p>
<ul>
<li><strong>同步的 PHP vs 異步的 Node.js</strong>
<ul>
<li>同步的 PHP 會為每個 Request 建立一個 thread，每個 thread 都會消耗記憶體，也就是說如果想要服務更多的客戶就要花心思在<mark>硬體設備</mark>上。</li>
<li>異步的 Node.js 是非阻塞 (non-blocking) I/O 設計，搭配上 Event Loop 可以用一句很形象的話說明：「與其人多但好多人閒著；還不如一個人拼命往死裡做。」</li>
</ul>
</li>
<li><strong>多執行緒的 PHP VS 單執行緒的 Node.js</strong>
<ul>
<li>
<p><strong>多執行緒 (multi-threaded)的 PHP</strong><br>使用阻塞 (blocking) I/O 的設計</p>
<blockquote>
<p>PHP 可以為每個 Request 都開一個執行緒；如果你想要實現非阻塞也能透過 <a href="https://reactphp.org/">reactPHP</a> 來實現。</p>
</blockquote>
</li>
<li>
<p><strong>單執行緒 (single-threaded)的 Node.js</strong><br>使用非阻塞 (non-blocking) I/O 設計 + 提供非同步 (asynchronous) 處理</p>
<blockquote>
<p>Node.js 原則上是單執行緒，但可以透過 <a href="https://pm2.keymetrics.io/">PM2</a> 的 Cluster Mode 達到多執行緒。</p>
</blockquote>
</li>
</ul>
</li>
<li><strong>應用場景</strong><br>從 Client 端與 Server 端的溝通頻率來做分析：
<ul>
<li><strong>溝通頻率不高</strong><br>PHP 是個不錯的選擇（ex：個人部落格，像 WordPress 就是用 PHP 寫的）。</li>
<li><strong>溝通頻率頻繁</strong><br>Node.js 更能激發性能（ex：single-page-application、聊天室）；它適合大吞吐量的系統，較不適合需要大量 CPU 運算的系統。</li>
</ul>
</li>
<li><strong>可使用的資源</strong>
<ul>
<li>
<p><strong>PHP 有 Composer</strong><br>Composer 的命名方式：「所有者/package 名稱」</p>
</li>
<li>
<p><strong>Node.js 有 NPM</strong><br>NPM 的命名方式：「package 名稱」</p>
<blockquote>
<p>因為 NPM 的命名方式太自由，導致上面有很多的資源都是無效資源，<mark>關鍵字第一個找到的未必是最合適的</mark>。</p>
</blockquote>
</li>
</ul>
</li>
<li><strong>人才市場</strong>
<ul>
<li><strong>人才數量</strong><br>PHP 比 Node.js 早了 10 幾年發行，因此市場上使用 PHP 的人比使用 Node.js 的人更多；如果<mark>職位流動性高，用 PHP 開發</mark>會比較合適。</li>
<li><strong>薪資</strong><br>物以稀為貴，同樣都是新人，<code>會 Node.js 的薪水會略高於會 PHP</code> 的求職者。</li>
</ul>
</li>
<li><strong>專案容量</strong><br>用 Laravel 跟 Express.js 來比較：
<ul>
<li><strong>專案初期</strong><br>一開始 Laravel 因為包山包海所以專案體積較大。</li>
<li><strong>專案後期</strong><br>儘管 Express 是 Node.js 輕量級的框架，但因為<mark>實作過程往往要擴充一堆 package</mark>，而且一個 package 往往會有很多的 dependency；這些原因容易導致最終實作出來的是一個笨重的專案。</li>
</ul>
</li>
<li><strong>程式語言轉換</strong><br>除非你的運氣逆天，每次都剛好找到符合你技能樹的公司，而且這間公司專案用的技術還很固定；不然肯定要面對程式語言的轉換，這邊分享幾個轉換時要注意的重點。
<ul>
<li><strong>找類型相似的框架</strong><br>從 PHP 跳到 Node.js 一定會面臨諸多不適應；但如果你選擇的是跟 <mark>Laravel 很類似的 AdonisJS 框架</mark>，這份不適感會下降許多，反之亦然。</li>
<li><strong>語言語法</strong><br>如果你已經熟悉了一種程式語言，我覺得轉換到另外一個語言的學習成本不會太高；但許多<mark>內建函式都要重新學習、生命週期也要重新熟悉、錯誤處理的經驗也要重新累積</mark>。</li>
<li><strong>專案規模</strong><br>如果是只需要 CRUD 邏輯的小專案，那我覺得藉此多瞭解一門程式語言是一個很棒的機會；但如果面臨的是業務邏輯複雜的大專案，我強烈建議一定要選自己熟悉的程式語言，或者團隊中的扛霸子熟悉這門語言；不然出事根本沒人可以救得了。</li>
</ul>
</li>
<li><strong>效能</strong>
<ul>
<li><strong>響應速度</strong><br>Node.js 靠著 V8 引擎加上非同步的特型，擁有較快的響應速度。</li>
</ul>
</li>
<li><strong>面對錯誤的處理</strong>
<ul>
<li>
<p>PHP 遇到某個 Request 錯誤時，它只對這個 Request 產生影響。</p>
</li>
<li>
<p>Node.js 因為所有 Request 都在單執行緒的 Web-server 中，所以某個 Request 導致的未知錯誤就可能影響到整個 Server。</p>
<blockquote>
<p>不過這塊可以透過 PM2 的 Cluster Mode 與自動重啟來補救。</p>
</blockquote>
</li>
</ul>
</li>
<li><strong>熱更新</strong>
<ul>
<li>PHP 修改後，只要刷新頁面就能看到。</li>
<li>Node.js 預設沒有熱更新，需要關閉專案後重啟。</li>
</ul>
</li>
</ul>
<hr>
<h3 class="h-nomark" id="22-用-supervisor-讓-nodejs-熱更新">2.2 用 supervisor 讓 Node.js 熱更新<a class="h-anchor" href="#22-%e7%94%a8-supervisor-%e8%ae%93-nodejs-%e7%86%b1%e6%9b%b4%e6%96%b0" aria-label="這個段落的連結"></a></h3>
<p>在開發階段推薦使用 supervisor 這款套件。</p>
<ul>
<li>
<p><strong>STEP 1</strong>：在全域安裝套件<code>npm install supervisor -g</code></p>
</li>
<li>
<p><strong>STEP 2</strong>：建立一個<code>myapp.js</code>的檔案，並複製貼上下面程式</p>
<div class="highlight"><pre tabindex="0" style="color:#e6edf3;background-color:#0d1117;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-javascript" data-lang="javascript"><span style="display:flex;"><span><span style="color:#ff7b72">var</span> http <span style="color:#ff7b72;font-weight:bold">=</span> require(<span style="color:#a5d6ff">&#34;http&#34;</span>);
</span></span><span style="display:flex;"><span>http
</span></span><span style="display:flex;"><span>  .createServer(<span style="color:#ff7b72">function</span> (req, res) {
</span></span><span style="display:flex;"><span>    res.writeHead(<span style="color:#a5d6ff">200</span>, { <span style="color:#a5d6ff">&#34;Content-Type&#34;</span><span style="color:#ff7b72;font-weight:bold">:</span> <span style="color:#a5d6ff">&#34;text/plain&#34;</span> });
</span></span><span style="display:flex;"><span>    res.end(<span style="color:#a5d6ff">&#34;Hello World!&#34;</span>);
</span></span><span style="display:flex;"><span>  })
</span></span><span style="display:flex;"><span>  .listen(<span style="color:#a5d6ff">3000</span>, <span style="color:#a5d6ff">&#34;127.0.0.1&#34;</span>);
</span></span></code></pre></div></li>
<li>
<p><strong>STEP 3</strong>：用<code>node myapp.js</code>啟動程式後，修改<code>res.end(&quot;Hello World!&quot;);</code>的內容；再刷新網頁後<mark>內容不變</mark>。</p>
</li>
<li>
<p><strong>STEP 4</strong>：改用<code>supervisor myapp.js</code>啟動程式，修改<code>res.end(&quot;Hello World!&quot;);</code>的內容；再刷新網頁後<mark>內容更新</mark>。</p>
</li>
</ul>
<p>supervisor 也可以做專案資料夾的監控，但是要記得排除一些資料夾（ex：儲存 log 檔的）；否則你的專案就無時無刻在重起了。</p>
<blockquote>
<p>如果是正式的網站且流量大，建議使用 PM2 來做處理，它也有監控資料夾的功能。</p>
</blockquote>
<hr>
<h3 class="h-nomark" id="23-不一定要拼個誰輸誰贏">2.3 不一定要拼個誰輸誰贏<a class="h-anchor" href="#23-%e4%b8%8d%e4%b8%80%e5%ae%9a%e8%a6%81%e6%8b%bc%e5%80%8b%e8%aa%b0%e8%bc%b8%e8%aa%b0%e8%b4%8f" aria-label="這個段落的連結"></a></h3>
<blockquote>
<p>存在即合理</p>
</blockquote>
<ul>
<li><strong>小專案不用花太多時間在評估框架及程式語言選擇上</strong><br>有些公司對專案要用什麼框架以及程式語言保持著非常謹慎的態度，謹慎的態度是對的，但也要考量到專案的規模；如果今天的專案就是 CRUD 的簡單應用，<mark>預估使用者數量不多或是主要來自於內部成員，用什麼框架及程式語言其實都差不多</mark>。</li>
<li><strong>看組織成員擅長的語言</strong><br>如果公司高層為了追求潮流而要求開發人員用一個不熟悉的框架去做專案，他最好祈求專案上線後平平安安；不然<mark>出事了公司沒有能夠處理的人才</mark>，沒有人會在意一個不能用的網站效能有多好。</li>
<li><strong>每個程式語言都有自己的擁護者</strong><br>在不同的條件下，每個程式語言都有自己的優勢，而且每年都會誕生新的框架與程式語言；筆者覺得與其不停盲目追逐新的技術，不如先深入研究一個成熟的技術，<mark>當你有辦法靠它解決各種現實難題時，再去學新的框架跟程式語言也不晚</mark>。</li>
</ul>
<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-既然你先學了-nodejs-的框架為何後來改用-php-的框架">3.1 既然你先學了 Node.js 的框架，為何後來改用 PHP 的框架？<a class="h-anchor" href="#31-%e6%97%a2%e7%84%b6%e4%bd%a0%e5%85%88%e5%ad%b8%e4%ba%86-nodejs-%e7%9a%84%e6%a1%86%e6%9e%b6%e7%82%ba%e4%bd%95%e5%be%8c%e4%be%86%e6%94%b9%e7%94%a8-php-%e7%9a%84%e6%a1%86%e6%9e%b6" aria-label="這個段落的連結"></a></h3>
<p><mark>考點：這題其實是想了解求職者的人格特質</mark></p>
<p>這兩個都是為了解決問題的技術，我一開始用 Node.js 的 Express 框架<mark>獨立完成</mark>了幾份專案；但後來有一個<code>需要 Team work</code> 的大型專案，因為當時的組長比較熟悉 PHP 的 Laravel 框架，所以我便藉由這個機會<mark>學習新的技術</mark>；也因為這次的技術轉換，讓我<mark>了解不同框架在部署以及效能各方面的差異</mark>。</p>
<blockquote>
<p><strong>我想透過上面的回答給面試官幾個訊息：</strong></p>
<ul>
<li>我能獨立完成專案，也可以團隊合作。</li>
<li>我願意學習新技術。</li>
<li>學習的同時會分析不同框架的優劣。</li>
</ul>
</blockquote>
<hr>
<h3 class="h-nomark" id="32-使用框架有什麼好處跟壞處">3.2 使用框架有什麼好處跟壞處？<a class="h-anchor" href="#32-%e4%bd%bf%e7%94%a8%e6%a1%86%e6%9e%b6%e6%9c%89%e4%bb%80%e9%ba%bc%e5%a5%bd%e8%99%95%e8%b7%9f%e5%a3%9e%e8%99%95" aria-label="這個段落的連結"></a></h3>
<p><mark>考點：確認求職者對框架的認知</mark></p>
<ul>
<li><strong>好處</strong><br>框架能夠<mark>讓初學者快速入門並開發出有一定水平</mark>的專案，因為框架提供了許多常用的函式，因此可以<mark>大幅縮短專案時程</mark>；在團隊協作上框架優勢更為明顯，能夠讓成員<mark>有一致的開發方式</mark>。</li>
<li><strong>壞處</strong><br>因為框架已經幫開發人員做了太多事情，這會導致<mark>開發人員並不理解許多功能的原理</mark>，這也造成了<mark>一但框架無法滿足功能，初學者的生產力會斷崖式下降</mark>；如果長期使用，也容易<mark>讓自己的開發思維被限制在框架內</mark>。</li>
</ul>
<hr>
<h3 id="筆者碎碎念">筆者碎碎念<a class="h-anchor" href="#%e7%ad%86%e8%80%85%e7%a2%8e%e7%a2%8e%e5%bf%b5" aria-label="這個段落的連結"></a></h3>
<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://thomashunter.name/posts/2012-06-21-php-vs-nodejs">PHP + Apache Stack vs Node.js</a></li>
<li><a href="https://web.archive.org/web/20220124190306/https://www.itread01.com/content/1549876684.html" title="原網頁已失效，連到網際網路檔案館的存檔">服務端 I/O 效能大比拼：Node、PHP、Java、Go</a></li>
<li><a href="https://jishuin.proginn.com/p/763bfbd2cab5">簡析 Node.js 特點與應用場景</a></li>
<li><a href="https://www.jianshu.com/p/6d84e5efe99d">詳細版 | 用 Supervisor 守護你的 Node.js 進程</a></li>
<li><a href="https://iter01.com/403097.html">淺談 Node.js 和 PHP 程式管理</a></li>
</ol>
<hr>
<hr>
<blockquote>
<p><img src="https://deanlin.net/blog/202109/fullstack-career-notes-day-13/images/fullstack-career-notes-day-13-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>
