ISP – interface segregation principle in SOLID

Interface segregation principle (ISP) – tạm dịch: chả biết dịch sao cho sát nghĩa ??, cái từ segregation dịch ra là tách rời ra. Interface thì khỏi phải giải thích rồi nhỉ 🙂 – anw, let’s move on …

Nguyên tắc này được diễn giải theo nguyên bản tiếng anh theo Uncle Bob
“Client should not be forced to implement an interface that it doesn’t use” – tức là các lớp con (derived classes) không nên hiện thực những phương thức (method) mà nó không cần dùng đến.

Nghe lùng bùng, và khó hiểu, mình lấy lại cái ví dụ mà mình xem ở laracast để minh hoạ trong bài viết này.

Ta có 1 interface WorkerInterface, một class HumanWorker, AndroidWorker. Trong interface WorkerInterface ta có 2 phương thức (work and sleep).
Các bạn có thể thấy ngay là AndroidWorker phải hiện thực phương thức sleep khi implements WorkerInterface – điều này thực tế không bao giờ xảy ra, vì android worker là cỗ máy thì ko ngủ ??

Xét diagram sau:

class diagram 1
class diagram 1

Có thể thấy rằng AndroidWorkerimplements sleep function thì không hợp lý lắm. Tuy nhiên, có thể by pass điều bất hợp lý này bằng cách return null khi implements phương thức này. Nhưng chỉ là giải pháp work-around

Trong terminal bạn chạy: php inversion-principle.php sẽ có output như sau:

php cli 1
php cli 1

Giải pháp:

Để khắc phục ta thử tách riêng 2 functions (sleep, work) trong WorkerInterface thành 2 interfaces (segregation) – với mục đích là AndroidWorker không “bị” phải implements hàm sleep. Khi đó ta có diagram sau:

class diagram 2
class diagram 2

So far seem so good laH ^^ ??. Ta xét thử đoạn code sau:

–> như các bạn thấy đấy, chúng ta lại vi phạm OCP (open closed principle) khi thiết kế như trên. Vậy thì phải làm sao nhỉ, chúng ta thử thêm một hàm (phương thức, method) trung gian beManaged qua một interface trung gian ManagableInterface như diagram sau:

class diagram 3
class diagram 3

Mấu chốt của giải pháp này là: cả 2 class HumanWorkerAndroidWorker đều implements phương thức beManaged của ManagableInterface. Khi override hàm này trong các class con, chúng ta kiểm soát việc gọi hay không gọi các phương thức (override) từ các interfaces khác

Phương án trên,  còn gọi là ISP – Interface Segregation Principle. Hi vọng bài viết này sẽ giúp các bạn có thêm tham khảo về ISP trong SOLID principles

Source code demo: https://github.com/nguyentienlong/isp-in-solid/tree/master

Bài viết liên quan:

  1. http://longka.info/blog/2016/01/24/single-responsibility-trong-solid-principle/ (S)
  2. http://longka.info/blog/2016/04/29/contextual-binding-in-laravel-and-o-in-solid-principles/ (O)
  3. http://longka.info/blog/2015/10/26/a-note-about-solid-principles-demo-in-symfony2/ (SOLID)

References:

  1. Laracast tutorial
  2. https://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
  3. Dependency relation in uml: https://vaughnvernon.co/?page_id=31

 

Một vài lưu ý khi cài đặt php7 (php-fpm) từ source code trên linux (fedora)

Giả sử bạn muốn cài đặt trên fedora, php7, php-fpm với nginx là proxy hứng request đẩy qua cho php xử lý (thông qua php-fpm).

Khi cài đặt từ source code có thể bạn sẽ gặp những vấn đề sau:

  1. Thiếu các thư viện khi chạy lệnh ./congigure
  2. Chỉ định đường dẫn đến thư mục sẽ cài php mà bạn muốn( hữu ích khi bạn muốn cài nhiều phiên bản php trên môi trường làm việc của bạn).
  3. Chỉ định đường dẫn đến file php.ini
  • Thiếu các thư viện khi chạy lệnh ./congigure

Tuỳ theo các tuỳ chọn của bạn, khi chạy lệnh ./configure bạn có thể thiếu những thư viện mà php cần, ví dụ bạn thiếu thư viện liên quan đến utf8 chẳng hạn, hãy dùng yum để tìm

  • Chỉ định đường dẫn đến file php.ini

Khi đó bạn chỉ cần copy file php.ini vào thư mục /etc/php7/php.ini, mọi thay đổi trong file này, sẽ ảnh hưởng đến cấu hình của php trên máy của bạn.

  • Chỉ định đường dẫn sẽ cài php ( hữu ích khi bạn muốn cài nhiều phiên bản php trên môi trường làm việc của bạn).

Lưu ý nữa: khi bạn khởi động php-fpm, mặc định php-fpm sẽ đọc file cấu hình của php-fpm tại /usr/local/etc/php-fpm.conf. Nếu bạn muốn chỉ định đến file cấu hình php-fpm trong thư mục cài đặt php /opt/php7/etc/php-fpm.conf.

 

Đây là script mình lưu trên gíst
https://gist.github.com/nguyentienlong/120af89ab11e5ec48014

Tham khảo:
http://php.net/manual/en/install.pecl.php-config.php
http://php.net/manual/en/install.unix.nginx.php

Single Responsibility trong SOLID Principle

Bài viết này bàn về S trong SOLID principle.

Trong bài viết này http://longka.info/blog/2015/10/26/a-note-about-solid-principles-demo-in-symfony2/ , mình nói sơ qua về ý nghĩa của từng nguyên tắc trong SOLID và demo với symfony2.

