Agile, Architecture, Design Pattern, Devops, Methodology, Microservices, OO Design Principles, TDD

InfoQ’s 2019, and Software Predictions for 2020

See full post at: https://www.infoq.com/articles/infoq-2019-retrospective/

Key Takeaways

  • Last month, Google claimed to have achieved quantum supremacy—the name given to the step of proving quantum computers can deliver something that a classical computer can’t. That claim is disputed, and it may yet turn out that we need a better demonstration, but it still feels like a significant milestone.
  • A surprise this year was the decline of interest in Virtual Reality, at least in the context of Smart-phone-based VR. Despite this we still think that something in the AR/VR space, or some other form of alternative computer/human interaction, is likely to come on the market in the next few years and gain significant traction.
  • We expect to see the interest in Web Assembly continue and hope that the tooling for it will start to mature.
  • In our DevOps and Cloud trend report, we noted that Kubernetes has effectively cornered the market for container orchestration, and is arguably becoming the cloud-agnostic compute abstraction. The next “hot topics” in this space appear to be “service meshes” and developer experience/workflow tooling.
  • We’re looking forward to seeing what the open source community and vendors are working on in the understandability, observability, and debuggability space in the context of architectural patterns such microservices and functions(as-a-service).

Development

Java

JavaScript, Java, and C# remain the most popular languages we cover, but we’re also seeing strong interest in Rust, Swift, and Go, and our podcast with Bryan Cantrill on “Rust and Why He Feels It’s The Biggest Change In Systems Development in His Career” is one of the top-performing podcasts we’ve published this year. We’ve also seen a growing interest in Python this year, probably fuelled by its popularity for machine learning tasks.

After a rather turbulent 2018, Java seems to be settling into its bi-annual release cycle. According to our most-recent reader survey Java is the most used language amongst InfoQ readers, and there continues to be a huge amount of interest in the newer language features and how the language is evolving. We also continue to see strong and growing interest in Kotlin.

It has been interesting to see Microsoft’s growing involvement in Java, joining the OpenJDK, acquiring JClarity, and hiring other well known figures including Monica Beckwith.

In the Java programming language trends report, we noted increased adoption of non-HotSpot JVMs, and we believe OpenJ9 is now within the early-adopter stage. As the time we noted that:

“We believe that the increasing adoption of cloud technologies within all types of organisation is driving the requirements for JREs that embrace associated “cloud-native” principles such as fast start-up times and a low memory footprint. Graal in itself may not be overly interesting, but the ability to compile Java application to native binaries, in combination with the support of polyglot languages, is ensuring that we keep a close watch on this project.”

.NET

The release of .NET Core 3 in September generated a huge buzz on InfoQ and produced some of our most-popular .NET content of the year. WebAssembly has been another area of intense interest, and we saw a corresponding surge in interest for Blazor, a new framework in ASP.NET Core that allows developers to create interactive web applications using C# and HTML. Blazor comes in multiple editions, including Blazor WebAssembly which allows single-page applications to run in the client’s web browser using a WebAssembly-based .NET runtime.

According to our most-recent reader survey, C# is the second-most widely used language among InfoQ readers after Java, and interest in C#8 in particular was also strong.

Web Development

Unsurprisingly, the majority of InfoQ readers write at least some JavaScript – around 70% according to the most recent reader survey – making it the most widely used language among our readers. The dominant JavaScript frameworks for InfoQ readers seem to currently be Vue and React. We also saw interest in using Javascript for machine learning via TensorFlow.js.  Away from JavaScript, we saw strong interest in some of the transpiler options. In addition to Blazor, mentioned above, we saw strong interest in Web Assembly, Typescript, Elm and Svelte.

Architecture

It’s unsurprising that distributed computing, and in particular the microservices architecture style, remains a huge part of our news and feature content. We see strong interest in related topics, with our original Domain Driven Design Quickly book, and our more-recent eMag “Domain-Driven Design in Practice” continuing to perform particularly well, and interest in topics like observability and distributed tracing. We also saw interest in methods of testing distributed systems, including a strong performance from our Chaos Engineering eMag, and a resurgence in reader interest in some for the core architectural topics such as API design, diagrams, patterns, and models.

AI, ML and Data Engineering

Our podcast with Grady Booch on today’s Artificial Intelligence reality and what it means for developers was one of our most popular podcasts of the year, and revealed strong interest in the topic from InfoQ readers.

Key AI stories in 2019 were MIT introducing GEN, a Julia-basd language for artificial intelligence, Google’s ongoing work on ML Kit, and discussions around conversational interfaces, as well as more established topics such as streaming.

It’s slightly orthogonal to the rest of the pieces listed here, but we should also mention “Postgres Handles More Than You Think” by Jason Skowronski which performed amazingly well.

Culture and Methods

If there was an overarching theme to our culture and methods coverage this year it might best be summed up as “agile done wrong” and many of our items focused on issues with agile, and/or going back to the principles outlined in the Agile Manifesto.

We also saw continued in interest in some of the big agile methodologies, notably Scrum, with both “Scrum and XP from the Trenches“, and “Kanban and Scrum – Making the Most of Both” performing well in our books department.

We also saw strong reader interest in remote working with Judy Rees’ eMag on “Mastering Remote Meetings“, and her corresponding podcast, performing well, alongside my own talk on “Working Remotely and Managing Remote Teams” from Aginext this year.

DevOps and Cloud

In our DevOps and Cloud trends report, we noted that Kubernetes has effectively cornered the market for container orchestration, and is arguably becoming the cloud-agnostic compute abstraction. The next “hot topics” in this space appear to be “service meshes” and developer experience/workflow tooling. We continue to see strong interest in all of thee among InfoQ’s readers.

A trend we’re also starting to note is a number of languages which are either infrastructure or cloud-orientated. In our Programming Languages trends report, we noted increased interest and innovation related to infrastructure-aware or cloud-specific languages, DSLs, and SDKs like Ballerina and Pulumi. In this context we should also mention Dark, a new language currently still in private beta, but already attracting a lot of interest. Somewhat related, we should also mention the Ecstasy language, co-created by Tangosol founders Cameron Purdy and Gene Gleyzer. Chris Swan, CTO for the Global Delivery at DXC Technology, spoke to Cameron Purdy about the language and the problems it’s designed to solve.

Software Predictions for 2020

Making predictions in software in notoriously hard to do, but we expect to see enterprise development teams consolidate their cloud-platform choices as Kubernetes adoption continues. Mostly this will be focussed on the “big five” cloud providers – Amazon, Google, IBM (plus Red Hat), Microsoft, and VMware (plus Pivotal). We think that, outside China, Alibaba will struggle to gain traction, as will Oracle, Salesforce, and SAP.

In the platform/operations space we’re expecting that service meshes will become more integrated with the underlying orchestration frameworks (e.g. Kubernetes). We’re also hopeful that the developer workflow for interacting with service meshes becomes more integrated with current workflows, technologies, and pipelines.

Ultimately developers should be able to control deploy, release, and debugging via the same continuous/progressive delivery pipeline. For example, using a “GitOps” style pipeline to deploy a service by configuring k8s YAML (or some higher-level abstraction), controlling the release of the new functionality using techniques like canarying or shadowing via the configuration of some traffic management k8s custom resource definition (CRD) YAML, and enabling additional logging or debug tooling via some additional CRD config.

In regards to architecture, next year will hopefully be the year of “managing complexity”. Architectural patterns such microservices and functions(as-a-service) have enabled developers to better separate concerns, implement variable rates of change via independent isolated deployments, and ultimately work more effectively at scale. However, our ability to comprehend the complex distributed systems we are now building — along with the availability of related tooling — has not kept pace with these developments. We’re looking forward to seeing what the open source community and vendors are working on in the understandability, observability, and debuggability space.

We expect to see more developers experimenting with “low code” platforms. This is partly fueled by a renewed push from Microsoft for its PowerApps, Flow, Power BI, and Power Platform products.

