---
# System prepended metadata

title: 後端面試題目

---

1. 開場
- 什麼是 Scrum/Agile? 技術
2. DB

- 如何選擇 NoSQL / RDBMS
- 請簡述 inner join、outer join
- 請簡述樂觀鎖、悲觀鎖
- 請簡述關係型資料庫的 4 大索引
- 請簡述關係型資料庫的 4 個隔離層級
- 如何避免髒讀
- 請簡述關係型資料庫查找的算法

3. Python

- 請比較 Python mutable object 與 immutable object 並舉例
- 請簡述一下 Python 的 generator、decorator、content manager
- 請說明一下 Python is 和 == 的差別
- 什麼是 GIL（幾乎每間都考 XD）
- 請比較 python 協程與 Go routine 的差別
- 請說明一下 CSRF 以及 Django 的 CSRF token

4. 其他

- 請說明一下什麼情境要用 session 什麼情境用 JSON Web Token（JWT）？
- 請比較 VM、Docker、K8s
- 請說明一下 K8s 的 node、pod 、container 的差異
- 說明一下 CI/CD
- 說明一下 BDD 與 TDD 的差別
- 說明一下 TDD 的好處壞處
- 如何動態擴容？
- 一個需求來你如何規劃？
- 說明一下 AWS lambda
- 說明一下 machine learning 和 deep learning 的差別
- 說明一下 RESTful API
- 比較 TCP/UDP 差異
- 說明一下 OOP
- 說明一下多態
- 說明一下 deadlock
- 說明一下 race condition
- 說明一下 thread 和 process
- Design pattern 用過哪些？
- 說明一下工廠模式、Singleton pattern

---

Scrum/Agile:
Scrum和Agile都是敏捷軟體開發方法論。Scrum是一種迭代和增量式的敏捷方法，用於管理複雜的專案。它強調團隊合作、自組織和迭代開發。Scrum將專案分為短期工作週期，稱為Sprint，通常為1至4週。每個Sprint都包含需求分析、設計、編碼、測試和審查等開發活動。

Agile是一個更廣泛的方法論，強調根據需求和客戶反饋的變化來快速適應和交付軟體。它強調團隊合作、溝通和自組織。Agile方法論包括Scrum、Kanban、Extreme Programming（XP）等。

技術:
DB（Database）代表資料庫，是一個用於存儲和組織資料的系統。資料庫技術有兩大類型：關聯型資料庫（RDBMS）和非關聯型資料庫（NoSQL）。

如何選擇 NoSQL / RDBMS:
選擇使用NoSQL或RDBMS取決於具體的需求和項目特點。一般而言，以下是幾個考慮因素：

1. 數據結構：如果數據的結構較複雜，需要較高的數據一致性和完整性，可以考慮使用RDBMS。如果數據結構較簡單或需要靈活性，可以考慮使用NoSQL。

2. 可擴展性：如果需要處理大量的數據和高流量，NoSQL通常具有更好的可擴展性。

3. 高可用性：NoSQL通常具有內建的高可用性和冗餘機制，能夠提供更好的容錯能力。

4. 高性能：根據項目的性能需求，可以選擇適合的資料庫技術。

inner join和outer join:
inner join是一種關聯操作，它返回兩個表之間匹配的記錄。只有在兩個表中都存在匹配的記錄時，才會返回該記錄。

outer join是一種關聯操作，它返回兩個表之間匹配和不匹配的記錄。它可以

包括左外連接、右外連接和完整外連接。左外連接返回左表中所有的記錄以及與右表匹配的記錄，右外連接返回右表中所有的記錄以及與左表匹配的記錄，完整外連接返回左右表中所有的記錄。

樂觀鎖和悲觀鎖:
樂觀鎖和悲觀鎖是並發控制的兩種策略。

樂觀鎖假設在絕大多數情況下，並發操作之間不會互相干擾。當進行更新操作時，樂觀鎖只在提交時檢查數據是否被其他操作修改，如果有修改則進行回滾或重新操作。

