thảo luận Cuối cùng thì áp dụng 4 tính chất OOP vào code base như thế nào nhỉ?

Viết lại chỉ là vd để thể hiện thím hiểu rõ server ntn thôi.
Rồi liên quan gì OOP? Ý là các a viết OOP như C#, Java thì sẽ không có khả năng để tự viết server, trình kém hơn mấy anh ko dùng OOP?

Quay lại vấn đề unit test, bản chất của nó là gì? Làm thế nào để viết unit test 1 cách đơn giản đỡ tốn cơm nhất? Có nhất định phải xài mock với dependency injection?
Ko xài mock với dependency injection thì xài cái gì để ko bị dependency?

Khi tôi xác định sẽ viết unit test thì sẽ cân nhắc thiết kế chương trình sao cho việc viết test là đơn giản nhất, thuần oop sẽ bị loại đầu tiên do một số tính chất khiến việc quản lý state và dependencies trở nên chồng chéo phức tạp. Đi giải bài toán theo đúng bản chất của vấn đề thì mọi thứ sẽ trở nên đơn giản.

Thật sự ko hiểu đoạn này, vì state và dependencies là những cái cơ bản của BẤT KỲ PHẦN MỀM NÀO CŨNG CÓ cho dù có lập trình kiểu nào đi nữa. Bây giờ business logic 1 chổ, code access database 1 chổ, muốn unit test business logic mà ko mock thằng database thì làm sao, thiết kế thế nào? :angry:
 
Last edited:
Thật sự ko hiểu đoạn này, vì state và dependencies là những cái cơ bản của BẤT KỲ PHẦN MỀM NÀO CŨNG CÓ cho dù có lập trình kiểu nào đi nữa. Bây giờ business logic 1 chổ, code access database 1 chổ, muốn unit test business logic mà ko mock thằng database thì làm sao, thiết kế thế nào? :angry:
Ví dụ của bác chỉ cần input là dữ liệu từ database như vậy thì chỉ có 1 dependency, hoàn toàn ko có vấn đề về state, vậy thì đơn giản bác rảnh thì viết mock, ko thì fake cũng được.

Vấn đề ở đây là khi bác code = thuần oop thì coi chừng ko chỉ là 1 dependency đơn giản như vậy, mà còn gặp rắc rối về state + 1 số dependency do các tính chất của oop. Cho nên hàm test có thể sẽ trở nên phức tạp x2, x3 thậm chí x10 so với 1 hàm test đơn giản chỉ có 1 depenency từ database.
 
Viết lại chỉ là vd để thể hiện thím hiểu rõ server ntn thôi.

Quay lại vấn đề unit test, bản chất của nó là gì? Làm thế nào để viết unit test 1 cách đơn giản đỡ tốn cơm nhất? Có nhất định phải xài mock với dependency injection?

Khi tôi xác định sẽ viết unit test thì sẽ cân nhắc thiết kế chương trình sao cho việc viết test là đơn giản nhất, thuần oop sẽ bị loại đầu tiên do một số tính chất khiến việc quản lý state và dependencies trở nên chồng chéo phức tạp. Đi giải bài toán theo đúng bản chất của vấn đề thì mọi thứ sẽ trở nên đơn giản.

Thím nói cao siêu quá tôi chả hiểu gì hết, nên cũng ko tranh luận thêm nữa. Kinh nghiệm cá nhân của tôi thì công ty nào cũng yêu cầu viết test hết, những project chưa test đủ 80% coverage đa phần đều như c*t.

Sent from Samsung SM-G973F using vozFApp
 
Ví dụ của bác chỉ cần input là dữ liệu từ database như vậy thì chỉ có 1 dependency, hoàn toàn ko có vấn đề về state, vậy thì đơn giản bác rảnh thì viết mock, ko thì fake cũng được.