In the .NET ecosystem, we believe that Blazor will keep gaining momentum among web developers. .NET 5 should also bring significant changes to the ecosystem with the promised interoperability with Java, Objective-C, and Swift. Although it is early to say, Microsoft’s recent efforts on IoT and AI (with ML.NET) should also help to raise the interest in .NET development.  Related we expect to see the interest in Web Assembly continue and hope that the tooling hear will start to mature.

Despite the negative news around VR this year, we still think that something in the AR/VR space, or some other form of alternative computer/human interaction, is likely to come on the market in the next few years and gain significant traction, though it does seem that the form factor for this hasn’t really arrived.

Architecture, Design Pattern

Low Coupling và High Cohesion là gì?

Low couplinghigh cohesion là 2 thuộc tính đi cùng với nhau như là mục tiêu cần đạt được trong thiết kế, trong bài viết này, cùng tìm hiểu xem chúng là gì, làm sao để đạt được và tránh các lỗi liên quan đến coupling và cohesion khi thiết kế phần mềm.

Coupling

Low coupling, loose coupling hay high couplingtight coupling, ắt hẳn ai trong chúng ta khi học về các nguyên lý lập trình căn bản đều biết về khái niệm coupling này. Coupling đề cập đến vấn đề phụ thuộc lẫn nhau giữa các component. Low coupling, loose coupling có nghĩa là các component ít phụ thuộc vào nhau, sự thay đổi trong component này ít khi, hoặc không ảnh hưởng đến component kia. Ngược lại, high coupling và tight coupling cho thấy các component phụ thuộc nhiều vào nhau, khi thay đổi 1 component thì các component kia đều bị ảnh hưởng và có khả năng phải thay đổi theo. Tất nhiên, low coupling là mục tiêu chúng ta cần hướng đến để đảm bảo cho hệ thống ít bị ảnh hưởng khi có thay đổi và do đó, tăng tốc độ thực hiện công việc và bảo trì.

Thêm một ví dụ nữa về coupling

Trong câu hỏi trên StackOverflow có một câu trả lời cho thấy một mô tả hài hước nhưng khá chính xác và rõ ràng về những gì 1: 1 coupling là:

iPod là một ví dụ tốt về tight coupling: một khi pin chết bạn cũng có thể mua một chiếc iPod mới vì pin được hàn cố định và sẽ không bị lỏng, do đó thay thế rất tốn kém. Một cái máy có tính loosely coupled sẽ cho phép thay đổi pin dễ dàng.

iPods are a good example of tight coupling: once the battery dies you might as well buy a new iPod because the battery is soldered fixed and won’t come loose, thus making replacing very expensive. A loosely coupled player would allow effortlessly changing the battery.

Tương tự, 1: 1, trong phát triển phần mềm.

Chúng ta sẽ xem xét diagram dưới đây:

tight_coupling

Nếu chúng ta nhìn vào hình trên, nó cho chúng ta thấy một mối liên hệ giữa hai class được gọi là tight coupling. Class1 ở trên tạo ra các đối tượng của Class2 trực tiếp, và thậm chí là đi đến các biến thành viên và truy cập vào. Điều này làm cho nó rất phụ thuộc vào Class2. Điều gì sẽ xảy ra nếu chúng ta quyết định rằng chúng ta muốn thêm tham số thêm vào trong constructor của Class2 và đặt mặc định là private? Sau đó, chúng ta phải thay đổi mọi cách sử dụng Class2 ở mọi nơi. Không đẹp lắm, heh? Có thể là một cơn đau đầu rất lớn và là một trong những vấn đề đầu tiên trong thiết kế.

Dưới đây là ví dụ bằng code:

public class ClassA {

	private boolean attributeA;

	public int methodA() {
		if(attributeA) {
			return new ClassB().attributeB;
		}
		return -1;
	}

	public String getValue() {
		return new ClassB().getValue();
	}

}

public class ClassB {

	public int attributeB;

	public String getValue() {
		return "Heh?!?";
	}

}

Một số giải pháp

Dependency inversion

Ví dụ trong Java, ta sẽ thêm một interface. Đó là cách Class1 sẽ chỉ phụ thuộc vào interface đó, chứ không phải là implementation thực tế của Class2, do đó giảm thiểu sự phụ thuộc trực tiếp giữa 2 class với nhau.

Law of Demeter (Don’t talk to strangers!)

Lợi điểm của Law of Demeter là nó giúp hệ thống của chúng ta đứng vững trước những thay đổi bằng cách giảm coupling hay còn gọi là cách design loose coupling, mọi sự thay đổi sẽ là nhỏ nhất nếu có thể.

Cohesion

Còn high cohesion (trái ngược với nó là low cohesion) là gì? Khi nói đến cohesion chúng ta nghĩ đến nhiệm vụ của từng module. Nhiệm vụ của từng module càng rõ ràng và tách biệt thì cohesion càng cao (high cohesion), và đó là mục tiêu cần đạt tới khi thiết kế. Giải thích bằng code có lẽ sẽ không rõ ràng, hãy xem xét câu dưới đây:

Tại kỳ họp Quốc hội thứ năm, khi thảo luận về quản lý chất lượng vệ sinh an toàn thực phẩm có vị đại biểu Quốc hội đã ví việc có tới 5 bộ chịu trách nhiệm chính như vậy cũng giống như “nhiều sãi không ai đóng cửa chùa”.Bởi thế, làm rõ trách nhiệm của từng cơ quan quản lý Nhà nước về an toàn thực phẩm là một yêu cầu được nhấn mạnh khi xây dựng Dự Luật An toàn thực phẩm.

Nguồn: http://vneconomy.vn/thoi-su/an-toan-thuc-pham-bo-nao-trang-trai-bo-nao-ban-an-20100519102635734.htm

Nếu xem Dự Luật An toàn thực phẩm là một feature thì rõ ràng nó đã không đạt được tính high cohesion trong thiết kế vì nó phải dàn trải và phụ thuộc vào rất nhiều module (5 bộ, phòng ban) khác nhau. Do đó, khi cần chỉnh sửa bổ sung dự luật sẽ rất khó khăn vì phải sửa 1 lúc 5 module, mà bạn thấy đó, điều đó rõ ràng là rất khó. Nếu quy trách nhiệm xây dựng bộ luật này cho một bộ ban duy nhất thì sẽ giảm tính phức tạp và do đó, tăng tính cohesion. High cohesion thường đạt được nếu ta tuân thủ theo nguyên tắc đơn nhiệm (Single responsibility principle), mỗi module, khi đó chỉ đảm nhiệm một nhiệm vụ duy nhất, không hơn không kém, và không có chuyện 2 module cùng làm một nhiệm vụ, một tính năng.

Đến đây chắc ai cũng hiểu được rồi đúng không? Ít nhất là về mặt lý thuyết, hãy xem xét bảng sau trước khi mình đi vào các dẫn giải tiếp theo

COHESION COUPLING
Cohesion thể hiện mối quan hệ bên trong module. Coupling thể hiển sự liên kết giữa các modules.
Cohesion thể hiện sức mạnh liên kết giữa các chức năng Coupling thể hiện quan hệ phụ thuộc vào nhiều modules.
Cohesion đánh giá chất lượng mà một component / module tập trung vào một việc đơn lẻ. Coupling là đánh giá mức độ một component / module liên kết với mudule khác.

Cohesion Type

Sự gắn kết ngẫu nhiên (Coincidental cohesion) – *Bad* Very low cohesion

Sự gắn kết ngẫu nhiên là khi các phần của mô-đun được nhóm lại một cách tùy tiện; mối quan hệ duy nhất giữa các bộ phận là họ đã được nhóm lại với nhau. Một ví dụ của điều này có thể là một lớp Utility, nơi các phần tử hoàn toàn độc lập với nhau lại được group lại với nhau. Hình dưới minh họa rõ hơn về điều này