悲觀鎖假設在並發環境中，並發操作之間可能會互相干擾。在執行操作之前，悲觀鎖會先鎖定資源，以防止其他操作對資源進行修改。常見的悲觀鎖包括行級鎖和表級鎖。

關係型資料庫的4大索引:
1. 主索引（Primary Index）：主索引是基於資料表的主鍵（Primary Key）建立的索引。它的作用是快速定位資料表中的記錄。

2. 唯一索引（Unique Index）：唯一索引是對資料表的某個唯一值（Unique Value）建立的索引。它的作用是確保索引的列中的數值唯一，可以用於加速查找和防止重複數據。

3. 聚集索引（Clustered Index）：聚集索引是根據資料表的某個列的值重新組織資料的索引。聚集索引決定了資料的物理存儲順序，一個資料表只能有一個聚集索引。

4. 非聚集索引（Non-clustered Index）：非聚集索引是在資料表上建立的一個獨立的索引結構。它的作用是加速查找操作，並允許以不同的列組合建立索引。

關係型資料庫的4個隔離層級:
1. 讀未提交（Read Uncommitted）：最低隔離層級，允許讀取未被提交的數據。可能會出現髒讀、幻讀、不可

重複讀等問題。

2. 讀已提交（Read Committed）：允許讀取已經提交的數據。避免了髒讀的問題，但仍可能出現幻讀和不可重複讀。

3. 可重複讀（Repeatable Read）：保證同一事務內多次讀取相同數據時，結果一致。避免了髒讀和不可重複讀的問題，但仍可能出現幻讀。

4. 序列化（Serializable）：最高隔離層級，強制事務串行執行，避免了髒讀、不可重複讀和幻讀等問題，但性能較差。

如何避免髒讀:
髒讀是指一個事務讀取到了另一個未提交的事務所修改的數據。要避免髒讀，可以使用較高的隔離層級，如可重複讀或序列化。這樣可以確保讀取操作只能讀取到已經提交的數據，而不會讀取到未提交的數據。

關係型資料庫查找的算法:
關係型資料庫使用多種算法來執行查找操作，包括：

1. 索引查找（Index Lookup）：通過索引快速定位到符合查詢條件的記錄。

2. 順序查找（Sequential Search）：按照順序逐一掃描資料表，直到找到符合查詢條件的記錄。

3. 哈希查找（Hash Search）：通過哈希函數將查詢條件映射到哈希碼，從哈希表中快速查找對應的記錄。

4. 排序查找（Binary Search）：對有序數組或索引樹進行二分查找，快速定位到符合查詢條件的記錄。

Python:

Python mutable object 與 immutable object 的比較並舉例:
在Python中，mutable object（可變對象）是指可以在原地進行修改的對象，而immutable object（不可變對象）是指不能在原地進行修改的對象。

舉例來說，列表（list）是一個mutable object，可以通過添加、刪除或修改元素來改變列表的內容：

```python
my_list = [1, 2, 3]
my_list.append(4)  # 在列表

末尾添加元素
print(my_list)  # 輸出: [1, 2, 3, 4]

my_list[0] = 0  # 修改列表的第一個元素
print(my_list)  # 輸出: [0, 2, 3, 4]
```

而字符串（string）是一個immutable object，不能原地修改字符串的內容，只能創建新的字符串：

```python
my_string = "Hello"
new_string = my_string + " World"  # 創建新的字符串
print(new_string)  # 輸出: "Hello World"
```

Generator、Decorator、Context Manager在Python中的解釋:
- Generator（生成器）是一種特殊的函數，可以生成一個序列的值，並且在每次生成值後保留函數的狀態，以便下次調用時繼續生成值。使用生成器可以節省內存，並且在需要大量迭代的場景中效果顯著。

- Decorator（裝飾器）是一種Python語言的語法糖，用於修改、擴展或包裝其他函數或類的行為。通常使用@符號將裝飾器應用於目標函數或類，以便在執行目標函數或類之前或之後執行額外的操作。

