Laravel và giải pháp kiến trúc cho ứng dụng quy mô lớn

Maintaining một ứng dụng quy mô lớn chưa bao giờ là dễ dàng. Chúng ta hãy bắt đầu tìm hiểu thiết kế kiến trúc cho các ứng dụng lớn với Laravel.
Laravel và giải pháp kiến trúc cho ứng dụng quy mô lớn
Laravel và giải pháp kiến trúc cho ứng dụng quy mô lớn

Laravel là một framework PHP phổ biến nhất hiện nay. Cấu trúc thư mục tốt, cách tổ chức tuyệt vời, được định nghĩa rõ ràng và dễ dàng tiếp cận. Làm việc với với kiến trúc mặc định của Laravel là hoàn toàn tốt đẹp với một ứng dụng nhỏ hoặc vừa. Nhưng khi nó là một ứng dụng lớn với hơn 50 Models khác nhau, chúng ta sẽ bắt đầu cảm thấy "lực bất tòng tâm" khi vật lộn với mớ code của chúng ta.

Maintaining cho một ứng dụng quy mô lớn (ở bất kỳ ngôn ngữ nào) đều không phải là trò đùa, đặc biệt là khi nó không được tổ chức đúng đắn. Cấu trúc mặc định của Laravel chắc chắn không hữu ích lắm trong trường hợp này. Bạn nên nhớ rằng một framework được xây dựng nên sẽ phục vụ cho hầu hết người dùng ở mức độ không quá phức tạp. 

Nhưng đầu tiên chúng ta sẽ "mổ xẻ" Laravel mặc định và những gì sẽ xảy ra khi áp dụng cho ứng dụng quy mô lớn.

Cấu trúc mặc định của Laravel tựa như thế này:

|- app/
   |- Console/
      |- Commands/
   |- Events/
   |- Exceptions/
   |- Http/
      |- Controllers/
      |- Middleware/
   |- Jobs/
   |- Listeners/
   |- Providers/
   |- User.php
|- database/
   |- factories/
   |- migrations/
   |- seeders
|- config/
|- routes/
|- resources/
   |- assets/
   |- lang/
   |- views/

Khá khô thoáng, sạch sẽ phải không nào? 

Nhưng khi chúng ta làm việc với các ứng dụng lớn, chúng ta thường áp dụng một số design patterns như TransformerRepository,... và thư mục của chúng ta sẽ trông như thế này:

|- app/
    |- Console/
        |- Commands/
    |- Criteria
    |- Events/
    |- Exceptions/
    |- Http/
        |- Controllers/
            |- Middleware/
    |- Jobs/
    |- Listeners/
    |- Mails
    |- Models/
    |- Presenters/
    |- Providers/
    |- Repositories/
    |- Services/
    |- Transformers/
    |- Validators/
    |- Support
|- database/
|- factories/
|- migrations/
|- seeders
|- config/
|- routes/
|- resources/
|- assets/
|- lang/
|- views/

Đây vẫn là một kiến trúc tốt. Chúng ta hãy bắt đầu nhìn vào thư mục Models.

|- app/
    |- Models/
        |- User.php
        |- Role.php
        |- Permission.php
        |- Merchant.php
        |- Store.php
        |- Product.php
        |- ProductAttribute.php
        |- ProductOption.php
        |- Category.php
        |- Tag.php
        |- Client.php
        |- Delivery.php
        |- Invoice.php
        |- Wallet.php
        |- Payment.php
        |- Report.php
        |- Comment.php
        |- Contact.php
        |- Page.php
        |- StaticBlock.php
        |- CustomField.php
        |- CustomFieldItem.php
        |- Media.php
        |- MediaConfig.php

Không tệ. Chúng ta cũng sẽ có thêm các Services để xử lí các Business Logic. Chúng ta còn có thêm RepositoriesTransformersValidators,... với số lượng tập tin tương tự hoặc hơn nhiều so với Models. Mỗi lần làm việc với một entity nào đó, bạn sẽ cần mở file tương ứng lên. Với nhiều người, điều đó khá mệt mỏi, nhưng đa số thì cảm thấy bình thường.

