# 資深後端面試試題
一、請舉例在你過去的工作經驗中,覺得面臨過最大的技術挑戰或最令你印象深刻的技術性問題,並分享你最後如何解決他?
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`