S: Single Responsibility  – tức là một class chỉ nên đảm nhận một nhiệm vụ, hoặc một class nếu có một lý do nào đó để thay đổi thì chỉ có một lý do ( A class should have only one reason to change [1])

Để hiểu rõ hơn, mình sẽ phân tích một ví dụ nó vi phạm qui tắc S sờ này, và làm sao để refactor nó đáp ứng qui tắc S (sờ, không phải rờ mó lung tung nhé).

Giả sử ta có một class Student như sau:

Trong ví dụ về class Student ở trên, bản thân class Student không cần phải quan tâm đến việc kết nối cơ sở dữ liệu thế nào, nó chỉ cần quan tâm đến các thông tin liên quan đến Student, những khóa học mà sinh viên đã đăng ký, hoặc đã học ( bảng enrollment ). Một lý do khác nữa, đó là giả sử sau này khi ta muốn thay đổi thông tin liên quan cơ sở dữ liệu (câu truy vấn, hệ quản trị csdl) ta cũng phải chạy vào class này chỉnh sửa.
Do đó chúng ta cần phải re-factor để khớp với qui tắc Sờ (Lờ) như sau:

Soure code on github https://github.com/nguyentienlong/solid-tut/blob/s-principle/src/Database.php#L8

Lúc đó, bên Class Student, bạn không cần phải quan tâm đến thông tin của db, việc kết nối db thế nào, etc… Hàm getCourses trong class student bây giờ sẽ như  thế này: https://github.com/nguyentienlong/solid-tut/blob/s-principle/src/Student.php#L38

Tuy nhiên bản thân class Student cũng không nên quan tâm lắm đến việc sql truy vấn thế nào, với các hệ quản trị cơ sở dữ liệu khác nhau thì câu query lại khác nhau, khi muốn sửa code chúng ta lại fai vào class Student này để sửa, lý do này không liên quan đế trách nhiệm và bổn phận của class Student. Những thứ liên quan đến db hay move sang class Database.

Do đó, chúng ta refactor lại class Database cho phù hợp với nguyên tắc S sờ như sau

Qua 2 lần refactor, chuẩn Sờ S ?

File database.sql https://github.com/nguyentienlong/solid-tut/blob/master/database.sql – mình dùng postgres sql làm demo.

References:
[1] https://en.wikipedia.org/wiki/Single_responsibility_principle

composer namespace và autoload với psr 4

Mục đích bài viết: Bạn muốn sử dụng namespace va` psr4?

namspace là gì: khi lập trình với JAVA hoặc .NET, chúng ta muốn gom những class liên quan đế nhau vào một package hay namespace.

psr4 là gì http://www.php-fig.org/psr/psr-4/ – là chuẩn để autoload các classes từ đường dẫn chứa classes cần load tự động (autoload)

Vậy autoload là gì? Nhiều người trong chúng ta viết chương trình theo phương pháp hướng đối tượng (OOP) và cứ mỗi class lại viết một file cho nó (theo cách mà JAVA hay .NET tổ chức). Với mục đích như thế, thay vì cứ mỗi file chúng ta lại dùng lệnh include hay require bao gồm cả đường dẫn đến tên file.

Chúng ta muốn đơn giản và tiện lợi hơn như sau

okay, nếu chúng ta đã hiểu thế nào là psr-4, namspace, autoloader – vậy làm sao tôi có thể tự tạo một project áp dụng composer namespace và autoload theo psr4 (hoạc có thể psr0)

Giả sử bạn có cấu trúc thư mức như sau, Student.php là class chứa thông tin về một sinh viên, và chúng ta muốn đặt nó trong namespace là  Longka và trỏ nó đến thư mục src/

composer autoloader psr4 folder structure
composer autoloader psr4 folder structure

và trong file index.php bạn muốn sử dụng cú pháp sau

Để làm điều này, đầu tiên tạo composer.json
Bạn có thể tạo file này bằng cách chạy lệnh

Sau đó trả lời các câu hỏi, nó sẽ cho ra composer.json như sau
Sau đó các bạn add autoload va psr-4 hoặc psr-0
vd:

Sau đó chạy lệnh, composer dumpautoload, nó sẽ generate thư mục vendor nếu có thể require, ở đây chúng ta chỉ bàn về  namespace va autoload .
Composer sẽ generate một số filé để hỗ trợ việc load class theo namespace
Sau đó trong file index.php
bạn chỉ cần

sau đó

Tét thử nhé 😉

php index.php
php index.php

Nếu bạn muốn đào sâu hơn về cách mà composer handle autoload bạn có thể tham khảo các files sau:

 

Mở rộng bài viết một xíu: trong trường hợp trong 1 namespace bạn có rất nhiều Class (es). Ở file index.php bạn không muốn cứ mỗi lần new một object lại use một class, trong khi  đó những class này lại cũng thuộc 1 namespace. Trong JAVA thì bạn có thể sử dụng

Trong php thì sao nhỉ: http://stackoverflow.com/questions/7121682/php-how-to-import-all-classes-from-another-namespace

Tại sao nên dùng PSR-4 với composer nhỉ ? ( pear ?? PSR-0 ??)
http://www.php-fig.org/psr/psr-4/meta/

Demo code:
https://github.com/nguyentienlong/composer-tut1
Tham khảo:
http://www.php-fig.org/psr/psr-4/
https://getcomposer.org/apidoc/master/Composer/Autoload/ClassLoader.html
https://getcomposer.org/doc/01-basic-usage.md#autoloading