Vấn đề ở đây là khi bác code = thuần oop thì coi chừng ko chỉ là 1 dependency đơn giản như vậy, mà còn gặp rắc rối về state + 1 số dependency do các tính chất của oop. Cho nên hàm test có thể sẽ trở nên phức tạp x2, x3 thậm chí x10 so với 1 hàm test đơn giản chỉ có 1 depenency từ database.

1 dependency là database, viết unit test mà ko mock, ko inject dependency thì làm thế nào? Input vào hay Fake chính là DI với mock rồi còn gì? Vì bác nói ko cần mock ko cần DI nên tôi mới hỏi.

Còn vụ code thuần OOP mà hàm test phức tạp x2, x3, x10 là sao tôi ko hiểu. OOP giúp test nó đơn giản hơn chứ sao bác lại nói ngược lại. Cho ví dụ cụ thể dc ko? :angry:
 
Thím nói cao siêu quá tôi chả hiểu gì hết, nên cũng ko tranh luận thêm nữa. Kinh nghiệm cá nhân của tôi thì công ty nào cũng yêu cầu viết test hết, những project chưa test đủ 80% coverage đa phần đều như c*t.

Sent from Samsung SM-G973F using vozFApp
Viết unit test nhiều cũng chưa chắc là hay đâu, mình biết nhiều cty đầu tư setup môi trường test full ứng dụng thay vì đặt nặng unit test, bao gồm gửi fake message, fake ssl, delay 5-10s, xài mạng 3g ko ổn định, ..v..v.. đủ loại môi trường khắc nghiệt
 
1 dependency là database, viết unit test mà ko mock, ko inject dependency thì làm thế nào? Input vào hay Fake chính là DI với mock rồi còn gì? Vì bác nói ko cần mock ko cần DI nên tôi mới hỏi.

Còn vụ code thuần OOP mà hàm test phức tạp x2, x3, x10 là sao tôi ko hiểu. OOP giúp test nó đơn giản hơn chứ sao bác lại nói ngược lại. Cho ví dụ cụ thể dc ko? :angry:
thuần oop là bác sẽ sử dụng nhiều tính chất như abstraction, đóng gói, kế thừa. mấy tính chất này chỉ làm state với dependency thêm phức tạp thôi. Mà state + dependency là mấu chốt để viết test đơn giản
 
thuần oop là bác sẽ sử dụng nhiều tính chất như abstraction, đóng gói, kế thừa. mấy tính chất này chỉ làm state với dependency thêm phức tạp thôi. Mà state + dependency là mấu chốt để viết test đơn giản

Bác vẫn chưa trả lời câu hỏi của tôi:
1. Viết unit test mà ko mock, ko inject dependency thì làm thế nào? Input vào hay fake chính là dependency injection và mock rồi còn gì?
2. Thuần OOP làm phức tạp thêm thôi là phức tạp thế nào, ví dụ cụ thể?
 
Cái trừu tượng là cái mà mọi phần mền hướng đến ấy, đừng có hiểu lầm cái tính abstraction với cái keywork abstract class nhá :LOL:.
Mình phải log in vào để like cho bạn. Mình làm phần mềm đã nhiều năm rồi, phỏng vấn rất nhiều candidate, thậm chí có người 5-7 năm kinh nghiệm apply vào vị trí senior developer vẫn nhầm lẫn abstraction với abstract class. Thật sự rất hiếm thấy người nào nói được câu này.
 
OOP là một cách tư duy, 4 cái kia chỉ là kết quả sau khi áp dụng cách tư duy và rút ra chứ không phải người ta gạch ra 4 cái đầu dòng đó rồi gọi là OOP.

Vì nó là cách tư duy, với mục đích cao nhất ko vượt ra ngoài kết quả của việc viết code, là làm sao tạo đc một sp chạy đúng, chạy nhanh, dễ maintenance, nên đầu tiên để học OOP là làm sao code được cho nó chạy, sau đó là bố trí code sao cho dễ đọc, tiếp đến là dễ mở rộng, cuối cùng là hiệu năng.

Cứ làm từng bước như vậy, nhiều lần, thật nhiều lần, tự nhiên sẽ hiểu 4 cái gạch đầu dòng.

