iT邦幫忙

2024 iThome 鐵人賽

DAY 24
0
佛心分享-IT 人自學之術

後端小白自學 Laravel系列 第 24

第 24 天:項目重構與優化

  • 分享至 

  • xImage
  •  

代碼重構和性能優化


代碼重構
一開始練習幾乎都是寫在 controller,這樣會造成 controller 很大一包,如果把驗證、用戶創建、郵件發送的邏輯提取到單獨的方法中,可以提高代碼的可讀性和可維護性。

當然對於第 23 天:代碼質量與測試提到的測試相對會分工較細,比較能區分 FeatureUnit 兩類。

// 原始練習的寫法
public function register(Request $request)
{
    // 驗證輸入
    $validated = $request->validate([
        'name' => 'required|max:255',
        'email' => 'required|email|unique:users',
        'password' => 'required|min:6|confirmed',
    ]);

    // 創建新用戶
    $user = new User();
    $user->name = $validated['name'];
    $user->email = $validated['email'];
    $user->password = bcrypt($validated['password']);
    $user->save();

    // 發送確認郵件
    Mail::to($user->email)->send(new WelcomeMail($user));

    // 返回成功響應
    return response()->json(['message' => 'User registered successfully!'], 201);
}
// 依照 clean code 原則各司其職
public function register(Request $request)
{
    $validated = $this->validateUser($request);

    $user = $this->createUser($validated);
    $this->sendWelcomeEmail($user);

    return response()->json(['message' => 'User registered successfully!'], 201);
}

private function validateUser(Request $request)
{
    return $request->validate([
        'name' => 'required|max:255',
        'email' => 'required|email|unique:users',
        'password' => 'required|min:6|confirmed',
    ]);
}

private function createUser(array $validated)
{
    $user = new User();
    $user->name = $validated['name'];
    $user->email = $validated['email'];
    $user->password = bcrypt($validated['password']);
    $user->save();
    return $user;
}

private function sendWelcomeEmail(User $user)
{
    Mail::to($user->email)->send(new WelcomeMail($user));
}

甚至如果可以,也依照以下架構流程把方法歸類!
架構分類

性能優化
一直以為後端就只要開出 api 就好,其實還講求回傳資料給前端的速度,依照使用者體驗和轉換率 google 提出載入速度若是 1~3 秒以內,直接關閉視窗的可能性大約增加 32%,但只要慢到 5 秒,關閉的可能性就會增加到 90%,所以後端也很講求速度。

我能想到的方法是快取還有從資料庫查詢速度加快!

  1. 數據庫查詢優化
    使用索引來加速查詢 -> 這很常聽前輩提到加索引可以加快速度,但實際上我還沒實做過!
    避免 N+1 查詢問題,使用 Eloquent 的預加載功能(with) -> 文件:模型關聯 - 預加載

    預加載前:每當訪問 comments 屬性時,都會進行額外的查詢,可能導致性能問題(N+1 查詢問題)。
    預加載後:在主查詢時一次性獲取所有相關的評論,減少了查詢數量,提高了效率。

    // 原始練習的寫法
    public function showPosts()
    {
        $posts = Post::all();                        // 獲取所有文章
        foreach ($posts as $post) {
            $post->comments = $post->comments;       // 獲取每篇文章的評論
        }
        return view('posts.index', ['posts' => $posts]);
    }
    
    public function showPosts()
    {
        $posts = Post::with('comments')->get();      // 預加載評論
        return view('posts.index', ['posts' => $posts]);
    }
    
  2. 快取(Caching)

    回顧:第 17 天:緩存 Cache

    使用 Laravel 的快取系統來儲存計算結果或常用資料。

    // 使用快取
    Cache::put('key', 'value', $minutes);
    $value = Cache::get('key');
    

使用 Laravel 的依賴注入和設計模式


依賴注入
通過構造函數注入依賴,讓 Laravel 的服務容器管理這些依賴,使得代碼更容易測試和維護。

public function show()
{
    $postRepository = new PostRepository(); // 直接實例化
    $posts = $postRepository->getAll();
    return view('posts.index', ['posts' => $posts]);
}
public function __construct(PostRepositoryInterface $postRepository)
{
    $this->postRepository = $postRepository;
}

public function show()
{
    $posts = $this->postRepository->getAll();
    return view('posts.index', ['posts' => $posts]);
}

工廠模式
通過工廠類來創建對象,這樣可以更容易地擴展和管理不同的通知類型,而不需要在每個地方都寫判斷邏輯。

例如,建立一個通知系統:

  1. 定義通知類別

    // EmailNotification.php
    class EmailNotification
    {
        public function send($data)
        {
            // 實現發送郵件的邏輯
            echo "發送郵件通知: " . $data;
        }
    }
    
    // SmsNotification.php
    class SmsNotification
    {
        public function send($data)
        {
            // 實現發送短信的邏輯
            echo "發送短信通知: " . $data;
        }
    }
    
  2. 定義通知工廠

    文件:The InvalidArgumentException class -> 如果出現例外,這個 class 會拋出異常。

    app/Factories 目錄下建立工廠

    // NotificationFactory.php
    class NotificationFactory
    {
        public static function create($type)
        {
            if ($type == 'email') {
                return new EmailNotification();
            } elseif ($type == 'sms') {
                return new SmsNotification();
            }
    
            throw new InvalidArgumentException("未知的類型: $type");
        }
    }
    
  3. service 建立商業邏輯
    下指令 mkdir app/Services 在 app 創建 Services 資料夾,並且在裡面新增一個 NotificationService.php 寫發送通知的商業邏輯

    // NotificationService.php
    class NotificationService
    {
        public function sendNotification($type, $data)
        {
            $notification = NotificationFactory::create($type);
            $notification->send($data);
        }
    }
    
  4. 建立 controller
    建立 NotificationController.php 並且在這裡調用 NotificationService 來發送通知

    // NotificationController.php
    namespace App\Http\Controllers;
    
    use App\Services\NotificationService;
    
    class NotificationController extends Controller
    {
        protected $notificationService;
    
        public function __construct(NotificationService $notificationService)
        {
            $this->notificationService = $notificationService;
        }
    
        public function sendEmail()
        {
            // 發送郵件通知
            $this->notificationService->sendNotification('email', '這是一封測試郵件!');
        }
    
        public function sendSms()
        {
            // 發送短信通知
            $this->notificationService->sendNotification('sms', '這是一條測試短信!');
        }
    }
    

上一篇
第 23 天:代碼質量與測試
下一篇
第 25 天:數據存儲與處理 Session
系列文
後端小白自學 Laravel30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
kuku
iT邦新手 4 級 ‧ 2024-09-29 21:25:12

數據庫查詢優化以外,最近實戰過程遇到需要把資料一筆一筆存入模型中,通常都會直接用 create() 的方法

$data->each(function (User $user) {
  User::query()->create($user);
}};

但是這樣就需要一直跟資料庫重新連線,如果有模型間有關聯更會吃效能,所以 laravel 有 creatMany 的批量新增的方法可以使用,減少資料庫連線!

🔔 creatMany 需要的資料格式是 [['aaa' => ...], ['bbb' => ...]]

kuku iT邦新手 4 級 ‧ 2024-09-29 21:27:27 檢舉

我要留言

立即登入留言