Vấn đề không nằm ở việc nhảy qua nhảy lại giữa các thư mục khác nhau, mà là maintaining và liên lạc giữa các Services với nhau.

Chúng ta cùng phân tích code base và tổng hợp lại những gì chúng ta cảm thấy:

  • Đây là một ứng dụng nguyên khối
  • Hơi gây khó khăn cho các developer khi làm việc với chúng
  • Khó khăn khi mở rộng

May mắn là chúng ta đã có một giải pháp - HMVC. Chia các thành phần của ứng dụng thành từng phần nhỏ hơn, nơi mà bên trong chúng gói gọn cấu trúc giống như một ứng dụng Laravel mặc định của bạn.

|- platform/
    |- users
        |- config/
        |- helpers/
        |- resources/
        |- routes/
        |- src/
            |- Models/
                |- User.php
                |- Role.php
                |- Permission.php
            |- Http
                |- Controllers/
                |- Requests/
                |- ViewComposers
            |- Providers/
            |- Services/
            |- Support/
        composer.json
    |- customers
        |- config/
        |- helpers/
        |- resources/
        |- routes/
        |- src/
            |- Models/
                |- Merchant.php
                |- Client.php
                |- Delivery.php
            |- Http
                |- Controllers/
                |- Requests/
                |- ViewComposers
            |- Providers/
            |- Services/
            |- Support/
        composer.json
    |- catalog
        |- config/
        |- helpers/
        |- resources/
        |- routes/
        |- src/
            |- Models/
                |- Store.php
                |- Product.php
                |- ProductAttribute.php
                |- ProductOption.php
                |- Category.php
                |- Tag.php
            |- Http
                |- Controllers/
                |- Requests/
                |- ViewComposers
            |- Providers/
            |- Services/
            |- Support/
        composer.json
    |- payments
        |- config/
        |- helpers/
        |- resources/
        |- routes/
        |- src/
            |- Models/
                |- Invoice.php
                |- Wallet.php
                |- Payment.php
                |- Report.php
            |- Http
                |- Controllers/
                |- Requests/
                |- ViewComposers
            |- Providers/
            |- Services/
            |- Support/
        composer.json
    ...

Thiết kế này có các ưu điểm:

  • Chia ứng dụng thành các phần nhỏ hơn, dễ dàng hơn trong quá trình maintaining
  • Mỗi modules đảm nhiệm từng nhiệm vụ cụ thể, code trở nên sạch sẽ và dễ hiểu hơn
  • Các modules được phân tách rõ ràng và kết nối thông qua composer. Các modules độc lập này có thể dễ dàng chia sẻ cho các dự án khác nhau khi cần thiết. 

Nhưng bên cạnh đó cũng sẽ có những nhược điểm như:

  • Bạn phải suy nghĩ nhiều hơn về việc giữ độc lập và tránh phụ thuộc lẫn nhau giữa các modules.
  • Không thích hợp cho người mới bắt đầu
  • Túm lại là nhiều folders hơn =]]~

Trong bài viết kế tiếp, mình sẽ hướng dẫn bạn bắt đầu xây dựng một ứng dụng HMVC với Laravel, và tận dụng sức mạnh của Composer khi quản lí modules.

Comments

Bài viết nổi bật

Dạo gần đây đi đâu cũng nghe nói về microservices, người người nhà nhà rục rịch chuyển dịch hệ thống sang microservices. Trước khi đưa ra sự so sánh, mình sẽ khái quát một chút về Monolith Application và MicroServices một chút cho các bạn chưa biết nắm rõ hơn nhé.
PHP là ngôn ngữ được sử dụng rộng rãi nhất trên thế giới trong lập trình web. Nó cũng bị ghét nhất. Nhưng tại sao nhiều developer lại ghét nó đến vậy? Hôm nay chúng ta hãy cùng tìm hiểu lý do xem chúng có thuyết phục không nhé ^_^
Lúc trước mình hay sử dụng cách này trên laptop phụ của mình, giờ mua license luôn rồi. Hôm nay mình xin chia sẻ cho bạn nào cần nhé.
JWT Tokens là một cách thức lưu trữ thông tin xác thực hiệu quả, nhưng làm cách nào để chúng ta có thể giúp chúng an toàn hơn? Có 2 cách thường dùng để lưu trữ JWT Tokens là LocalStorage và Cookies. Bây giờ chúng ta sẽ bắt đầu "mổ xẻ" các ưu - nhược điểm của mỗi loại nhé.
Có khá nhiều bạn đã yêu cầu mình một bài viết về Repository Design Pattern. Vậy mục đích của nó là gì? Nó có thực sự cần thiết cho ứng dụng của bạn hay không? Những điểm mạnh, điểm yếu của nó là gì? Chúng ta cùng đi sâu tìm hiểu qua bài viết này nhé.