your-email-1

Sự gắn kết logic (Logical cohesion)

Sự gắn kết logic là khi các phần của mô-đun được nhóm lại vì chúng được phân loại logic để làm việc tương tự, ngay cả khi chúng khác nhau theo bản chất (ví dụ: nhóm tất cả các function xử lý đầu vào cho chuột và bàn phím).

Sự gắn kết thời gian (Temporal cohesion)

Sự gắn kết thời gian là khi các phần của mô-đun được nhóm lại khi chúng được xử lý – các phần được xử lý tại một thời điểm cụ thể trong quá trình thực hiện chương trình (ví dụ như một hàm được gọi là sau khi catch một exception khi close file, tạo ra một error log và thông báo đến người dùng).

Sự gắn kết theo thủ tục (Procedural cohesion)

Sự gắn kết theo thủ tục là khi các phần của mô-đun được nhóm lại bởi vì chúng luôn tuân theo một trình tự thực thi nhất định (ví dụ: một chức năng kiểm tra quyền truy cập tệp và sau đó mở tệp).

Sự gắn kết thông tin / trao đổi (Communicational/informational cohesion)

Sự liên kết giao tiếp là khi các phần của mô-đun được nhóm lại vì chúng hoạt động trên cùng một dữ liệu (ví dụ như mô-đun hoạt động trên cùng một bản ghi thông tin).

Sự liên kết tuần tự (Sequential cohesion)

Sự liên kết tuần tự là khi các phần của một mô-đun được nhóm lại bởi vì đầu ra từ một phần là đầu vào đến một phần khác giống như một dây chuyền lắp ráp (ví dụ như một chức năng đọc dữ liệu từ một tệp tin và xử lý dữ liệu).

Sự gắn kết về mặt chức năng (Functional cohesion) *Good*

Sự gắn kết chức năng là khi các phần của mô-đun được nhóm lại vì tất cả chúng đóng góp vào một nhiệm vụ duy nhất được định nghĩa rõ ràng của mô-đun (ví dụ, phân tích Lexical của một chuỗi XML).

Một cách nhìn sự gắn kết trong hướng đối tượng là nếu các method trong class đang sử dụng bất kỳ private attribute nào. Hình dưới là một ví dụ về cách một lớp gắn kết cao sẽ như thế nào.

high_cohesion
Sử dụng các số liệu (metric) như LCOM4 (Lack of Cohesive Methods) trong Sonar, và “Relational cohesion measurement” trong NDepend (trong .NET) và JDepend (trong Java), bạn có thể xác định các lớp cần được sắp xếp lại. Lý do bạn muốn các method hoặc các class refactor lại để được gắn kết hơn là nó làm cho việc thiết kế mã đơn giản hơn cho người khác sử dụng nó.

Có một vài trường hợp rất phổ biến mà tôi có thể nghĩ đến cho thấy tính low cohesion trong thiết kế:

Trường hợp 1: Method không liên quan gì đến class

Trường hợp 2: Utility Class

Trường hợp 3: Hidden objects and subclasses

Không phải lúc nào cũng có thể đạt được sự gắn kết tuyệt đối cao trong lớp, nhưng biết nó là gì và làm thế nào để nó góp phần vào việc thiết kế tổng thể có thể là một kiến thức tốt. Chúng ta không thể luôn luôn làm cho hoàn hảo, nhưng ít nhất chúng ta có thể phấn đấu để làm tốt hơn.

<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>
public class HighCohesionExample {

	private String attributeA;
	private String attributeB;

	public int calculate() {
		return doCalculate(attributeA) + doCalculate(attributeB);
	}

	private int doCalculate(String attribute) {
		return attribute.length() * 3;
	}

	public String getValue() {
		return String.format("%s & %s", attributeA, attributeB);
	}

}

Một class càng nhỏ, có ít attribute và method thì càng dễ đạt được tính cohesion cao, vì khi đó, chúng dễ dàng được sử dụng trong class một cách có ý nghĩa và liên quan đến nhau.

Mở rộng

Một câu hỏi đặt ra là hai tính chất này có cùng lúc đạt được song song với nhau hay không? Hay sẽ loại trừ nhau? Ví dụ như phân rã thành càng nhiều module thì tính low coupling sẽ càng đạt được, ngược lại nếu như một tính năng bị phân rã thành nhiều module thì khi sửa đổi sẽ gặp nhiều khó khăn, do đó lại không đạt được tính high cohesion như mong đợi, và trường hợp ngược lại.

Để trả lời câu hỏi này, chúng ta cần tập trung vào scope (phạm vi) của chúng. Nhìn nhận một cách tổng thể từ ban đầu, low coupling liên quan đến sự phụ thuộc, hiểu biết giữa các module với nhau, còn high cohesion là việc gom nhóm các thành phần có liên quan về cùng một module để dễ dàng quản lý và bảo trì. Vì vậy, chúng không loại trừ nhau và chúng ta có thể đạt được cả 2.

Có trường hợp ta tổ chức các thành phần làm chung một chức năng vào cùng một module rồi, thì vẫn có khả năng xảy ra chuyện các module phụ thuộc chồng chéo lên nhau, khi đó ta gọi nó có tính high cohesion nhưng tight coupling.

Kết luận

Mục tiêu của thiết kế có thể túm gọn trong 3 từ: low coupling, high cohesion và encalsulation, bằng cách đảm bảo được 3 tính chất này, hệ thống sẽ có khả năng phát triển, mở rộng và bảo trì cực cao (tất nhiên, nói dễ hơn làm)

Đây là bài viết trong loạt bài viết về “Tổng quan về sự phát triển của kiến trúc phần mềm“. Đây là loạt bài viết chủ yếu giới thiệu về một số mô hình kiến trúc phần mềm hay nói đúng hơn là sự phát triển của chúng qua từng giai đoạn, qua đó giúp chúng ta có cái nhìn tổng quát, up-to-date và là roadmap để bắt đầu hành trình chinh phục (đào sâu) thế giới của những bản thiết kế với vai trò là những kỹ sư và kiến trúc sư phần mềm đam mê với nghề.

Bài viết được tham khảo từ:

High Cohesion, Loose Coupling

Tổng hợp bởi edwardthienhoang

Book, Design Pattern, TDD

Book Review: xUnit Test Patterns: Refactoring Test Code: Gerard Meszaros

Khi đối diện với những điều không (chưa) biết, kẻ bi quan sẽ tỏ ra lo sợ và trốn chạy, người lạc quan thì không như vậy, họ luôn biết cách đối mặt với nó.

Vào những năm cuối thập niên 90, khi phong trào eXtreme Programming mới bắt đầu được khai nén, đã có những nhóm, những nhà tiên phong đi đầu trong việc áp dụng các kỹ thuật của nó như pair programming, collective ownership và test driven development. Tuy nhiên, họ đã gặp phải rất nhiều vấn đề trong đó, ví dụ như là làm thế nào để apply TDD, viết và quản lý test code cho real-world project. Khi production code lẫn test code bắt đầu phình ra cũng là lúc họ nhận ra rằng ngày càng tốn nhiều effort chỉ để làm những công việc lặp đi lặp lại. Đã có lúc, đến 90% effort bỏ ra chỉ cho việc maintenance những unit test cases đã có chỉ để đáp ứng một thay đổi cực kỳ minor. Một con số thật sự làm nản lòng và gây hoang mang dù là những người lạc quan nhất. Và họ biết, họ cần phải làm gì đó để thay đổi điều đó.

3394674118_28fd307467