- Context Manager（上下文管理器）是一種用於管理資源的對象，通常用於確保資源的正確分配和釋放。通過實現`__enter__`和`__exit__`方法，可以將一個對象變成上下文管理器，並使用`with`語句來管理資源的生命周期。

Python中的is和==的差異:
- `is`運算符用於比較兩個對象的身份是否相同，即它們是否引用同一個對象。如果兩個對象的身份相同，則返回`True`；否則返回`False`。

- `==`運算符用於比較兩個對象的值是否相等。對於內建類型的對象，例如數字、字符串和列表，它比較它們的值是否相等。對於自定義類型的對象，可以通過重寫`__eq__`方法來定義相等的比較方式。

GIL（全局解釋器鎖）是什麼:
GIL（Global Interpreter Lock）是在CPython中存在的一個機制。CPython是Python的標準解釋器，GIL是用於確保在同一時間只有一個執

行緒能夠執行Python的字節碼指令。

由於GIL的存在，多執行緒的Python程序在多核CPU上無法實現真正的並行執行。儘管Python的多執行緒可以在I/O密集型任務中獲得性能提升，但在計算密集型任務中並不能充分利用多核處理器的優勢。

Python協程與Go routine的差異:
Python協程是一種編寫非阻塞代碼的方式，通過使用`asyncio`庫，可以在單個執行緒中實現並發。Python協程使用`async`和`await`關鍵字來定義和控制非阻塞的操作。

Go routine是Go語言中的一種輕量級執行緒，可以在單個進程中實現並發。Go語言提供了原生的並發支持，可以通過`go`關鍵字啟動一個新的Go routine，並且Go runtime會自動調度這些Go routine的執行。

Python協程和Go routine的差異主要在於實現方式和語言特性上。Python協程依賴於`asyncio`庫，並且在I/O密集型任務中表現良好，但在計算密集型任務中受限於GIL。Go routine是語言層面支持的並發模型，可以更有效地利用多核處理器，適用於各種任務。

CSRF（Cross-Site Request Forgery）是什麼以及Django的CSRF token:
CSRF是一種攻擊方式，攻擊者通過引導受害者在已經認證的網站上執行惡意操作。攻擊者利用受害者的身份，向網站發送未經授權的請求，例如修改用戶資料、發布惡意內容等。

Django是一個流行的Python Web框架，它提供了內置的CSRF保護機制。Django的CSRF保護基於CSRF token（也稱為CSRF令牌）。CSRF token是一個隨機生成的字符串，用於驗證用戶請求的合法性。

在Django中，每個表單都需要包含一個CSRF token，並且在發送請求時，該token會被包含在請求中。當服務器接收到

請求時，會驗證CSRF token的有效性，如果驗證通過，則處理該請求；如果驗證失敗，則拒絕該請求，防止CSRF攻擊。

情境使用session和JSON Web Token（JWT）:
- 使用session：當應用程序需要存儲用戶的狀態信息或敏感信息時，可以使用session。通常，使用session時，服務器會為每個用戶生成一個唯一的session ID，用於識別該用戶。該session ID存儲在用戶的瀏覽器中，並在每次請求時與服務器進行交互。服務器根據session ID來查找相應的session數據，以恢復用戶的狀態。

- 使用JSON Web Token（JWT）：當應用程序需要在分散式環境中進行身份驗證和授權時，可以使用JWT。JWT是一種輕量級的身份驗證和授權標準，基於JSON格式，包含了用戶的身份信息和相關的元數據。JWT由三部分組成：header、payload和signature。用戶在通過身份驗證後，服務器將生成一個JWT並返回給用戶。用戶在後續的請求中，需要攜帶該JWT，並在服務器端進行驗證。

VM（虛擬機）、Docker和K8s的比較:
- VM（虛擬機）：虛擬機技術是通過在物理硬件上模擬多個虛擬環境來實現虛擬化。每個虛擬機都運行著完整的操作系統和應用程序，相互之間相互隔離。虛擬機具有較高的隔離性和安全性，但需要較大的系統資源和啟動時間。

