# 資深後端面試試題 一、請舉例在你過去的工作經驗中,覺得面臨過最大的技術挑戰或最令你印象深刻的技術性問題,並分享你最後如何解決他? Ans: 與爬蟲相關的就是在爬漫畫圖片任務的時候,爬到的不是圖片而是一串加密文字 後來在網頁上的相關函式庫堆裡面找到畫圖片相關的解密器 之後實作出解密器並將圖片產出 ---- 二、如果要實作一個黑名單檢查器來檢查一個 URL 是否存在黑名單內,而黑名單的資料量可能高達數百萬筆,請問在不使用外部服務(如:MySQL、Redis)的前提,並可以允許有一定機率內的誤判情況下,你會如何以最低的時間及空間複雜度來實作以下的 BlacklistChecker 來判斷該 URL 是否存在黑名單之內?(使用文字描述即可,不需要寫出完整程式) ```php public function checkUrl(string $url) { $blacklistChecker = new BlacklistChecker(); if (! $blacklistChecker->checkUrl($url)) { throw new BlacklistException('This url is in blacklist.'); } return true; } ``` Ans: 使用布隆過濾器(Bloom Filter) 將網址 Hash 之後轉成 BitMap 後成為 Key 並設值為 1 存進 memcached ---- 三、如下面範例 Topic 和 Comment 兩個 Model 之間為一對多的關聯,listTopicsWithComments 方法會列出依據建立時間倒序排序的 Topic,並列出每個 Topic 底下所有的 Comment,請問以下的程式可能存在什麼問題?如果是你會怎麼修改? 以下程式以 Laravel 框架為基礎 ```php public function listTopicsWithComments(Request $request) { $topics = Topic::latest()->paginate(); return TopicResource::collection($topics); } ``` ```php namespace App\Http\Resources; use Illuminate\Http\Resources\Json\JsonResource; class TopicResource extends JsonResource { public function toArray() { return [ 'id' => $this->resource->id, 'title' => $this->resource->title, 'comments' => $this->resource->comments ]; } } ``` Ans: 當 comment 數過多時會有效能問題 ```php public function listTopicsWithComments(Request $request) { $topics = Topic::with('comments')->latest()->paginate(); return TopicResource::collection($topics); } ``` ---- 四、A、B 兩間不同第三方金流廠商各自提供了交易的 HTTP API,程式中 WalletA 與 WalletB 分別封裝 API 並且共同實作了 WalletContract 介面。如下有一個 transferMoney 的方法來達成將 A 錢包餘額轉帳至 B 錢包的功能,請問以下的程式可能存在什麼問題,如果是你會怎麼修改?(使用文字描述即可,不需要寫出完整程式) ```php interface WalletContract { // 依據交易單號進行存款操作,並回傳操作後餘額 public function deposit(string $transactionNumber, string $userId, float $money): float; // 依據交易單號進行提款操作,並回傳交易後餘額 public function withdraw(string $transactionNumber, string $userId, float $money): float; // 確認特定交易單號的交易是否成功執行 public function checkTransaction(string $transactionNumber): boolean; // 取得特定使用者的當下錢包餘額 public function getBalance(string $userId): float; } ``` ```php // 範例中假設只會 A 錢包單方向轉帳至 B 錢包 public function transferMoney(User $user, float $money) { $walletA = new WalletA(); $walletB = new WalletB(); // 檢查 A 錢包餘額是否足夠 if ($walletA->getBalance($user->id) < $money) { throw new WalletException('Wallet amount is not enough.'); } // 產生唯一的交易單號 uuid $transactionNumber = TransactionNumberGenerator::generate(); // 執行 A, B 錢包的轉帳交易 $walletA->withdraw($transactionNumber, $user->id, $money); $walletB->deposit($transactionNumber, $user->id, $money); return [ 'success' => true; ]; } ``` Ans: $walletA->withdraw 在執行後需檢查交易餘額,不能為負數 ---- ###### tags: `面試` `技術` `Backend`