TDD, kẻ thì khen, người thì chê. Kẻ khen thì trầm trồ về sự ưu việt của nó, kẻ chê thì nói TDD thực sự chỉ là 1 thứ rối rắm, tốn nhiều công lắm của mà không thực sự giải quyết được bài toán mà họ gặp phải. Nhưng có mấy kẻ hiểu được làm TDD như thế nào cho effective. Khi đối diện với một dự án phức tạp, vấn đề gây đau đầu nhất trong mỗi lần thay đổi source code chính là degradation, làm sao để analyze và thực hiện regression test để bảo đảm code change là “vô hại” đến những phần khác. Những lúc như vậy, ai cũng mong có một bộ automated test để phòng thân, nhưng cái giá của nó không phải là free, hoặc có thể là vô giá.

Prorgramming is hard, hay nói cách khác, tạo ra những đoạn code trong sáng, dễ maintain và extend là không dễ. Trừ khi ta nắm được các bí quyết để làm chuyện đó. Bằng cách nhận biết đâu là những đoạn code tệ (code smell), hay mở rộng ra là project smell, architecture smell, environment smell, ta sẽ biết cách để sửa chữa chúng. Refactoring những chỗ không tốt thành tốt hơn đòi hỏi những kỹ thuật cao hơn như nắm vững các coding, design principle, patterns. Khi đó, code sẽ trở nên sáng sủa và vững vàng hơn nhiều, programming is now easy and much more exciting, like a joy!! ^^

Testing is extremely hard, vì trường học không (kịp) dạy ta các kỹ năng về kiểm thử. Programmer thích lập trình, sợ bugs, ghét tester… nên đâm ra ghét testing. Đặc biệt không có anh nào code dở mà có thể test (unit, at least) giỏi, mấy người như vậy qua làm tester hết rồi. Còn lại những anh code dở và test cũng dở, và những anh code vốn giỏi mà test dở. (Chỗ này hại não =)) Với những anh code giỏi thì khả năng để improve kỹ thuật testing là tương đối dễ dàng, những anh khác, vui lòng quay lên phần “Programming is hard”.

Để make (Unit) Testing more fun and do-able, việc đầu tiên chính là phải code giỏi cái đã. “Code that hard to test is the bad code”. Vậy làm sao để nhận diện đâu là code tệ? Đa phần đã nghe đến code smell, vậy còn test smell. Sử dụng test smell để nhận diện các vấn đề gây khó khăn cho việc viết test là bước đầu tiên. Test smell có thể bao hàm rất nhiều thứ kể cả code smell. Bên cạnh đó, cũng giống như programming, testing cũng có principle và pattern của nó. Nói chung, mọi thứ đều có nguyên tắc, tuân thủ theo luật lệ sẽ cho ra các sản phẩm unit-test chất lượng.

Nếu ai đủ kiên nhẫn đọc đến đây thì sẽ thắc mắc, viết dông dài vậy làm gì. Ah, tất nhiên là mình giới thiệu sách rồi (thực ra là khoe cuốn sách mới mua, mới đọc được có cái (hard)cover và cái preface đã bay lên chém gió như thần).

Tên cuốn sách
xUnit Test Patterns: Refactoring Test Code: Gerard Meszaros

Mục đích cuốn sách:
– Giải tỏa nỗi sợ về (automated) (unit) testing. Là nguồn cảm hứng và chỗ dựa (kỹ thuật) vô cùng bổ ích cho những ai đã, đang và sẽ có dự định improve productivity throuhg testing. Cuốn sách đề cập đến các kỹ thuật develop automated unit test case, các test smell để giúp programmer tránh các lỗi thường gặp lúc viết production code và test code + các cách refactoring chúng. Test principle là kim chỉ nam cho việc viết test, test design patterns là các practices áp dụng cho từng trường hợp cụ thể.
– Nếu xem GoF là kinh thánh cho dân Production Code thì xUnit Test Patterns này là dành cho Test Code.

For fun:
– (Khoe) Sách gốc hardcover $79.99. Dày 900 trang, nặng gãy tay :)))
– Người review trên tinh thần chém gió là chính chứ mới đọc được cái cover thôi =))
– Chỉ có cuốn sách trong hình là thật
– Link ebook cho dân không đủ điều kiện: google nhé 😉

Design Pattern, Java, OO Design Principles

Avoid NullPointerException in Java

I would like to share with you some tips to deal/prevent NPE in your code:

The BIG IMPORTANT rule: do NOT assign / pass / return null value and keep your code as cohesive as possible.

Programming tips / techniques:
1. Return an empty collections instead of null.
For example:
List:

return Collections.emptyList()

Set:

return Collections.emptySet()

Map:

return Collections.emptyMap()
org.apache.commons.lang.ArrayUtils.EMPTY_XXX_ARRAY

2. Return

org.apache.commons.lang.StringUtils.EMPTY

or “” instead of null

3. Return “UNKNOWN” enum instead of null

4. Check null before executing a variable

5. Null-safe checking technique

if("Hello".equals(hello)) { }

instead of

if(hello != null) {
	if(hello.equals("Hello")) { }
}

or

if(hello.equals("Hello")) { }

