---
# System prepended metadata

title: 資深後端面試試題
tags: [Backend, 技術, 面試]

---

# 資深後端面試試題
一、請舉例在你過去的工作經驗中，覺得面臨過最大的技術挑戰或最令你印象深刻的技術性問題，並分享你最後如何解決他？

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`