- Docker：Docker是一個開源的容器化平台，它使用輕量級的容器來運行應用程序。Docker容器共享操作系統內核，但是在容器中運行的應用程序與宿主機和其他容器相互隔離。Docker具有快速啟動、低資源消耗和高度可移植性等優點。

- K8s（Kubernetes）：K8s是一

個開源的容器管理平台，用於自動化部署、擴展和管理容器化應用程序。K8s提供了對Docker容器的集群管理功能，包括自動化部署、服務發現、負載均衡和容器伸縮等。K8s具有高可用性、可擴展性和自我修復能力。

K8s的node、pod和container的差異:
- Node（節點）是K8s集群中的一個工作節點，可以是物理機器或虛擬機器。每個Node都運行著K8s代理服務和容器運行時，用於管理和執行容器。

- Pod（莢艙）是K8s中最小的可部署單位，它是一個或多個容器的集合。Pod提供了一個獨立的網絡和存儲環境，這些容器共享這個環境。通常，Pod中的容器是相關的，它們一起工作以完成特定的任務。

- Container（容器）是一個輕量級的獨立運行單位，它包含應用程序及其相依的庫和文件。容器是根據映像（Image）創建的實例，並運行在K8s集群中的節點上。容器具有良好的隔離性，可以快速啟動和停止。

CI/CD是什麼:
CI/CD（Continuous Integration/Continuous Deployment）是一種軟件開發流程和實踐，旨在實現快速、可靠和可重複的軟件交付。CI/CD將持續集成（Continuous Integration）和持續部署（Continuous Deployment）結合在一起。

持續集成是指開發人員將代碼頻繁地集成到共享存儲庫中，並自動進行編譯、測試和代碼檢查等操作，以快速發現和解決問題。

持續部署是指在代碼經過測試並通過一系列自動化檢查後，自動部署到生產環境中。這樣可以實現快速且可靠的軟件交付，減少人工操作和減輕部署風險。

BDD（Behavior-Driven Development）和TDD（Test-Driven Development）的差異:
- BDD強調通過共享語言和

協作來確保軟件的行為符合預期。BDD的測試用例通常以自然語言的形式編寫，並與業務利益相關聯。BDD的重點是通過定義行為和功能來促進團隊間的溝通和對功能的共同理解。

- TDD則是一種開發方法論，要求在編寫功能代碼之前先寫測試代碼。TDD的主要目標是確保代碼的正確性和可測試性。TDD的開發流程通常包括紅色（寫測試不通過）、綠色（寫足夠的代碼讓測試通過）和重構（重構代碼以提高質量）三個階段。

TDD的好處:
- 測試覆蓋率高：TDD要求在開發過程中先寫測試，確保代碼被充分測試覆蓋，減少bug的出現。

- 提高代碼質量：TDD強制開發者思考代碼設計和功能，鼓勵模塊化、低耦合的設計，從而提高代碼質量。

- 減少重構風險：TDD在開發過程中包含重構階段，確保代碼的可讀性和可維護性。

TDD的壞處:
- 開發速度較慢：由於需要先寫測試代碼，再寫功能代碼，因此開發速度相對較慢。

- 需要良好的測試設計能力：TDD要求開發者能夠良好地設計測試用例，涉及到對需求的理解和分析能力。

動態擴容的方法:
- 垂直擴容（Vertical Scaling）：通過增加單個資源的容量來擴展系統，例如增加服務器的CPU、內存等。垂直擴容的好處是簡單直接，但受限於單一資源的物理限制。

- 水平擴容（Horizontal Scaling）：通過增加系統中相同組件的個數來擴展系統，例如增加服務器的數量。水平擴容可以提供更好的可擴展性，但可能需要考慮到資源共享和數據同步等問

題。

- 自動化擴容：通過監測系統的負載狀態和性能指標，自動觸發系統的擴容操作。這可以使用自動化工具和腳本來實現，使系統能夠根據實際需求自動調整資源配置。