Principle and Pattern:
6. Null Object Pattern (https://sourcemaking.com/design_patterns/null_object/java-0)
(My favourite pattern belong with Template Method and Bridge)
Instead of

public Manager getManager(ManagerType inType){
	switch(inType) {
		case PROJECT:
			return ProjectManager();
		case DEPARTMENT:
			return DepartmentManager();
		default:
			break;
	}
	return null;
}

Let try:

public Manager getManager(ManagerType inType){
	switch(inType) {
		case PROJECT:
			return ProjectManager();
		case DEPARTMENT:
			return DepartmentManager();
		default:
		break;
	}
	return NullManager();
}

Design tips:

class NullManager extends Manager {
	// Implement all abstract methods of Manager
	// Override neccessary methods to drive to do "Nothing" or "Default" action.
}

7. Avoid too many dot syntax. (http://en.wikipedia.org/wiki/Law_of_Demeter)
For example:

getSettingManager().getSettingPanel().getHeaderPanel().getHeaderLabel().setText("Setting");

Class Variable:
8. Try initializing variable member of class before using it.
Direct initialization

private List mPersons = new ArrayList();

Initialize them in class Constructor

public Family() {
	mPersons = new ArrayList();
}

Constructor dependency injection

public Family(List inPersons) {
	mPersons = inPersons;
}

Provide accessibility through getter and using lazy initialization

public getPersons() {
	if(mPersons == null) {
	mPersons = new ArrayList();
	}
	return mPersons;
}

9. Avoid / eliminate method dependency injection (setter)

public setPersons(List inPersons) {
	mPersons = inPersons;
}
NGUỒN: HTTP://EDWARDTHIENHOANG.WORDPRESS.COM/
EMAIL: EDWARDTHIENHOANG@GMAIL.COM

[/sourcecode]

Design Pattern, OO Design Principles

Những nguyên tắc, những định luật của lập trình mà chúng ta nên có sẵn trong đầu

Nguồn : http://qiita.com/hirokidaichi/items/d6c473d8011bd9330e63

Người dịch : Phan Hoàng Minh (https://viblo.asia/minhp/posts/wpVYRP2kG4ng)

page0010

Nguyên tắc Demeter

Còn có tên gọi khác là nguyên tắc “càng biết ít càng tốt”.

Demeter là tên gọi của Nữ thần nông nghiệp, cũng là nữ thần phân phát trong thần thoại Hi Lạp. Tên bà được dùng để đánh dấu sự ra đời của nguyên tắc này, đây có thể xem là một triết lý nền tảng của việc lập trình được sinh ra từ một aspect-oriented programming (AOP) project cùng tên.

Quan điểm cơ bản của nguyên tắc này chính là : tối giản sự hiểu biết của 1 object về cấu trúc, thuộc tính của các object khác ngoài nó (bao gồm các thành phần con).

http://en.wikipedia.org/wiki/Law_of_Demeter

Nói một cách đơn giản là không được tiếp xúc với thuộc tính, method của các object khác một cách trực tiếp.

#Vi phạm nguyên tắc Demeter
console.log(aStudent.class.grade)

#Không vi phạm nguyên tắc Demeter
console.log(aStudent.getGrade())

Định luật Wirth

“Software gets slower faster than hardware gets faster” – “Tốc độ tiến hóa của phần cứng không bằng tốc độ thoái hóa của phần mềm.”

http://en.wikipedia.org/wiki/Wirth’s_law

Có lẽ ý chính của nó là : lập trình ngày càng dùng nhiều tài nguyên phong phú nên framework phải luôn tiến hóa để phục vụ cho việc đó. Suy ra, tốc độ phần cứng dù có tang lên đi nữa thì tốc độ phần mềm cũng chẳng hề thay đổi gì.

Định luật Brook

Đây là một định luật dựa trên kinh nghiệm thực tế : “Đưa thêm người vào 1 project đang chậm, sẽ chỉ khiến nó càng chậm hơn.”

Hay có thể nói theo một cách khác nữa là “Tập hợp 9 bà bầu lại cũng không thể khiến đứa trẻ ra đời sau 1 tháng.”

Luận thuyết cơ bản của định luật này là

  • Cần thời gian để quen với project
  • Công sức dành cho việc communication sẽ tăng

http://en.wikipedia.org/wiki/Brooks%27s_law

Định luật Conway

“Organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations.”

“Một công ty thiết kế hệ thống thế nào cũng sẽ làm ra những thiết kế giống y hệt với thiết kế hệ thống của chính công ty họ.”

http://en.wikipedia.org/wiki/Conway%27s_law

Nghiên cứu gần đây chỉ ra rằng hệ thống của công ty là nhân tố ảnh hưởng lớn nhất đến vấn đề phát sinh ra bug của sản phẩm.

http://research.microsoft.com/apps/pubs/default.aspx?id=70535

Nguyên tắc bất ngờ nhỏ nhất (least astonishment)

Trong trường hợp trên cùng 1 interface có 2 yếu tố hành xử mâu thuẫn với nhau, hoặc cách hành xử không rõ ràng thì cần phải chọn cách hành xử nào gây bất ngờ ít nhất cho người sử dụng.

http://en.wikipedia.org/wiki/Principle_of_least_astonishment

Đây là 1 nguyên tắc về giao diện người dùng.

Một ví dụ đơn giản :

Trên 1 interface có 2 chức năng :

  • Ấn ctrl+Q để thoát chương trình.
  • Nhập macro (lưu 1 tổ hợp phím mang 1 chức năng nào đó để tiện cho việc sử dụng về sau).

Sẽ có trường hợp user muốn dùng Ctrl+Q cho macro của mình, nên hành xử đúng với nguyên tắc bất ngờ nhỏ nhất chính là : trong khi nhập macro thì ctrl+Q được coi như là tổ hợp phím bình thường, không phải là lệnh tắt chương trình. Đây chính là điều gây bất ngờ ít nhất cho người dùng.

Nguyên tắc Boy Scout

Nguyên tắc của các tổ chức Boy scout chính là : lúc đi phải sạch đẹp hơn lúc đến.

Trong lĩnh vực lập trình thì nguyên tắc đó sẽ được hiểu là “Khi bạn checkin 1 module thì lúc đó nó phải đẹp hơn lúc bạn checkout.”

Nguyên tắc YAGNI

Viết tắt của “You ain’t gonna need it” – Cái (chức năng, phần) ấy rồi sẽ không cần thiết.

Đó là một câu khẩu ngữ nhắc nhở người lập trình rằng trong quy trình eXtreme Programming (lập trình cực hạn) thì : “Chưa phải lúc cần thiết thì chưa được phép làm.”

Nguyên tắc DRY

Viết tắt của “Don’t repeat yourself” – với ý nghĩa là “Đừng lặp lại những gì giống nhau”.

http://en.wikipedia.org/wiki/Don%27t_repeat_yourself

Khi nguyên tắc này được áp dụng tốt, dù ta có thay đổi 1 phần thì những phần không liên quan cũng sẽ không bị thay đổi theo. Hơn nữa, những phần có liên quan sẽ được thay đổi cùng 1 lượt, giúp ích rất nhiều cho cả khâu estimate và khâu thực hiện.

Nguyên tắc KISS

Viết tắt của “Keep it simple, stupid” – “Cứ đơn giản thôi, đồ ngu!”. Đây là 1 triết lí của Hải quân Mỹ.

http://en.wikipedia.org/wiki/KISS_principle

Những triết lý tương tự có thể kể đến là :

Phương châm dao cạo Okham (Okham’s razor) – “Không đưa ra nhiều giả thiết nếu không cần thiết. Cái gì cần ít giả thiết để chứng minh sẽ không thể chứng minh được bằng nhiều giả thiết.”

Albert Einstein – “Làm cái gì cũng nên đơn giản nhất có thể, nhưng đơn giản quá thì không được”.

Leonardo da Vinci – “Đơn giản nhất chính là tinh xảo nhất”.

Antoine de Saint- Exupéry – “Hoàn hảo, không phải là không thêm vào được nữa, mà là không thể bớt đi được nữa”.

Nguyên tắc SOLID

Tập hợp những nguyên tắc trong lập trình hướng đối tượng. Các chữ cái đầu hợp lại thành SOLID.

http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)

SRP (Single Responsibility Principle) – “Một class chỉ được có 1 nhiệm vụ” hay nói cách khác, “nếu muốn chỉnh sửa class thì chỉ được phép có 1 và chỉ 1 lý do”.

OCP (Open/closed principle) – “Mở class khi cần mở rộng nó, đóng class khi cần chỉnh sửa nó”.

LSP (Liskov substitution principle) – “Subtype phải luôn có thể được thay thế bằng supertype”.

ISP (Interface segregation principle) – “Việc dùng nhiều interface cho các client khác nhau, tốt hơn là việc chỉ dùng 1 interface cho cùng lúc nhiều mục đích” hay nói cách khác “Không được phép hạn chế access vào những method mà client không sử dụng”.

DIP (Dependency inversion principle) – “Module tầng trên không được phụ thuộc vào module tầng dưới. Bất cứ module nào cũng phải phụ thuộc vào cái trừu tượng, không phải vào cái cụ thể”.

Design Pattern, OO Design Principles, Tản mạn

Tản mạn về Dependency Injection

Tản mạn về Dependency Injection

Như thường lệ, blog của mình sẽ rất ít các định nghĩa, rất nhiều code, hình ảnh minh họa và những câu nói dí dỏm. OK, hãy bắt đầu với định nghĩa về Dependency

Dependency

Khi trong class A có sự tồn tại của lớp B, dùng lớp B để làm 1 công việc gì đó, ta nói lớp A đang phụ thuộc vào lớp B. Ví dụ: CustomerRepository.java

package com.edward.tutorial.di.repository;

import java.util.Collection;

import com.edward.tutorial.di.model.Customer;

public class CustomerRepository {
	public Customer findOne(String customerId) {
		// Code stuff
	}

	public Collection<Customer> findAll() {
		// Code stuff
	}

	public void create(Customer customer) {
		// Code stuff
	}

	public boolean update(Customer customer) {
		// Code stuff
	}

	public void delete(Customer customer) {
		// Code stuff
	}
}

CustomerService.java

package com.edward.tutorial.di.service;

import java.util.Collection;

import com.edward.tutorial.di.model.Customer;
import com.edward.tutorial.di.repository.CustomerRepository;

public class CustomerService {
	
	CustomerRepository customerRepository;
	
	Collection<Customer> findAll() {
		return customerRepository.findAll();
	}

	Customer create(Customer customer) {
		customerRepository.create(customer);
		return customer;
	}
	
	Customer update(Customer customer) {
		customerRepository.update(customer);
		return customer;
	}

	void delete(String customerId) {
		Customer customer = findOne(customerId);
		customerRepository.delete(customer);
	}
	
	public Customer findOne(String customerId) {
		return customerRepository.findOne(customerId);
	}
}

Như ví dụ ở trên, lớp CustomerService đang phụ thuộc vào lớp CustomerRepository, vì CustomerService đang sử dụng 1 instance của CustomerRepository để thực hiện việc lưu trữ dữ liệu xuống database, cụ thể ở đây là customerRepository. Dependency1 Vậy: customerRepository được khởi tạo ở đâu? Vì nếu không được khởi tạo, thì khi sử dụng chúng ta sẽ nhận được NullPointerException. Câu trả lời là: để sử dụng được đối tượng customerRepository trong CustomerService, chúng ta sẽ có 2 cách:

  1. Khởi tạo đối tượng customerRepository trong lớp CustomerService.
  2. Truyền (Inject) đối tượng customerRepository đã được khởi tạo sẵn từ bên ngoài vào lớp CustomerService.

Dependency2

Injection

CHÚNG TA VỪA NHẮC ĐẾN INJECT. ĐÚNG VẬY, KHI LÀM THEO CÁCH 2, NGHĨA LÀ CHÚNG TA ĐANG THỰC HIỆN DEPENDENCY INJECTION. MỘT LƯU Ý KHÁC: Nếu chỉ muốn hiểu Dependency Injection là gì thì xin chúc mừng, chúng ta đã hoàn thành mục tiêu ở đây. Tuy nhiên chắc sẽ chẳng ai muốn dừng lại tại đây. Cho nên chúng ta sẽ đi tiếp phần demo và những chủ đề liên quan đến Dependency Injection Tiếp tục với việc demo cho 2 cách trên. Dependency3 Vậy các bạn sẽ tự hỏi: cách nào là tốt nhất, lúc nào nên dùng cách nào? Câu trả lời vẫn như mọi khi: không cách nào là hoàn hảo.

Tightly coupling và Loosely coupling

Trước khi đi vào phân tích ưu nhược của các cách làm, chúng ta cần làm rõ 2 khái niệm: tightly coupling và loosely coupling.

Tightly coupling:

Ở cách 1, khi khởi tạo đối tượng customerRepository ngay trong lớp CustomerService, ta nói lớp CustomerService đang phụ thuộc hoàn toàn vào lớp CustomerRepository. Trong suốt quá trình chương trình được thực thi (runtime), lớp CustomerService sẽ chỉ làm việc với duy nhất thể hiện của lớp CustomerRepository. Ở cách 2, mặc dù chúng ta không khởi tạo trực tiếp đối tượng customerRepository trong lớp CustomerService mà inject từ ngoài vào, nhưng lớp CustomerService vẫn chỉ làm việc được đối tượng customerRepository, do đó, cách 2 vẫn là Tightly coupling. Vậy, tightly coupling là việc một lớp TRỰC TIẾP sử dụng (phụ thuộc) trực tiếp vào thể hiện cụ thể của 1 lớp khác. TightlyCoupling

Loosely coupling:

Trái với tightly coupling, dễ dàng suy ra loosely coupling là việc một lớp KHÔNG TRỰC TIẾP sử dụng (phụ thuộc) vào thể hiện cụ thể của bất cứ 1 lớp cụ thể nào. Cho đến bây giờ vẫn chưa có 1 ví dụ nào để cho thấy loosely coupling như thế nào. Trong Java (hoặc các ngôn ngữ lập trình hướng đối tượng khác), để đạt được loosely coupling trong thiết kế, chúng ta cần sử dụng khái niệm “đa hình” (polymorphism). Tính đa hình trong lập trình hướng đối tượng là việc định nghĩa những đối tượng trừu tượng (abstraction) như abstract class hoặc interface. Những đối tượng abstraction này khai báo hoặc đưa ra quy ước (contract) và cho phép nhiều lớp đối tượng cụ thể kế thừa và định nghĩa lại hành vi cho riêng chúng.

Ví dụ về tính đa hình

Một tổ chức tiêu chuẩn ISO nào đó đưa ra định nghĩa về chiếc điện thoại: điện thoại là vật có khả năng nghe và nhận cuộc gọi. Lúc này ISO chưa hề cho ra đời 1 chiếc điện thoại nào có thể cầm nắm được, túm lại, nó chỉ là định nghĩa, để khi có người đang cầm trên tay 1 chiếc điện thoại thực sự thì họ có thể gọi hoặc nhận cuộc gọi. Sau khi đã có định nghĩa thế nào là điện thoại, các nhà sản xuất điện thoại hàng đầu thế giới mới bắt tay vào việc sản xuất ra những chiếc điện thoại theo tiêu chuẩn đã đặt ra bởi ISO. Hiện tại có 2 nhà sản xuất là Nokia và Samsung. Mục đích của họ là phải sản xuất ra những chiếc điện thoại có thể nghe và gọi được theo tiêu chuẩn ISO. Khi những chiếc điện thoại được tung ra thị trường, người sử dụng sau đó mua về và thực hiện chức năng nghe gọi mà họ đã từng được nghe ISO công bố trước đó. Tuy nhiên khi thực hiện cuộc gọi từ điện thoại Nokia thì sẽ nghe câu “Hello Microsoft” đầu tiên, còn với Samsung sẽ là câu “Lee Yong-dae” chẳng hạn. (I love Badminton). Có một nhà sản xuất nghiệp dư (giấu tên) cũng tập tành sản xuất điện thoại nhưng không tuân theo tiêu chuẩn của ISO, vậy nên khi cho ra thị trường, người ta không thể thực hiện nghe gọi, mà chỉ có thể… nghe nhạc. Vậy nên có thể gọi đây là cái máy nghe nhạc (tuân theo tiêu chuẩn của một tổ chức nào đó dành cho máy nghe nhạc), chứ không phải cái điện thoại. Phần mô tả cho đa hình đến đây là hết. Cười chút đã. =)) Do vậy, một lớp được gợi là loosely couling khi nó chỉ phụ thuộc vào các đối tượng high level (Abstract class hoặc Interface) thay vì phụ thuộc vào các lớp đối tượng cụ thể (concrete class). (Giống như việc một người tuyên bố, tui biết sử dụng tất cả điện thoại, miễn là nó có thể gọi và nghe, chứ không riêng gì cái điện thoại mà cứ phát ra câu “Lee Yong-dae”.) Ví dụ với bài Điện thoại theo chuẩn ISO ở trên