P/s: Ngôn ngữ OOP cung cấp nhiều công cụ hơn để giúp cài đặt tư duy OOP chứ ko phải nó định nghĩa OOP.


via theNEXTvoz for iPhone
 
Last edited:
Thím có viết unit test ko? Unit test nó sẽ chạy khác với code thực tế đúng không? Trong unit test thím cần mock/stub một số thứ để test tất cả scenario đúng không? Cái đó chính là trừu tượng đấy.

Sent from Samsung SM-G973F using vozFApp
Oà thì ra là vậy :( OOP trên mạng lý thuyết quá
 
đương nhiên ko có cái gì là hoàn mỹ được cái này mất cái kia, phải xem xét và đánh giá thôi, vì vậy oop ở trình thiết kế hệ thống nó sẽ khác với oop ở trình dev

muốn hiểu rõ oop như thế nào thì phải nếm trải nổi đau của những người ko dùng oop mắc phải,
anh cứ làm 1 dự án ko cần nghĩ đến việc dùng oop đi, xong đến lúc vấn đề nảy sinh như chuyện fix bug, tích hợp tính năng mới, thay thế code cũ bằng code mới, mở rộng tính năng, sửa đổi tính năng, ràng buộc trong kiến trúc code ... lúc đó đảm bảo anh sẽ tự động vận dụng kiến thức về oop vào để giải quyết vấn đề, còn nếu anh ko cần vận dụng vào thì chứng tỏ project đó ko cần dùng oop nên ko cần thiết

mấy cuốn sách clear code, design pattern nó được đúc kết ra từ những kinh nghiệm của người đi trước họ vấp phải những vẫn đề đó rồi tổng quá lại thôi, theo hay ko theo tùy bản thân, tôi đảm bảo cho dù có đọc trăm cuốn sách đi nữa mà anh ko va chạm trực tiếp với vấn đề, thì mọi lời nói cũng người khác anh sẽ ko để lọt tai đâu, nếm trải sai lầm trả giá cho sai lầm mới nhớ lâu đc

có thể lập trình ngày nay nó tiến bộ hơn như các thớt trên chia sẽ, là nó sẽ tách ra làm rất nhiều microservice, nên có thể mỗi microservice này nó sẽ ko quá phức tạp đến nổi phải thiết kế 1 kiến trúc như mono
 
Vầy nhé, giả sử 1 công ty có 3 loại nhân viên fresher, mediator và senior. Fresher bắt buộc phải có 1 senior kèm và 1 senior có thể mentor nhiều fresher. Mediator thì không liên quan ai cả.

Nếu ông tạo 1 class duy nhất là EmployeeRole và dùng chung cho tất cả nhân viên thì không đảm bảo tính bao đóng, vì Mediator có thể truy cập vào các thuộc tính mentor => phải tạo 3 class riêng biệt cho từng role, mỗi class sẽ bao đóng 1 số property nhất định.

Tính đa hình là cuối tháng khi ông tính lương nhân viên, Senior sẽ nhận được thêm phụ cấp ứng với số lượng fresher mình mentor => cùng là hàm TinhLuong() của nhân viên thôi nhưng business flow sẽ khác nhau cho từng role.

Trừu tượng với kế thừa nó gắn liền nhau, khỏi ví dụ nha.

Sent from Samsung SM-G973F using vozFApp
1. đảm bảo tính bao đóng để làm gì thím
 
Cái trừu tượng là cái mà lúc ông dùng để đăng kí service đó, đại loại là các module ko đc phụ thuộc chặt vào nhau mà phải thông qua 1 lớp trừu tượng, phải làm cho nó lỏng lẻo ra để dễ tháo lắp sau này ví dụ ông muốn kết nối tới 1 cái db, hôm nay thằng xếp vui nó bảo kết nối tới mysql, ngày mai nó buồn nó lại bảo kết nối đến sqlsv, lúc này t sẽ tạo ra 1 cái hợp đồng,(là lớp trừu tượng, chỉ chứa khai báo ko thân hàm, mớ code của ông sẽ làm việc với thằng này chứ ko làm việc với 2 thằng db kia, lúc nào cần thằng db nào thì sẽ do ông quyết định thông qua lớp trừu tượng , khuya bàn phím điện thoại type đc vậy thôi :rolleyes:

Gửi từ Việt Nam bằng vozFApp
ví dụ cụ thể 1 đoạn code được không thím.
nếu chuyển từ mysql sang sqlsv thì tính trừu tượng có lợi gì trong việc code?
chuyển thì em sửa code thôi. trừu tượng chi cho mệt
 
Kế thừa thì properties của lớp cha nó là cuả thằng con rồi, trừ khi anh khai báo private. Còn overriding là khái niệm hoàn toàn khác, nó là chỉnh sửa lại method được kế thừa từ thằng cha. Anh ko cần overrding anh vẫn modify properties được kế thừa từ thằng cha dc mà.
cho ví dụ đc ko thím.
Nếu overriding rồi, giống viết lại hàm. sao ko viết hàm mới cho rồi, kế thừa làm gì
 
cho ví dụ đc ko thím.
Nếu overriding rồi, giống viết lại hàm. sao ko viết hàm mới cho rồi, kế thừa làm gì

Viết hàm mới thì sẽ làm thay đổi interface, nghĩa là phải sửa code ở consumer, ví dụ có 10 chổ đang sử dụng object EmailService và hàm Send như này emailService.Send()

Bây giờ muốn mổi email send ra phải lưu vào database thì ko lẽ viết hàm mới rồi chạy đi sửa 10 chổ?

Cách thường làm là tạo một class mới kế thừa từ EmailService. Ví dụ DatabaseEmailService rồi override hàm Send() để lưu email vào database. Lúc override thì có thể gọi lại hàm Send() của base class, chỉ cần viết thêm đoạn lưu database thôi.

via theNEXTvoz for iPhone
 
cho ví dụ đc ko thím.
Nếu overriding rồi, giống viết lại hàm. sao ko viết hàm mới cho rồi, kế thừa làm gì
Honda thiết kế ra chiếc xe máy 2 bánh, goi là class HaiBanh, có cái hàm BopKen() { Keu BimBim }.
Sau đó nó ra nhiều dòng xe khác nhau, một chiếc gọi là Vision, nên có class Vision: kế thừa HaiBanh, do đó khi BopKen() nó sẽ kêu BimBim. Một chiếc khác gọi là SH, có class SH: kế thừa HaiBanh, nhưng muốn bán giá cao hơn nên cho lúc BopKen kêu sang hơn: bẹp bẹp, lúc này nó sẽ override thằng cha nó, override BopKen() { Keu BẹpBep }
 
oop hay fp thì cũng là thực thi function thôi , nhưng oop nó đòi hỏi anh phải tạo tất cả các object dây mơ rễ má với cái thằng object cha chứa cái function đó vì vậy nó cần cái DI để quá trình tạo các Object đó ko bị cản trở ,còn fp thì input transform ra output thôi dependency nó nằm trong input cả rồi cái nào cần thì khởi tạo rồi truyền vô thôi ko dư thừa như oop tóm lại fp ko quan tâm nhiều DI vì nó thực thi cái đó 1 cách tự nhiên rồi.
Vd như muốn test xem quá trình từ chuối sang cứt oop thì phải tạo con khỉ tạo đủ tay chân mũi miệng cho nó thiết kế ngu ngu có khi phải tạo cả khu rừng nữa cơ , cho nó ăn chuối rồi đợi nó tiêu hóa ra cứt, còn fp thì chỉ quan tâm chuối gồm các thành phần hóa học cơ bản nào rồi các công thức chuyển hóa học hóa nó thành cứt thôi, thích thì xắp xếp các công thức để tối ưu hóa quá trình chuyển hóa cứt và thậm chí chả cần quan tâm tới con khỉ.
 
1. Trừ tượng
Trừ tượng không phải chỉ là từ khoá abstract trong java mà nó là 1 khải niệm rộng hơn rất nhiều đó là việc ẩn giấu đi chi tiết. Bạn không cần phải biết 1 api nó làm gì bạn chỉ cần biết đầu vào api cần gì và đầu ra của api nó như thế nào. Như thế bạn sẽ k cần phải học nguyên lý của từng con ốc vít mà chỉ cần biết cỗ máy nó làm gì thôi.
Vậy trong java có từ khoá abstract và interface nó làm cái gì? Hai từ khoá ấy chủ yếu phục vụ cho việc thiết kế nói chung và việc "program to interface"(program to supertype ).
2. Bao gói
Bao gói là việc hạn chế truy cập vào attribute và method. Mỗi một public method bạn viết, đó là bạn đã cung cấp 1 api cho project. Tính bao gói sẽ phối hợp chặt chẽ với tính trừ tượng thông qua việc bạn mô tả method và return type. Việc này phục vụ cho 2 mục đích chính 1 - Bảo trì hệ thống , việc bạn quay trở lại tối ưu hoá cho những dòng code trước đó của api bạn cung cấp (đản bảo input và output vẫn thế) 2- là giúp ích cho nhưng cộng sự có thể bắt nhịp nhanh với nhưng api bạn viết.
3. Đa hình
Bỏ qua việc overload method thì
Đó là việc bạn có thể truy cập được các kiểu dữ liệu khác nhau chỉ với interface hoặc abstract class (hoặc class cha). Bằng việc sử dụng method của class cha nhưng tham chiếu đến implement của class con trong runtime. Nói 1 cách khác nó phục vụ cho việc program to interface và làm lỏng cái thành phần liên kết với nhau (loose coupling).
Có thể đọc Thêm Inversion of control và dependency injection.
4. Kế thừa
Như cái tên, nó là việc kế từ code.
Ngoài việc kế thừa re-use code nó còn phục vụ cho việc đa hình nữa

=> Từ 4 tính chất cơ bản này bằng việc kết hợp với nhau sẽ giúp ích được trong khâu giải quyết vấn đề, bảo trì, mở rộng cũng như cộng tác với nhau trong quá trình viết phần mềm.
Cũng từ 4 tính chất cơ bản các programmer giàu kinh nghiệm đi trước đúc kết ra thứ gọi là design pattern.

Còn làm sao để pro hơn, mình chưa pro nên mình chưa biết:sad:
 
xài đơn giản nhưng để maintain thì phải xi nghĩ kĩ, design đàng hoàng à
MjfezZB.png


như trong vid này:

  • Circle, Rectangle kế thừa Shape
  • Shape có hàm draw(), tùy implementation mà có thể xài backend là OpenGL, DirectX, vẽ ra svg, v.v...
  • Vậy nếu viết code bừa thì lại xài kế thừa thành OpenGlCircle, DirectXCircle, SvgCircle, ... kế thừa Circle
  • Sau này lại đẻ ra hàm serialize() cho Shape, có thể serialize thành json, xml, messagepack, protobuf, v.v...
  • Thế là lại đẻ ra class JsonOpenGlCircle, JsonDirectXCircle, ... kế thừa OpenGlCircle; XmlOpenGlCircle, XmlDirectXCircle, ... kế thừa DirectXCircle; ...
  • Chỉ với 2 hàm draw() (có N1 implementations) và serialize() (có N2 implementations) mà xài kế thừa bậy bạ đã phải tạo ra N1*N2 classes
    kH9BFd2.gif
    Với M hàm mỗi hàm có Nx impl thì thành ra N1*N2*...*NM classes thì chết mọe.

phải design sao cho chỉ cần implement đúng N1 + N2 implementations thoy. Xài OOP thì dễ nhưng xài cho dễ ứng phó với thay đổi mới là khó
JEWoIdl.png
Ý nghĩa thật sự rất hay
 
Back
Top