在面對需求時的規劃方法:
1. 確定需求的優先級和重要性。
2. 初步估算工作量和時間，確定項目的可行性。
3. 編制項目計劃，包括任務分解、資源分配和時間軸等。
4. 按照計劃執行項目，定期監控進度和資源使用情況。
5. 隨著項目進展，及時調整計劃，根據需求變化進行優化和調整。
6. 定期回顧項目的執行情況，學習經驗教訓，改進工作流程和方法。

AWS Lambda是一種無伺服器計算服務，它使您能夠運行代碼而無需管理伺服器。您只需提供您的代碼，AWS Lambda會處理伺服器的配置和自動擴展，以確保您的代碼僅在需要時運行，從而節省資源和成本。

機器學習（Machine Learning）和深度學習（Deep Learning）的差異:
- 機器學習是一種人工智能（AI）的分支領域，它關注如何使用算法和統計模型使計算機具有學習能力，並根據數據進行預測和決策。機器學習主要通過對數據的學習和模型的訓練，從中提取特徵並進行預測。

- 深度學習是機器學習的一個子集，它基於人工神經網絡（Artificial Neural Network）的理論和方法，以實現對大量數據的高效學習和表徵學習。深度學習通常使用多層神經網絡結構，可以自動學習和提取複雜的特徵表示，並在圖像識別、語音識別和自然語言處

理等領域取得重要的突破。

RESTful API（Representational State Transfer）是一種設計風格和軟件架構，用於構建分佈式系統中的 Web 服務。它遵循一組原則和約束，包括使用統一的資源標識符（Uniform Resource Identifier，URI）作為標識、使用標準的 HTTP 方法（如GET、POST、PUT、DELETE）進行操作、使用狀態碼表示操作結果等。

TCP（Transmission Control Protocol）和UDP（User Datagram Protocol）的差異:
- TCP是一種面向連接的協議，提供可靠的數據傳輸和錯誤檢測機制。它通過確保數據包的順序和完整性，以及檢測和重傳丟失的數據包來確保可靠的傳輸。TCP適用於需要可靠傳輸的應用場景，如文件傳輸、Web瀏覽等。

- UDP是一種無連接的協議，提供非可靠的數據傳輸。它不保證數據包的順序、完整性和可靠性，且不提供重傳機制。UDP具有低延遲和高效率的特點，適用於實時性要求較高的應用場景，如音頻/視頻流傳輸、即時通訊等。

OOP（Object-Oriented Programming）是一種程式設計的方法論，將現實世界中的事物抽象成物件，通過定義物件的屬性和方法，實現封裝、繼承和多態等特性。

多態（Polymorphism）是OOP中的一個概念，它表示對於相同的消息（方法調用），不同的物件可以有不同的行為。多態通過繼承和方法重寫實現，使得代碼可以更靈活、可擴展和可重用。

Deadlock（死結）是多線程或多進程環境中的一種情況，當多個進程或線程互相等待對方釋放資源時，導致所有的進程或線程都無法繼續執行，形成死循環。解決死結的方法包括死結檢測、

死結預防、死結避免和死結解除等。

Race condition（競態條件）是多線程環境中的一種情況，當多個線程同時訪問和操作共享資源時，由於執行順序不確定，可能產生不可預測的結果。解決競態條件的方法包括使用鎖（Lock）、互斥體（Mutex）、條件變量（Condition Variable）等同步機制。

Thread（線程）是在一個進程內執行的一條獨立的執行路徑，它共享進程的資源，但有自己的狀態和執行棧。Process（進程）則是正在運行的程序的實例，它擁有獨立的內存空間和資源。

常見的設計模式包括單例模式（Singleton Pattern）、工廠模式（Factory Pattern）、觀察者模式（Observer Pattern）、策略模式（Strategy Pattern）、裝飾者模式（Decorator Pattern）等。這些設計模式提供了一種結構化和可重用的設計方案，有助於提高程式碼的可讀性、可維護性和擴展性。單例模式用於保證類只有一個實例，工廠模式用於封裝對象的創建過程，觀察者模式用於建立對象之間的一對多依賴關係，策略模式用於將算法封裝成獨立的類並使其可以相互替換，裝飾者模式用於動態地為對象添加功能。