package com.edward.tutorial.di.phone;

public abstract class Phone {
	public abstract void call(String number);
	public abstract void answer(String number);
}

package com.edward.tutorial.di.phone;

public class NokiaPhone extends Phone {

	@Override
	public void call(String number) {
		System.out.println("Microsoft... " + number);
	}

	@Override
	public void answer(String number) {
		System.out.println(number + " Buy me...");
	}
}

package com.edward.tutorial.di.phone;

public class SamsungPhone extends Phone {

	@Override
	public void call(String number) {
		System.out.println("Kpop Kpop Kpop... " + number);
	}

	@Override
	public void answer(String number) {
		System.out.println(number + " I wanna cry...");
	}
}

package com.edward.tutorial.di.phone;

public class User {
	Phone phone;
	
	public User(Phone phone) {
		this.phone = phone;
	}
	
	public void bringMePhone(Phone phone) {
		this.phone = phone;
	}
	
	public void call(String number) {
		phone.call(number);
	}
	
	public void answer(String number) {
		phone.answer(number);
	}
}

package com.edward.tutorial.di.phone;

public class Main {

	public static void main(String[] args) {
		User bill = new User(new SamsungPhone());
		bill.call("0123");
		bill.bringMePhone(new NokiaPhone());
		bill.answer("0124");
	}
}

Quay lại ví dụ của chúng ta Extract CustomerRepository class thành CustomerRepository interface

package com.edward.tutorial.di.repository;

import java.util.Collection;