Mục lục

Related posts

Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Phân trang - một thành phần không thể thiếu trong các ứng dụng có lượng dữ liệu lớn. Tuy nhiên, bạn hiểu được bao nhiêu về nó?
Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
Dạo gần đây đi đâu cũng nghe nói về microservices, người người nhà nhà rục rịch chuyển dịch hệ thống sang microservices. Trước khi đưa ra sự so sánh, mình sẽ khái quát một chút về Monolith Application và MicroServices một chút cho các bạn chưa biết nắm rõ hơn nhé.
Cách bỏ qua câu lệnh --set-upstream quen thuộc cho các con lười
Mình sẽ giới thiệu 2 cách để xóa một property trong Javascript Object. Một cách sử dụng mutable - toán tử delete, một cách còn lại là immutable - tính năng Object Restructuring.

Tin mới nhất

Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Trong phần này, chúng ta sẽ tìm hiểu một số khái niệm cơ bản nhất về AWS là gì và một số lợi ích khi sử dụng AWS.
Trở thành một software developer hiệu suất cao không phải là điều dễ dàng. Điều này đòi hỏi bạn phải có kỹ năng và kiến thức về lập trình, cũng như cách tiếp cận và giải quyết các vấn đề phức tạp. Tuy nhiên, nếu bạn có chút kiên nhẫn và sự nỗ lực, bạn hoàn toàn có thể trở thành một developer tài năng và thành công.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.
Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.
Thông tin được định nghĩa dưới dạng dữ liệu, kiến thức về thông tin, và trí tuệ về tri thức.
Phân trang - một thành phần không thể thiếu trong các ứng dụng có lượng dữ liệu lớn. Tuy nhiên, bạn hiểu được bao nhiêu về nó?
Javascript là một thành phần không thể thiếu đối với frontend developers. Tuy nhiên, ngay từ lúc ra đời, nó đã tồn tại khá nhiều vấn đề cần khắc phục. Đó là lý do tại sao từ 2015 (ES6) tới 2021 (ES12) ra đời nhằm giúp Javascript trở nên tốt hơn.
Dạo này mình làm việc với mấy bạn trên github, thấy hay xài mấy từ viết tắt mà mình không hiểu lắm. Thôi thì tổng hợp lại một list các từ viết tắt hay dùng trong github luôn cho ai cần :D
Triển khai Saga Pattern trong microservices với NodeJS và Choreography-Based Saga
Mô hình Saga đưa ra một giải pháp có cấu trúc để giải quyết thách thức này. Nó cung cấp một phương pháp có hệ thống để quản lý transaction qua nhiều microservices. Điều này giải quyết những phức tạp của các transaction phân tán và hoàn toàn tương thích với các nguyên tắc của kiến trúc microservices, được đặc trưng bởi sự kết nối lỏng lẻo và khả năng triển khai độc lập của các service.
Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.
Một trong những câu hỏi được đặt thường xuyên nhất về TypeScript là liệu chúng ta nên sử dụng interface hay type. Câu trả lời cho câu hỏi này, giống như nhiều câu hỏi lập trình khác, là nó phụ thuộc vào tình hình cụ thể. Trong một số trường hợp, một cái có lợi thế rõ rệt hơn cái kia, nhưng trong nhiều trường hợp, chúng có thể thay thế cho nhau.
Đây là các types cơ bản nhưng cũng phổ biến nhất trong Typescript. Một số types khác phức tạp hơn cũng được xây dựng dựa trên những types cơ bản này.