12/08/2018, 18:26

Tổng quan về Composer - Đơn giản từ sự phức tạp

Trong hai bài viết trước, tôi đã cùng các bạn điểm qua những vấn đề nan giải trong quá trình quản lý thư viện mã nguồn mở PHP cũng như cách mà Composer đã giúp chúng ta đơn giản hóa công việc hơn bao giờ hết. Tôi cảm thấy khó khăn khi đặt ra tiêu đề của bài viết này vì tôi cảm thấy những điều tôi ...

Trong hai bài viết trước, tôi đã cùng các bạn điểm qua những vấn đề nan giải trong quá trình quản lý thư viện mã nguồn mở PHP cũng như cách mà Composer đã giúp chúng ta đơn giản hóa công việc hơn bao giờ hết. Tôi cảm thấy khó khăn khi đặt ra tiêu đề của bài viết này vì tôi cảm thấy những điều tôi chia sẻ dưới đây có thể đơn giản nhưng lại phức tạp, cơ bản nhưng lại nâng cao... Sở dĩ tôi phải nói như vậy là vì để hiểu được cách làm việc của Composer (hay cả Dependency Manager khác), các bạn phải tìm hiểu thêm rất nhiều thứ liên quan khác như version constraints, version control system, respository host, autoload file (với php),... Có vẻ hơi nhiều nhỉ? Tạm bỏ qua những thứ "linh tinh" này, chúng ta bắt đầu tìm hiểu nhé.

Cùng nhìn lại chủ đề của series này, các bạn sẽ thấy rằng tôi đề cập đến một từ khóa. Đó là "Dependency Manager" hay "Dependency Management Tool". Vậy thì "Dependency Manager" thực sự là gì? Tại sao Composer là một "Dependency Manager"?

Trước đây, tôi thường cho rằng hai cụm từ "Package Manager" và "Dependency Manager" có cùng ý nghĩa. Và như lẽ tự nhiên, nhiều lúc tôi dùng chúng khá "tùy tiện". Tôi chỉ thực sự đặt ra câu hỏi cho bản thân khi nghiêm túc đọc được một câu giải thích ngắn gọn trên trang Composer Introduction.

Composer is not a package manager in the same sense as Yum or Apt are...

Tôi tạm dịch là "Composer không phải là một Package Manager tương tự như YUM hoặc APT". Vâng, Composer không phải là một Package Manager mà là một Dependency Manager. Trong đầu tôi tự đặt ra hàng tá các câu hỏi thắc mắc tại sao?, như thế nào?...

Thực tế, tôi tự thấy mình vẫn chưa đọc hay nghiền nghẫm đủ tài liệu để phân biệt hai khái niệm Tiếng Anh này. Cho nên, tôi sẽ chỉ nói ra một vài gạch đầu dòng suy nghĩ chủ quan của mình và rất mong nhận được sự đóng góp thông tin từ tất cả các bạn. Trước hết, hãy cùng tôi làm rõ một số từ "nguyên tố":

  • "Package" hoặc "Software Package" là một tập hợp các tệp với nhiều loại hay chức năng khác nhau. Tập hợp này có thể bao gồm mã nguồn, tệp thực thi, (ví dụ như tệp .exe cho windows), tệp nhị phân, tệp cấu hình, hình ảnh, videos,... Chúng được đóng gói lại thành một nhóm có mối liên hệ chặt chẽ, thường là một phần mềm hoàn chỉnh hay tập hợp mã nguồn dùng cho lập trình. Ví dụ như trình duyệt google chrome, hay trình soạn thảo vscode mà tôi đang dùng chẳng hạn. Một tiện ích mở rộng (extension) của chrome cũng có thể coi là một package.

  • "Dependency" là sự phụ thuộc. Trong phát triển phần mềm, "sự phụ thuộc" nghĩa là một package có thể yêu cầu hệ thống phải cài đặt nhiều packages khác để nó có thể hoạt động được hoặc chính bản thân package đó cũng sẽ được yêu cầu bởi rất nhiều packages khác. Ví dụ, trước đây, khi sử dụng windows, tôi thường cài đặt AppServ mà nó thì yêu cầu phải có một số môi trường như c++ redistributable. Như vậy, c++ redistributable là một dependency của AppServ, c++ redistributable phải được cài đặt thì AppServ mới có thể hoạt động được.