import com.edward.tutorial.di.model.Customer;

public interface CustomerRepository {

	public abstract Customer findOne(String customerId);

	public abstract Collection<Customer> findAll();

	public abstract void create(Customer customer);

	public abstract boolean update(Customer customer);

	public abstract void delete(Customer customer);

}

CustomerRepositoryImpl sẽ implement CustomerRepository interface

package com.edward.tutorial.di.repository;

import java.util.Collection;

import com.edward.tutorial.di.model.Customer;

public class CustomerRepositoryImpl implements CustomerRepository {
	@Override
	public Customer findOne(String customerId) {
		// Code stuff
	}

	@Override
	public Collection<Customer> findAll() {
		// Code stuff
	}

	@Override
	public void create(Customer customer) {
		// Code stuff
	}

	@Override
	public boolean update(Customer customer) {
		// Code stuff
	}

	@Override
	public void delete(Customer customer) {
		// Code stuff
	}
}

Và inject CustomerRepository interface thay vì CustomerRepositoryImpl

package com.edward.tutorial.di.service;

import java.util.Collection;

import com.edward.tutorial.di.model.Customer;
import com.edward.tutorial.di.repository.CustomerRepository;

public class CustomerService {
	
	CustomerRepository customerRepository;
	
	public CustomerService(CustomerRepository customerRepository) {
		this.customerRepository = customerRepository;
	}
	
	Collection<Customer> findAll() {
		return customerRepository.findAll();
	}

	Customer create(Customer customer) {
		customerRepository.create(customer);
		return customer;
	}
	
	Customer update(Customer customer) {
		customerRepository.update(customer);
		return customer;
	}

	void delete(String customerId) {
		Customer customer = findOne(customerId);
		customerRepository.delete(customer);
	}
	
	public Customer findOne(String customerId) {
		return customerRepository.findOne(customerId);
	}
}

LooselyCoupling

Nên design theo Tightly coupling hay Loosely coupling

Câu trả lời là Loosely coupling. Vì sao? Đọc tiếp…

Loosely coupling = Dependency Injection + Abstraction

Dependency Injection không giúp chúng ta cải thiện tính flexibility trong thiết kế. Tuy nhiên khi chúng ta kết hợp với Abstraction bằng cách inject các đối tượng abtract, thì chúng ta đã có một bản thiết kế loosely coupling và flexibility.

Dependency inversion principle

Dependency inversion principle là 1 trong 5 nguyên lý thiết kế hướng đối tượng (S.O.L.I.D). Xem thêm tại (https://edwardthienhoang.wordpress.com/2013/11/27/the-dependency-inversion-principle/) Nói đơn giản, Dependency inversion principle giúp chúng ta có được 1 thiết kế loosely coupling Dependency inversion principle = Loosely coupling = Dependency Injection + Abstraction

Inversion of Control (IoC)

Nếu như Dependency inversion là principle thì Inversion of Control là pattern tuân theo principle này. Trong Java, IoC pattern xuất hiện khá nhiều. Lấy 1 ví dụ rất quen thuộc, đó là hàm public static void main(String[] args)

package com.edward.tutorial.di;

public class Main {

    public static void main(String[] args) {
        System.out.println("Developer's dream starts from here");
        doMyWish();
    }

    private static void doMyWish() {
        System.out.println("I wish this app would be the most favourite one in the world");
    }
}

Tất cả các lập trình viên Java đều quá quen thuộc với hàm main này – entry point của 1 chương trình Java truyền thống. Lần này chúng ta sẽ không bàn đến cú pháp, mà bàn đến một việc mà được cho là “chẳng ai quan tâm là mấy”. Câu hỏi là: hàm doMyWish() được gọi bởi hàm main(), vậy hàm main() được gọi bởi hàm nào? Câu trả lời là: Java sẽ gọi hàm main() của chúng ta. Vậy làm thế nào mà Java (chính xác hơn là javac.exe hay đại loại là một cái cao siêu gì đó) có thể gọi được hàm main của chúng ta?

Hollywood principle: “Don’t call us, we’ll call you.”

Dịch nôm na: “Đừng có gọi cho tui, để lại số điện thoại, tui sẽ gọi bạn.” Ngôi sao mà, có quyền chảnh. Nếu nói Java là 1 ngôi sao Hollywood, và hàm main là 1 ai đó, thì việc chúng ta cần làm là nói với ngôi sao đó: “Đây! Địa chỉ của tui đây”. Cung cấp cho Java đường dẫn tới class com.edward.tutorial.di.Main chứa hàm main. Việc còn lại cứ để Java lo, Java sẽ gọi hàm main trong class com.edward.tutorial.di.Main và “Developer’s dream” will be started. LƯU Ý: Hollywood principle chỉ là cách gọi khác của Dependency inversion principle. Thêm 1 ví dụ dễ thấy.

JButton helloButton = new JButton("Hello");
helloButton.addActionListener(new ActionListener() {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("I would say Hello to everyone!");
    }
});

Chúng ta không hề gọi hàm actionPerformed(ActionEvent e), mà chỉ khai báo như vậy, và nói: “Hey! Java Swing or EventDispatchThread or something like that, call me when someone click the helloButton”. Một lần nữa, Java sẽ lo việc đó.

Inversion of Control Container (IoC Container)

Chúng ta đã thấy sự tuyệt vời với những đoạn code ở trên, Inversion of Control Container chính là những ngôi sao Hollywood thực thụ, họ định nghĩa ra Hollywood principle, công việc của lập trình viên là: viết ra những đoạn code và nhờ IoC Container đâu là điểm entry point Trong Eclipse, chúng ta dễ dàng config entry point cho 1 chương trình Java tại: Config_Main

Inversion of Control Container Framework (IoC Container Framework)

Trong ứng dụng Java truyền thống, IoC Container có thể được hiểu như những ví dụ ở trên. Tuy nhiên, trong những ứng dụng Java Enterprise, IoC Container mới có nhiều đất diễn, có khá nhiều Framework hỗ trợ IoC Container tạm gọi là IoC Container Framework như: JEE Framework hoặc Spring Framework. Nơi mà những khái niệm về: Dependency Injection, Inversion of Control hay Inversion of Control Container sẽ được nhắc đến như là những Core Feature. Tất cả đều hướng đến một mục đích duy nhất: tạo ra ứng dụng loosely coupling, flexibility cũng như giúp lập trình viên tập trung 99% vào công việc cho business flow.

Loosely coupling và Testing

Một lợi ích không thể nhắc đến khi thiết kế chương trình theo loosely coupling style chính là Testing. Thay vì phải inject những đối tượng thực vào trong SUT (System under test, hay nôm na là class cần test), chúng ta có thể inject các stub đã implement interface vào trong SUT. Chi tiết sẽ được bàn trong bài viết về UnitTesting. 🙂

Learn from Question&Answer

Có một bạn hỏi như sau:
Nói về chủ đề này, với DI thì ok. Bài viết này của anh khá sâu, tuy nhiên phần ioc lại chưa đc rõ rằng lắm. Vẫn còn khá chung chung. A có thể giải thích cho em vài vấn đề sau. Giữa DI và ioc
1. Thằng nào là con thằng nào?. Quan điểm con của nhau có đúng ko?.
2. Theo em đc biết, DI là 1 design pattern xây dựng lên để đáp ứng cho tính lỏng lẻo, giảm sự liên kết phụ thuộc và khi đó IoC chính là thằng thực hiện theo cái DI đó, nó sẽ sử dụng BeanFactory và ApplicationContext để thao tác lấy thông tin từ XML xử lý, tạo đối tượng. Khi đó, với quan điểm của em thì em nghĩ chẳng thằng nào là con thằng nào cả.

Answer:
Một câu hỏi khá hay. Trong cái thắc mắc của em đã trả lời luôn rồi.
Đúng như em nói: DI là 1 Design Pattern “để đáp ứng cho tính lỏng lẻo, giảm sự liên kết phụ thuộc”. IoC thì rộng hơn, và thường đi liền với Framework. Framework sẽ invert và control phần xương sống của application được develop bên trên, và “chừa”, “cung cấp” 1 số “cổng” để developer có thể inject phần implement của mình vào application. (Inject ở đây có 2 cách hiểu như 2 ví dụ dưới đây.

1. BeanFactory và ApplicationContext: em đang nói đến Spring Framework, vậy đó, Spring cho phép em inject các implementation của mình vào application qua ApplicationContext và 1 số Bean XML. Rõ ràng, DI được dùng để làm chuyện này thông qua @Autowired hay @Inject (CDI)

2. Tuy nhiên, trong bài viết của anh còn đề cập đến một chuyện đơn giản hơn. Đó là Java Swing Framework. Swing cho phép chúng ta định nghĩa ra “những action to be peformed” khi 1 event cụ thể được fired. Còn việc fire đó sẽ do Swing chứ ko phải do mình. DI không được dùng trong đây, nghĩa là Swing không cần đến pattern DI mà vẫn làm được việc Invertion of Control.
Từ 2 ví dụ trên có thể cho em hiểu Invertion Of Control là gì và mối quan hệ với DI rồi nhé.

Kết thúc bài tại đây, hi vọng trong giới hạn hiểu biết cùng với cách giải thích của mình sẽ giúp các bạn có thêm 1 cái nhìn khác về các khái niệm: Dependency Injection, Dependency Inversion Principle, IoC.. Trong những bài sau, chúng ta sẽ bàn luận về IoC Container trong Spring Framework. Happy learning

NGUỒN: HTTP://EDWARDTHIENHOANG.WORDPRESS.COM/ EMAIL: EDWARDTHIENHOANG@GMAIL.COM

Architecture, Design Pattern

We Are Complicating Things a Bit too Much (TDD & DDD)

The other day, I saw something that really encompasses one of the biggest hurdles for younger developers to get through. That hurdle is terminology. These days, there is all sorts of “___ driven development”. In our team, we even joke about “assumption driven development”.

Naming things is one of the hardest things to deal with in programming. It gets worse when we are doing something that is uncomfortable. Make it worse, before we ever started programming there are tons of people who have already named things (and naming things was hard for them too).

And see, this is where we as a community come in and can help people understand things a lot easier. Of course it doesn’t hurt if we don’t muck up some serious patterns and terminology even more (no I’m not talking about Facades, the argument over that hurt the community more).

All The Driven Development

One of the big things that bothered me the other day was hearing someone say “you thought TDD was hard, wait until you change over to using DDD”. Maybe it was out of context, but I think that at heart, a lot of young developers (especially those that are freelancing or the most senior on a small young team) get confused. It used to be information on software patterns was a bit more limited: you hear something from a close coworker, that one message board you subscribe to, a professor, a senior dev, etc then you use it. Now, we face massively social communities where everyone spouts their ideas on Twitter, G+, SO, and more. A developer that would have been slowly introduced to design patterns, Extreme Programming/Agile Development, and best practices are instead bombarded with everything at once.

So I hope to clarify some confusion of thinking that TDD (Test Driven Development) and DDD (Domain Driven Development) are somehow in competition or mutually exclusive. They aren’t in fact! So I’ll dig in to what I’ve taken out of the two methods and where they fit together.

What Is TDD

TDD is the process of writing tests based on a particular desired pieced of functionality, letting them fail. Then you write the least amount of code possible to make the test pass, then write another test. Cycle this over and over until you have finished a feature and then go back and refactor. It’s a bit simplified, I know, but this is the heart of TDD. Don’t get stuck in the mud about it! Don’t worry about techniques, code structure, etc.

Don’t let people fool you!

TDD is just the process of testing code before writing it!

What Is DDD

DDD takes a bit more explaining. You see, a Domain is a set of functionality that you are attempting to mimic that lies outside of your application. Maybe this is a physical event like an election, maybe it’s something a bit more arbitrary such as a source code project initializer. You will want to assign a Domain Expert, this could be your project manager, yourself when you put on your spec writing hat for a new side project (that is really dangerous though), but most likely, your Domain Expert will be your client. The point is, to create something, you must first understand what it is you are trying to create! DDD describes the process of consulting and deciding on explicit definitions of each piece of the domain that you are trying to mimic. And you make sure that these definitions are written before ever writing code. Then these definitions and naming structures from your domain study are used to create a more informed code base. Then when you pick your head up for the next change, error, fix, whatever: you consult with the Domain Expert and turn programming talk back into the Domain terminology.

Don’t let people fool you!

DDD is the process of being informed about the Domain before each cycle of touching code!

Mixing the Two Together

Alright, so now lets see WILL IT BLEND!? That is the question. DDD lives mostly in how you research before coding, how you name things, and how you interact with the client. On the other hand, TDD is the process of actually writing your code. So, as you can see, there is no conflict of interest between the two strategies and they fit together quite well.

Ok, I Lied… A Bit…

If you read Eric Evan’s book on Domain Driven Development and Martin Fowler’s Blog, you will see that their process of Domain Driven Development goes beyond just getting an informed view of the domain and describing it with “ubiquitous language”. They include code coverage, continuous integration, a testing strategy, and code organization as part of the DDD life cycle. While these things do happen between getting domain information from a client before coding and then translating things back to the domain expert, I’m not so sure that these are really part of DDD. Let me explain.

If as good programmers (and good DDD programmers at that), we decide to break things down into their unique single role parts we’d see a few things when examining the formation of the DDD mindset. First, is that it borrows heavily from Extreme Programming. EP was a multi pronged approach to developing software in a more iterative and maintainable fashion. It included planning phases, writing tests, using continuous integration, and more. EP claimed that code was the most important thing in a software project, and developers should be prepared to code efficiently.

Evan’s came in and took a lot from the toolbelt in front of him and created his own method to attacking software problems and he put understanding the domain first. This meant that while code was still really important, the best code in the world is only as good as the understanding of the problem you are trying to solve. At the end of the day, what makes Evan’s process unique was the communication with a Domain Expert. It’s this communication that I would argue IS DDD. Everything else was slight modifications on existing techniques.

A Word On Code Structure

I made a point that TDD as a philosophy doesn’t care how you structure your code. There are those that would probably think that this transfers to DDD as well. Unfortunately it’s a bit stranger than that. While the simplified view of DDD makes me want to say that code structure isn’t part of DDD, I can’t really tell you that. With a deep understanding of the domain and wanting to mimic the domain within the code base, your code structure will and should be influenced. Also on the other side of things, it makes the translation of software output to the domain expert much easier for you: if you are stuck remembering how this SuperDuperSoftwarePatternThing relates back to your domain, you aren’t doing yourself any favors. Stick with efficiency and mimic the language you set up when talking with the client. If things are hard to structure, that’s a sign that you may not understand the specifications for the different actors in the domain.

A Word On BDD

BDD is an implementation of TDD which brings in some aspects of DDD. BDD focuses on how to name tests and instructs that tests should start from outside interaction in. For instance if you want to go to a page and see some blog posts you’d write the test for the route, say “hey I want to see some posts”, then you’ll say “I need to get some posts from somewhere”, then keep going until collide with unit tests at the low level.

BDD also goes to the effort of giving a more conversational way of writing tests. Since many tests start from the outside of a system and work their way in, BDD lends itself well to testing a pass or fail condition for a user story or feature. This means that you describe what actors are setting up a feature to be tested and then what result is to be expected. If you caught that, you may see that BDD lends itself as a TDD strategy for teams that have a solid domain definition from DDD. BDD is also often heralded because BDD testing tools can be arguably more human readable to non-developers such as Domain Experts.

http://ryantablada.com/post/we-are-complicating-things-a-bit-too-much-(tdd-and-ddd)