Theo đó, tôi sẽ có khai khái niệm trọng tâm sau:

  • Package Manager là công cụ dùng để cấu hình một hệ thống (thường là hệ điều hành). Nó sẽ giúp ta thiết lập môi trường để chạy hay xây dựng nhiều phần mềm khác nhau. Nó có phạm vi toàn cục và ảnh hưởng đến toàn bộ hệ thống. Ví dụ, tôi sử dụng Ubuntu HĐH 16.04 và cài đặt phần mềm - package A; sau khi cài đặt, phần mềm A có thể được sử dụng toàn cục, thực thi ở bất cứ đâu và bởi bất kì tài khoản người dùng nào.

  • Dependency Manager thì gắn liền với từng phần mềm hay dự án cụ thể. Nó có phạm vi cục bộ, chỉ quản lý packages cho từng dự án riêng lẻ. Theo đó, nó cài đặt những packages cần thiết vào trong một thư mục của dự án chẳng hạn và tất nhiên chỉ sử dụng cho dự án đó mà thôi. Khi chuyển sang dự án khác, chúng phải cài đặt và quản lý những packages hoàn toàn khác.

Mặc dù so sánh là vậy, nhưng với vốn hiểu biết ít ỏi hiện tại, tôi vẫn cảm thật khó khăn để hiểu "đúng" hơn về ngữ nghĩa của Package và Dependency (Manager). Thôi thì hãy đặt chúng vào một hoàn cảnh cụ thể như trong trường hợp này để tạm chấp nhận là chúng khác biệt. Tóm lại, Composer là Dependency Manager đúng như lời giải thích từ trang chủ, nó chỉ mặc định quản lý dependencies cho từng dự án riêng lẻ trên phạm vi cục bộ của dự án đó.

(Tôi sẽ tiếp tục tìm hiểu và phân tích những điều này, hy vọng gặp lại các bạn vào một bài viết khác để làm nó trở lên sáng tỏ hơn)

Nếu các bạn đã đọc bài viết trước trong series của tôi thì chắc hẳn đã cài đặt Composer cho máy tính cá nhân của mình. Còn nếu không, các bạn hãy tự tìm hiểu cách cài đặt trên Internet nhé. Composer chạy đa nền tảng, đặc biệt với 3 loại phổ biến là Windows, Unix, Linux. Trang chủ của Composer đã hướng dẫn khá chi tiết việc cài đặt hoặc các bạn có thể thoải mái tham khảo những bài hướng dẫn khác.

Để sử dụng Composer nhằm mục đích quản lý dependencies cho một dự án, chúng ta phải tạo ra một tệp với tên composer.json trong thư mục gốc của dự án đó. Tệp này được dùng để khai báo những dependencies cần thiết cũng như nhiều thông tin quan trọng khác.

Tên gói và phiên bản (Package Name and Version Constraints)

Nhiệm vụ chính của Composer là quản lý dependencies, do vậy dễ hiểu rằng việc quan trọng nhất chính là khai báo những dependencies mà dự án cần sử dụng trong phần có khóa "require".

{
    "require": {
        "monolog/monolog": "1.0.*"
    }
}

Dễ dàng nhận thấy "monolog/monolog" chính là tên gói (package name), "1.0.*" ràng buộc về phiên bản (version constraints). Cụ thể thì ví dụ trên đây yêu cầu monolog/monolog với phiên bản phù hợp 1.0.0, 1.0.1,... Chúng ta sẽ cùng tìm hiểu từng từ khóa tương tứng.

  • "package name" là tên gói theo đúng nghĩa đen             </div>
            
            <div class=
0