Experience

Kĩ năng “back of the envelope” dành cho các developer

Kì này, chúng ta tìm hiểu về một kĩ năng “bá đạo” mang tên Back of the Envelope. Tại sao lại gọi nó là kĩ năng của các developer “thần thánh”?

  • Phỏng vấn tuyển dụng tại cái công ty Google, Facebook, Amazon đều đòi hỏi developer có kĩ năng này.
  • Kĩ năng này không bao giờ lỗi thời, đến tầm Project Manager hay Software Architect vẫn cần. Đại ca Bob Martin – Chú Bob (Tác giả Clean Code) rất trùm sò trong kĩ năng này.
  • Kĩ năng này không chỉ hữu dụng trong lập trình, mà còn rất bổ ích trong cuộc sống.
  • Tuy đơn giản nhưng rất lại có rất ít developer biết, luyện tập và áp dụng nó

Đến đây bạn cũng tò mò kĩ năng này là gì mà sao lại ghê gớm như vậy phải không nào? Đọc hết bài viết để tìm hiểu nhé!

Back of the Envelope là cái chi?

Mặc dù nghe hầm hồ như vậy nhưng thật ra đây chỉ là kĩ năng “tính nhẩm”.

Cái tên Back of the Envelope (BotE) có nghĩa là Mặt sau Phong Bì, tức là tính nhẩm các phép đơn giản, có thể viết và tính trên một tờ giấy nhỏ, ngay trên mặt sau của phong bì.

Một mẩu phong bì là quá đủ để tính 

Ủa, vậy thì nó có gì ghê gớm? Đừng đùa! Hãy xem một câu hỏi phỏng vấn tuyển dụng của Microsoft dưới đây

  • Có bao nhiêu người lên dây đàn piano ở Chicago?

Hoặc một câu hỏi khác trong tuyển dụng của Google

  • Một chiếc xe bus có thể chứa được bao nhiêu quả bóng đánh gôn?

Để giải đáp câu hỏi này, chúng ta phải vận dụng kĩ năngBotE và tính nhẩm:

  • 1 chiếc xe buýt thông thường có chiều dài 6m, rộng 2,5m và cao 1,8m.
  • Kích thước ấy tương đương với thể tích khoảng 26.220l.
  • 1 quả bóng đánh gôn có thể tích khoảng 0,04l.
  • Như vậy chia 26.220 cho 0,04 ta sẽ có khoảng 655.000 quả bóng gôn.
  • Trừ đi chỗ ghế ngồi và các đồ vật khác, ước tính 1 xe buýt sẽ chứa được khoảng 500.000 quả bóng gôn. (Nguồn: genk)

Các bạn thấy đấy, kĩ năng tính nhẩm này không có gì phức tạp, chỉ là ước đoán, cộng trừ nhân chia. Vậy tại sao các công ty nổi tiếng lại đánh giá cao nó đến vậy? Cùng xem phần dưới nhé!

Tại sao developer phải biết kĩ năng này?

Trong ngành lập trình,  chúng ta rất hay phải đưa ra những ước tính, dự đoán (về thời gian hoàn thành công việc, performance của hệ thống,  tần số sử dụng phần cứng).

Trong Programming Pearl có kể một cố sự như sau:

Năm 1983, đại ca Bob Martin nhận được bản design của hệ thống email thiết kế cho Thế Vận Hội 1984 (Thiết kế bởi AT&T, một công ty viễn thông rất lớn).

Sau khi bỏ vài phút tính nhẩm bằng BotE, Martin tính ra rằng để hệ thống hoạt động được, một phút phải có ít nhất 120 giây.

Bản design nhanh chóng bị trả về với chủ nó.

Uncle Bob thần thánh

Thuần thục kĩ năng BotE này, ta có thể tính toán, đưa ra những ước tính chính xác về hệ thống. Giả sử thiết kế một hệ thống, ta ước đoán số lượng người sử dụng là bao nhiêu, dữ liệu cần lưu trữ chiếm dung lượng bao nhiêu, từ đó tính ra lượng phần cứng cần dùng.

Trong các ngành khác như xây dựng, cầu đường, các kĩ sư thường phải dùng kĩ năng tính toán, ước tính khá nhiều (lượng vật liệu cần sử dụng, khả năng chịu tải của nhà hay cầu). Tuy nhiên, đôi khi lập trình viên chúng ta lại hay bỏ sót những điều này, dẫn tới lỗi tràn bộ nhớ, thiếu dung lượng v…v

Áp dụng vào cuộc sống

Không chỉ dùng trong nghề nghiệp, các bạn còn có thể ứng dụng kĩ năng này để tính toán, cải thiện cuộc sống của mình.

Giả sử bạn muốn bỏ bia rượu để tiết kiệm tiền nuôi vợ con, làm sao để biết mỗi năm mình nhậu hết bao nhiêu tiền. Rất đơn giản, thử áp dụng BotE nào:

1 tuần bạn nhậu 3 buổi. 1 năm có khoảng 52 tuần, vậy là bạn nhậu 52 x 3 = 156 buổi.

Mỗi buổi bạn uống khoảng 3 chai bia (Ai tửu lượng cao hơn sửa thành 5 chai nhe). Ngoài tiệm 1 chai bia khoảng 15.000. Vậy mỗi buổi bạn tốn: 3 x 15.000 = 45.000.

Vậy cả năm bạn sẽ tốn khoảng: 156 * 45.000 = 7.020.000, tức bảy triệu đồng tiền bia một năm.

Sau 5 năm không nhậu bạn sẽ tiết kiệm được 35 triệu, đủ mua một con xe máy rồi.

Nhịn uống bia 5 năm mới đủ tiền mua xe. Thôi cứ uống tiếp đi….

Bạn cũng có thể áp dụng kĩ năng này để tính số thời gian mình bỏ ra xem JAV, Facebook là bao nhiêu (để hạn chế); số tiền mình đã chi cho gấu là bao nhiêu (đặng còn đòi quà lúc chia tay). Có ích quá còn gì??

Làm sao luyện?

Như mình đã nói, luyện kĩ năng này không quá khó. Bản chất của nó chỉ là tính toán, cộng trừ nhân chia thôi! Điều quan trọng là bạn phải tập khả năng ước đoán, cái gì không đoán được thì cứ đưa ra một con số rồi từ từ tìm hiểu sau nhé.

Các bạn có thể thử bằng cách giải một số câu đố trong cuốn Programming Pearl sau.:

  1. FedEx có dịch vự gửi dữ liệu bằng cách bỏ vào ổ cứng, gửi ổ cứng qua đường máy bay. Giả sử bạn muốn gửi 1PB (1000 TB) dữ liệu từ Hà Nội sang HCM, bạn sẽ gửi bằng Internet hay bằng FedEx.
  2. Nếu chỉ gõ phím trong Notepad, gõ bao lâu thì bạn sẽ gõ đầy dung lượng 1 ổ cứng.
  3. Giả sử thế giới chậm đi gấp 1 triệu lần. CPU thực thi 1 lệnh mất bao lâu? Ổ cứng quay hết 1 vòng mất bao lâu? Thời gian để bạn gõ tên bạn là bao lâu?

 Những câu khó hơn thì các bạn xem trang 66 trong sách nhé. Nhớ chia lời giải của mình trong phần comment nhé. (Dữ liệu đưa ra trong đề cố ý không nói rõ về dung lượng, loại ổ cứng v…v nên các bạn cứ tự đưa ra dự đoán nha).

Tài liệu đọc thêm:

Nguồn: Techtalk via toidicodedao

Book, Leadership, Tản mạn

Review sách: Thói quen thứ 8

Đã rất lâu rồi mới có thời gian để review 1 cuốn sách. Thật ra mình cũng chưa có hứng để viết lắm, mà thôi nhân lúc đang rảnh thì viết luôn chứ đợi khi có hứng thì lại không có thời gian (bận rộn cơm áo gạo tiền quá mà).

Hôm nay mình sẽ nói về cuốn Thói quen thứ 8 của Stephen R.Covey.

Nếu đọc các cảm nhận trên mạng thì sẽ có rất nhiều nơi tóm tắt ý đồ của cuốn sách như sau: “Thói quen thứ 8 là tìm ra tiếng nói của bản thân và giúp đỡ người khác tìm ra tiếng nói của họ, để từ đó chúng ta cùng phát triển trong Thời đại Thông tin, thời kỳ mà sự phụ thuộc lẫn nhau còn quan trọng hơn cả sự độc lập.

Thật ra khi đọc xong cuốn sách thì tôi vẫn không thể nắm hết được ý nghĩa của nó. Tuy nhiên, mỗi người khi tìm đọc một cuốn sách nào đó thì họ đang đi tìm kiếm câu trả lời cho một vấn đề nào đó mà họ đang băn khoăn tìm lời giải đáp. Và tôi cũng không ngoại lệ, tôi tiếp cận cuốn sách này dưới góc độ nâng cao nhận thức về quản lý. Quản lý bản thân, quản lý cấp dưới và làm việc với cấp trên.

Dưới đây là 1 số trích dẫn, hình ảnh từ cuốn sách, mục đích là để gợi nhớ. Bạn nào chưa đọc thì nên đọc và hãy làm cho riêng mình 1 bản ghi chú dựa trên cảm nhận của bản thân thì sẽ hiệu quả hơn : )

Tổng quan về 8 thói quen

tqt8-1

Mô thức

Bắt đầu từ bên trong.

https://trinhdinhlinh.com/sach/7-thoi-quen-de-thanh-dat/mo-thuc-va-nguyen-tac/

Tầm nhìn, kỷ luật, đam mê và lương tâm

Lãnh đạo là khả năng biến tầm nhìn thành hiện thực.

WARREN BENNIS

tqt8-2

Các nhà lãnh đạo hàng đầu đều có tầm nhìn, óc thực tiễn, đạo đức và lòng dũng cảm. Đây chính là bốn năng lực, bốn hình thức của sự nhận thức, là ngôn ngữ giao tiếp cần có để đạt được những kết quả lâu dài và có ý nghĩa.

Nhà lãnh đạo có tầm nhìn là người luôn biết tư duy lớn, tư duy cái mới và tư duy đột phá. Và, điều quan trọng hơn hết là họ biết giữ mối liên hệ với cấu trúc sâu rộng về nhận thức và tiềm năng sáng tạo của con người.

PETER KOESTENBAUM, Nhà triết học về quản trị

Tầm nhìn là khả năng nhìn thấy trước những gì có thể xảy ra trong công việc, sự nghiệp và trong tổ chức bằng đôi mắt của trí tuệ. Tầm nhìn có được khi chúng ta dùng trí tuệ để đưa ra khả năng đáp ứng nhu cầu. William Blake nói rằng: “Những gì hôm nay được chứng minh là đúng thì trước đó chỉ là sự tưởng tượng”. Khi một người không có tầm nhìn và không quan tâm đến việc phát triển khả năng sáng tạo của trí tuệ, họ sẽ trở thành con mồi trên con đường đi đến chủ nghĩa nạn nhân.

Tính kỷ luật là cái giá phải trả để đưa tầm nhìn đi vào thực tiễn. Đây là phần liên quan đến những thực tế khó khăn, hiển nhiên và đôi khi thật tàn nhẫn, nhưng cần phải có để biến tầm nhìn thành sự thật. Kỷ luật xuất hiện khi tầm nhìn kết hợp với sự cam kết. Đối nghịch với tính kỷ luật và sự cam kết là sự buông thả – tức sự đánh đổi những điều quan trọng nhất của cuộc sống để hưởng những thú vui hay khoái lạc nhất thời.

Sự đam mê là ngọn lửa, là sự khao khát, là sức mạnh của lòng quyết tâm, là động lực để duy trì tính kỷ luật nhằm thực hiện tầm nhìn. Sự đam mê xuất hiện khi nhu cầu của con người trùng khớp với tài năng độc nhất vô nhị của riêng họ. Khi một người không có sự đam mê trong việc đi tìm và sử dụng tiếng nói của bản thân nhằm phụng sự những mục đích cao quý, thì khoảng trống trong tâm hồn họ sẽ đầy rẫy những cảm giác không an toàn và những tiếng nói trống rỗng theo khuôn mẫu xã hội. Trong mối quan hệ và trong các tổ chức, xét theo một khía cạnh nào đó thì sự đam mê bao gồm cả lòng trắc ẩn.

Lương tâm là nhận thức nội tâm về đạo đức để phân biệt đâu là đúng và đâu là sai, là động lực để con người hướng đến ý nghĩa cuộc sống và sự cống hiến vì mục đích cao đẹp. Lương tâm là sức mạnh dẫn đường cho tầm nhìn, tính kỷ luật và sự đam mê. Lương tâm tương phản với cái tôi ích kỷ thường ngự trị trong cuộc sống của mỗi chúng ta.

Đang tính viết tiếp mấy phần sau thì chợt nhớ ra đã có người viết rất kỹ về các phần này nên thôi quyết định trích dẫn link để mọi người cùng đọc qua. (P/s: anh này có nhiều bài viết rất hay về kỹ năng sống, các bạn nên đọc thêm tại https://chienluocsong.com)

Bốn nhu cầu của con người.

https://chienluocsong.com/sachthoi-quen-thu-8-p1-bon-nhu-cau-cua-con-nguoi/

Bốn năng lực của con người:

https://chienluocsong.com/sachthoi-quen-thu-8-p2-bon-nang-luc-cua-con-nguoi/

Lãnh đạo và quản lý

https://chienluocsong.com/sachthoi-quen-thu-8-p3-lanh-dao-va-quan-ly/

Chủ động và trao quyền (MUST READ)

https://chienluocsong.com/sachthoi-quen-thu-8-p4-chu-dong-va-trao-quyen/

Vai trò của lãnh đạo

https://chienluocsong.com/sachthoi-quen-thu-8-p5-4-vai-tro-cua-lanh-dao/

Architecture, Craftsmanship

Clean Architecture: Standing on the shoulders of giants

This post is part of The Software Architecture Chronicles, a series of posts about Software Architecture. In them, I write about what I’ve learned on Software Architecture, how I think of it, and how I use that knowledge. The contents of this post might make more sense if you read the previous posts in this series.

Robert C. Martin (AKA Uncle Bob) published his ideas about Clean Architecture back in 2012, in a post on his blog, and lectured about it at a few conferences.

The Clean Architecture leverages well-known and not so well-known concepts, rules, and patterns, explaining how to fit them together, to propose a standardised way of building applications.

Standing on the shoulders of EBI, Hexagonal and Onion Architectures

The core objectives behind Clean Architecture are the same as for Ports & Adapters (Hexagonal) and Onion Architectures:

  • Independence of tools;
  • Independence of delivery mechanisms;
  • Testability in isolation.

In the post about Clean Architecture was published, this was the diagram used to explain the global idea:

cleanarchitecture-5c6d7ec787d447a81b708b73abba1680
Robert C. Martin 2012, The Clean Architecture

As Uncle Bob himself says in his post, the diagram above is an attempt at integrating the most recent architecture ideas into a single actionable idea.

Let’s compare the Clean Architecture diagram with the diagrams used to explain Hexagonal Architecture and Onion Architecture, and see where they coincide:

 

  • Externalisation of tools and delivery mechanisms

    Hexagonal Architecture focuses on externalising the tools and the delivery mechanisms from the application, using interfaces (ports) and adapters. This is also one of the core fundaments of Onion Architecture, as we can see by its diagram, the UI, the infrastructure and the tests are all in the outermost layer of the diagram. The Clean Architecture has exactly the same characteristic, having the UI, the web, the DB, etc, in the outermost layer. In the end, all application core code is framework/library independent.

  • Dependencies direction

    In the Hexagonal Architecture, we don’t have anything explicitly telling us the direction of the dependencies. Nevertheless, we can easily infer it: The Application has a port (an interface) which must be implemented or used by an adapter. So the Adapter depends on the interface, it depends on the application which is in the centre. What is outside depends on what is inside, the direction of the dependencies is towards the centre. In the Onion Architecture diagram, we also don’t have anything explicitly telling us the dependencies direction, however, in his second post, Jeffrey Palermo states very clearly that all dependencies are toward the centre. The Clean Architecture diagram, in turn, it’s quite explicit in pointing out that the dependencies direction is towards the centre. They all introduce the Dependency Inversion Principle at the architectural level. Nothing in an inner circle can know anything at all about something in an outer circle. Furthermore,when we pass data across a boundary, it is always in the form that is most convenient for the inner circle.

  • Layers

    The Hexagonal Architecture diagram only shows us two layers: Inside of the application and outside of the application. The Onion Architecture, on the other hand, brings to the mix the application layers identified by DDD: Application Services holding the use case logic; Domain Services encapsulating domain logic that does not belong in Entities nor Value Objects; and the Entities, Value Objects, etc.. When compared to the Onion Architecture, the Clean Architecture maintains the Application Services layer (Use Cases) and the Entities layer but it seems to forget about the Domain Services layer. However, reading Uncle Bob post we realise that he considers an Entity not only as and Entity in the DDD sense but as any Domain object: “An entity can be an object with methods, or it can be a set of data structures and functions.“. In reality, he merged those 2 innermost layers to simplify the diagram.

  • Testability in isolation

    In all three Architecture styles the rules they abide by provide them with insulation of the application and domain logic. This means that in all cases we can simply mock the external tools and delivery mechanisms and test the application code in insulation, without using any DB nor HTTP requests.

As we can see, Clean Architecture incorporates the rules of Hexagonal Architecture and Onion Architecture. So far, the Clean Architecture does not add anything new to the equation. However, in the bottom right corner of the Clean Architecture diagram, we can see a small extra diagram…

Standing on the shoulders of MVC and EBI

The small extra diagram in the bottom right corner of the Clean Architecture diagram explains how the flow of control works. That small diagram does not give us much information, but the blog post explanations and the conference lectures given by Robert C. Martin expand on the subject.

cleanarchitecturedesign

In the diagram above, on the left side, we have the View and the Controller of MVC. Everything inside/between the black double lines represents the Model in MVC. That Model also represents the EBI Architecture (we can clearly see the Boundaries, the Interactor and the Entities), the “Application” in Hexagonal Architecture, the “Application Core” in the Onion Architecture, and the “Entities” and “Use Cases” layers in the Clean Architecture diagram above.

Following the control flow, we have an HTTP Request that reaches the Controller. The controller will then:

  1. Dismantle the Request;
  2. Create a Request Model with the relevant data;
  3. Execute a method in the Interactor (which was injected into the Controller using the Interactor’s interface, the Boundary), passing it the Request Model;
  4. The Interactor:
    1. Uses the Entity Gateway Implementation (which was injected into the Interactor using the Entity Gateway Interface) to find the relevant Entities;
    2. Orchestrates interactions between Entities;
    3. Creates a Response Model with the data result of the Operation;
    4. Populates the Presenter giving it the Response Model;
    5. Returns the Presenter to the Controller;
  5. Uses the Presenter to generate a ViewModel;
  6. Binds the ViewModel to the View;
  7. Returns the View to the client.

The only thing here where I feel some friction and do differently in my projects is the usage of the “Presenter“. I rather have the Interactor return the data in some kind of DTO, as opposed to injecting an object that gets populated with data.

What I usually do is the actual MVP implementation, where the Controller has the responsibility of receiving and responding to the client.

Conclusion

I would not say that the Clean Architecture is revolutionary because it does not actually bring a new groundbreaking concept or pattern to the table.

However, I would say that it is a work of the utmost importance:

  • It recovers somewhat forgotten concepts, rules, and patterns;
  • It clarifies useful and important concepts, rules and patterns;
  • It tells us how all these concepts, rules and patterns fit together to provide us with a standardised way to build complex applications with maintainability in mind.

When I think about Uncle Bob work with the Clean Architecture, It makes me think of Isaac Newton. Gravity had always been there, everybody knew that if we release an apple one meter above the ground, it will move towards the ground. The “only” thing Newton did was to publish a paper making that fact explicit*. It was a “simple” thing to do, but it allowed people to reason about it and use that concrete idea as a foundation to other ideas.

In other words, I see Robert C. Martin is the Isaac Newton of software development! 🙂

Resources

2012 – Robert C. Martin – Clean Architecture (NDC 2012)

2012 – Robert C. Martin – The Clean Architecture

2012 – Benjamin Eberlei – OOP Business Applications: Entity, Boundary, Interactor

2017 – Lieven Doclo – A couple of thoughts on Clean Architecture

2017 – Grzegorz Ziemoński  – Clean Architecture Is Screaming

* I know Sir Isaac Newton did more than that, but I just want to emphasize how important I consider the views of Robert C. Martin.

From https://herbertograca.com/2017/09/28/clean-architecture-standing-on-the-shoulders-of-giants/

Architecture, Craftsmanship

Clean Architecture Is Screaming

Uncle Bob’s Clean Architecture keeps your application flexible, testable, and highlights its use cases. But there is a cost: No idiomatic framework usage!

Welcome to the fifth installment of little architecture series! So far we have covered layershexagonsonions, and features. Today, we’ll look at a close friend of all four – Uncle Bob’s Clean Architecture, initially introduced here.

What Is Clean Architecture?

Clean Architecture builds upon the previously introduced four concepts and aligns the project with best practices like the Dependency Inversion Principle or Use Cases. It also aims for a maximum independence of any frameworks or tools that might stay in the way of application’s testability or their replacement.

Clean Architecture divides our system into four layers, usually represented by circles:

  • Entities, which contain enterprise-wide business rules. You can think of them as about Domain Entities a la DDD.
  • Use cases, which contain application-specific business rules. These would be counterparts to Application Services with the caveat that each class should focus on one particular Use Case.
  • Interface adapters, which contain adapters to peripheral technologies. Here, you can expect MVC, Gateway implementations and the like.
  • Frameworks and drivers, which contain tools like databases or framework. By default, you don’t code too much in this layer, but it’s important to clearly state the place and priority that those tools have in your architecture.

Between the circles, there is a strong dependency rule – no code in the inner circle can directly reference a piece of code from the outer circle. All outward communication should happen via interfaces. It’s exactly the same dependency rule as we introduced in the Onion Architecture post.

Apart from the layers, Clean Architecture gives us some tips about the classes we need to implement. As you can see in the picture below, the flow of control from the Controller to the Use Case goes through an Input Port interface and flows to the Presenter through an Output Port interface. This ensures that the Use Case and the user interface are properly decoupled. We’ll see an example of this later in the implementation section.

The Essence of Clean Architecture

I see two things that make Clean Architecture distinct and potentially more effective than other architectural styles: strong adherence to the Dependency Inversion Principle and Use Caseorientation.

Strong Adherence to DIP

Similarly to its Onion cousin, Clean Architecture introduces the Dependency Inversion Principle at the architectural level. This way, it explicitly states the priorities between different kinds of objects in your system. In a way, Clean Architecture does a better job at this, as it leaves no doubt about the tools like frameworks or databases – they have a dedicated layer outside all others.

Use Case Orientation

Similarly to what we’ve seen in Package by FeatureClean Architecture promotes vertical slicing of the code and leaving the layers mostly at the class level. The major difference between the two is that instead of focusing on a blurry concept of a feature, it reorients the packaging towards Use Cases. This is important as, ultimately, in any application that has some sort of GUI, one could identify real Use Cases. It’s also important to note that entities sit in a different layer as in complex systems, one Use Case can orchestrate several entities to cooperate and categorizing it by the type of the entity would be artificial.

Implementing Clean Architecture

We can’t be 100% sure about how Uncle Bob would implement a Clean Architecture today, as his book about it comes out in July (I preordered it already and will do a review or rehash of this post then), but we can look at the GitHub repository of his Clean Code Case study:

Packaging

As you can see, the Entities and Use Cases layers have their own separate packages, while the other layers can be identified only conceptually. The socketserver,  http, and  view packages can be considered a part of the Frameworks and Drivers, while gateways package is a little bit ambiguous – their implementation is surely the Interface Adapters layer, but their interfaces conceptually belong to Use Cases. My guess is that the interfaces are extracted to a separate package so they can be shared between different Use Cases. But it’s just a guess!

By looking at the usecases.codecastSummeries, we can get more insight into how a complete Use Casepackage looks like. As you can see, it accommodates all classes related to the execution of a particular Use Case: the view, controller, presenter, boundaries, view and response models, and the Use Case class itself.  This might be a lot more classes than you usually see in your projects when you execute an Application Service, but that’s what it takes to go perfectly Clean.

Internals

If you dug deeper into the implementation of the project’s classes, you’d see no annotation there other than @Override. That’s because of the frameworks being at the very outer layer of the architecture – the code is not allowed to reference them directly. You might ask, how could I leverage Spring in such a project? Well, if you really wanted to, you’d have to do some XML configurations or do it using @Configuration and @Bean classes. No @Service, no @Autowired, sorry!

My Extra Advice

Pulling off a Clean Architecture might be a demanding task, especially if you worked with a Package by Layer, fat controllers kind of project before. And even if you get the idea and necessary skills to implement it, your colleagues might not. They might want to do this anyway, but simply forget to add interfaces or work around framework annotations when necessary. One way to prevent some of these issues could be to create a Maven module for each of the layers so that breaking a rule won’t even compile. At the same time, if you don’t have these already, introducing Pair Programming or Code Reviews will help you to prevent people from messing up with the dependency declarations (circular dependencies would not work, but adding Spring both to the Use Cases and Adapters module would!).

Benefits of a Clean Architecture

  • Screaming – Use Cases are clearly visible in the project’s structure
  • Flexible – you should be able to switch frameworks, databases or application servers like pairs of gloves
  • Testable – all the interfaces around let you setup the test scope and outside interactions in any way you want
  • Could play well with best practices like DDD – to be honest, I haven’t seen it so far, but I also don’t see anything stopping you from making an effective mix of DDD’s Strategic and Tactical Patterns with Clean Architecture

Drawbacks of Clean Architecture

  • No Idiomatic Framework Usage – the dependency rule is relentless in this area
  • Learning Curve – it’s harder to grasp than the other styles, especially considering the point above
  • Indirect – there will be a lot more interfaces than one might expect (I don’t see it as necessarily bad, but I’ve seen people pointing this out)
  • Heavy – in the sense that you might end up with a lot more classes than you currently have in your projects (again, the extra classes are not necessarily bad)

When to Use Clean Architecture

Before I say something, let me note that I haven’t tried implementing it in a professional context yet, so all of it is a gut feeling. We will probably get some more knowledgeable advice from Uncle Bob himself in his upcoming book.

If we consider Clean Architecture‘s biggest drawbacks and its essence, I would derive the following criteria to consider:

  • Is the team skilled and/or convinced enough? One might consider this lame, but if people just don’t get it or they don’t want to do this, imposing the rigor of Clean Architecture on them might be counter-productive.
  • Will the system outlive major framework releases? Since we’re talking about heavy technology flexibility here, it’s important to consider if we’ll ever capitalize on this benefit. My experience so far suggests that most systems will, even if the developers won’t be in the company by then.
  • Will the system outlive the developers and stakeholders employment? Since Clean Architecture is so sound and makes Use Cases so clearly visible, systems that follow its principles will be much simpler to comprehend in the code, even if those who wrote it and asked for it are already gone.

Summary

Clean Architecture looks like a very carefully thought and effective architecture. It makes the big leap of recognizing the mismatch between Use Cases and Entities and puts the former in the driving seat of our system. It also gives a clear place for Frameworks and Drivers in our system – a separate layer outside all other layers. This, combined with the dependency rule might give us a plethora of benefits, but also might be way harder to pull off. In the end, it boils down to the question whether the system will live long enough so that the investment returns.

From https://dzone.com/articles/clean-architecture-is-screaming

Chưa phân loại, Leadership

[Book] Talking with Tech Leads by Patrick Kua (Lessons Learned)

Being a good developer doesn’t necessarily make you a good Tech Lead. This book explores the delicate balance between the technical and non-technical worlds and, with over 35 accounts from Tech Leads, we can better understand some of the challenges faced and lessons learned from tech leadership across our industry.

When I started this book project, I wasn’t sure what sort of responses people would give, nor was I sure if there would be any interest in this topic. As I shared the idea with developers and potential interview candidates, the questions I posed puzzled them because they could not name many books that tackled these important issues.

Many people could reel off books and resources that described how to write better code or how to design and build robust applications. Other people knew of books and resources that taught general leadership, communication, and management theory, but developers and Tech Leads expressed frustration about their generality, lack of context, and not necessarily being entirely relevant to the Tech Lead role.

After reading through the responses in one sitting, I was fascinated by how frequently certain themes emerged and how people would return to the same topics time and time again. In this section, I summarize those recurrent themes and how they shed light on different aspects to the Tech Lead role.

Lead

Lessons Learned by First-Time Tech Leads

The transition from a role where you exclusively write code to one where writing code is only a small part is what often takes people by surprise. Here are lessons the First-Time
Tech Leads touched upon:

– Having a broader outlook – Moving beyond the thoughts of a single feature, or code and seeing the whole breadth of the team and business.

– Sensing greater responsibility – The authority that comes with the title requires greater accountability; you are accountable not only for your decisions, but the decisions and actions of each person on the team.

– Guiding the technical vision – The combination of more responsibility and a broader outlook gives rise to concerns when individuals move in different directions. You spend more time providing direction from a technical point of view.

– Coping with less time writing code – You have to redefine how you bring value to the team. You have to look at how you enable others to contribute quality code that requires little rework and delivers to business needs rather than the amount of code or features you deliver.

– Juggling more context switches – The Tech Lead role challenges your time and task-management capabilities as more people will interrupt you for clarification, guidance, and advice. Burning issues draw you away from code-writing, so you need to beware of contributing to the critical path or holding unique knowledge from the team.

– Allowing people to fail – You cannot be everywhere at once and, as much as you want to tell people the traps to avoid, you have to accept that sometimes people learn-best by failing. Instead you ensure failure has a small impact by improving the speed of feedback loops.

– Realizing people aspects are hard – As a developer, you deal with computers for most of the time. You can act grumpily and the computer doesn’t react. You realize that everyone is unique and so reacts differently to your interactions. Suddenly you are responsible for resolving conflicts when, before, you could silently slip away.

Lessons Learned by Practising Tech Leads

The seasoned Tech Lead has worked with several teams, possibly across different organisations. Their commentary often represents wisdom gained from making mistakes and learning from them, having had a chance to apply those lessons in a new context. The lessons learned from Practicing Tech Leads are summarized below.

People

– Remaining technically grounded – Other developers respect you more if you still write code with the team. Your understanding of the issues also improves if you have contact with the code.

– Finding and developing good people – As a Tech Lead you are responsible for hiring a great team. You cannot rely on hiring people in an ever-changing market and so you need to develop the people in your team and create an environment that encourages learning.

– Listening to the team – As a developer, you probably spend most of your time giving opinions. Your Tech Lead role requires you to now listen to all the opinions and find the best solution within this cacophony.

– Appreciating individual strengths – You will appreciate and sometimes be frustrated by the way people behave differently. You start to recognize different strengths and find ways and situations where people’s these are best applied.

The “Tech” of a Tech Lead

– Guiding the technical solution – A Tech Lead is responsible for everyone sharing the same technical vision. You use architecture diagrams and whiteboard sessions to help build a shared understanding within the team to help align people.

– Harmonizing team direction – Nothing is more destructive in a development team than conflict that resolves itself through the source control system, with different opinions expressed through snide commit messages, or by overwriting someone else’s style. A Tech Lead detects conflicts and differences in direction and facilitates the team to get back on track.

– Managing technical risks – Software has so many potential traps and someone must ensure they don’t get forgotten. Your role as a Tech Lead is to find ways to create visibility and shared understanding of technical risks and to find ways as a group to address them.

– Taking a longer-term view – Developers are more likely to focus on a very narrow view of their feature or contribution. Tech Leads worry more about how the choices of today will turn into the problem areas of tomorrow.

Bridging the Business with Tech

– Building trust – As a developer, you spend most of your time in the details, interacting with people from other parts of the business just enough to work out what you need to build the right feature. As you move into the Tech Lead role, you spend more time building relationships with key business stakeholders; becoming the “go to” person from the technical team.

– Finding time for technology – Bowing to the pressures from the business to add more features is easy. Ensuring that it is done in a sustainable way is one key challenge that the Tech Lead balances. Having a strong trust with the business makes this possible and translating the benefits of investing in technology helps build better understanding.

– Making technology solutions easy to understand – Software is complex in many ways, filled with terminology, constantly changing brands and ideas. As an experienced Tech Lead, you know how to simplify the technical solution and can find analogies or stories to help non-technical people understand the technical landscape enough to help them make better decisions.

– Influencing planning – When you have built strong trust and skill in simplifying technical ideas, you will inevitably be drawn into more future-focused sessions that might involve budgeting or project planning, because people see yours as an important component. You balance this carefully because more time away from the team reduces the freshness of your own information.

– Championing business needs – Sometimes technology teams drift away from understanding end users and the business models that serve them. Tech Leads bring that bigger picture back to the team, and clarify how technical solutions impact end users, and what the business goals are. With this knowledge, the team can make better trade-offs in solution-fidelity once they understand what and how a solution will be used.

You

– Adapting to new circumstances – From the responses in this book, you can see how many diverse situations Tech Lead may find themselves in and the richness of skills needed to deal with them. You must find ways to build skills you may never have had a chance to develop before.

– Making yourself redundant – Although you may find it easy to play the “Hero Tech Lead” who does everything on their own, it is not sustainable over the long term, nor does it scale to a bigger team. You focus on developing people and finding ways to delegate tasks so that you can spend more time “just being a developer”.

– Using your own strengths – Everyone has their own approach to being a Tech Lead, and when thrust into this role, you spend more time introspecting about what you can offer and apply it generously.

Final Words

I hope that you have enjoyed reading the stories from the people in my book as much as I enjoyed gathering and reflecting on them. Some people’s stories may have resonated more-strongly than others, and if you find yourself in different circumstances, I would encourage you to read the stories afresh as you may find that someone else’s stories resonate more than they did previously.

I hope my book has helped to give you a clearer understanding of what a Tech Lead role does. The Tech Lead role is very different from that of a developer. You suddenly have to balance depth of technical understanding with the people side and find time to build relationships with the business. You face new challenges building these new skills. You suddenly find yourself responsible for more people than just yourself and you discover that there is rarely any “right” answer when it comes to people.

Fortunately, you are not the first to embark on taking on this role and, with this collection of stories and lessons in hand, you will be better prepared for it.

From “Talking with tech leads” by Patrick Kua

Chưa phân loại, Leadership

5 Tips for Being an Effective Tech Lead

Becoming a Tech Lead is a tough transition for any developer, because only part of the skills and experience you had as a developer prepares you for the expectations of a new role. Instead of simply designing and writing code, a Tech Lead is suddenly responsible for an entire development team – and this means dealing with people, both technical and non-technical.

The time a developer spent focusing on writing well-designed code does not translate into the skills necessary for understanding people, resolving conflict, or suddenly having to juggle more tasks than they can possibly achieve by themselves.

Tech lead butterfly - zoomed in.png
I present 5 tips for being an effective Tech Lead.

1. Learn to Delegate

As a developer, you get a kick from working out what the hard, technical problem is to solve. You research different ways to solve the problem, seek the most simple solution and celebrate a victory when you want that red, failing test going green.

As a Tech Lead, you cannot take on all the coding tasks, and cannot take on all the hard or interesting problems, regardless of your experience. You have many more responsibilities that need time and attention, and if you are focused solely on a single task, those other responsibilities will fail to be fulfilled. When you take on the harder problems, it also misses opportunities for other developers to grow and problem solve, which will lead to frustration and potentially people leaving your team!

Of course, there are some problems when your experience and knowledge are important, but you do not want to be a bottleneck in solving problems, so you want to find a way to delegate and still be involved. Solutions might include kicking off a design session with developers to talk about general approaches, and reviewing progress with the developer on a regular basis to see if things are on track.

As you and the developer build trust with each other, you can be less involved and fully delegate an activity to let you focus on more important tasks.

2. Find Time to Code

The role is called “Tech Lead” for a reason, and it is essential that you find some time to spend in the codebase. Being involved in the code helps you build respect with the rest of the team, but it also helps keep your knowledge up to date and current with constraints, problems and the “shape” of the current codebase.

If you do not spend time with the code, you run the risk of invoking the “Ivory Tower Architect” anti-pattern, leading technical decisions without understanding their real implications for implementation or maintenance. This anti-pattern has numerous side effects including destroying trust with developers, increasing the development time of new features, and increasing the accidental complexity of your software systems.

There are many different ways a Tech Lead can find time to code, but it is essential that you make it a priority. This often means making difficult choices about where you spend your time. Tip #1 should help increase the amount of available time you have. I know some Tech Leads who will block out time in their calendar to ensure that there is always time during the week to write or review code with the other developers. I know of other Tech Leads who review commit logs, and provide feedback to developers – similar to a loose pair-programming style.

3. Visualise Your Architecture

I have worked in several teams where developers had no idea how their task fit into a bigger picture. A small technical decision made by a developer might have a wider architectural impact, but is impossible to prevent if developers do not understand the broader picture.

An effective Tech Lead often has a visual representation of their system architecture on-hand and uses it to have discussions with developers. There will often be different views of the architecture (logical, deployment, etc) and each diagram helps developers see how their task fits into a broader system architecture.

A whole-team whiteboard session is often a useful exercise for reviewing the overall architecture, as it evolves over time to meet differing requirements and the discussion during the session is even more important than the diagram. Focus on key quality attributes that drive out your architectural vision (scalability, performance, usability concerns, etc) and how they have shaped your architecture. Call out assumptions and the historical context to help developers guide their everyday decisions.

4. Spend Time 1-on-1 with Team Members

An effective Tech Lead will not be measured with how many coding tasks they complete. They are measured by how effective their software team is. Anything that a Tech Lead can do to make each person on their team better, makes the overall team better. Sit down with members on your team to understand their backgrounds, their strengths, their interests and their goals to understand how the people in your team fit together as a group. Connect developers with opportunities for them to grow. This means allowing them to take risks so they can learn and grow, but also contribute to the team. Encourage people sharing knowledge across the team and find ways to help each team member connect with each other.

5. Learn to Speak the Language of the Business

To be an effective Tech Lead, you will need a great relationship with people outside of the development team including people like Product Managers, Marketing, Sales and CxOs. They will not understand the vocabulary you accumulated as a developer, and talking to them in terms of frameworks, technical tools and platforms will only confuse them.

An effective Tech Lead finds ways for non-technical people to understand technical concepts, and the best way to do that is to find the terms that business people use and find ways to explain tasks in those terms. Use visual models, whiteboard sessions and metaphors to help business people understand technical concepts and their implications. You might rehearse on friends or relatives who don’t work in technology to see if you can succinctly explain an idea.

Minimize the translation layer as much as possible by bringing business terms into the development team and encouraging their use as much as possible. The better the developer team uses these domain terms, the better their understanding and empathy with business stakeholders will be.

Find out more about the experiences of other tech leads in Patrick‘s book ‘Talking with Tech Leads‘. You can download a free sample of the book here.​ Also, don’t miss the author’s post on Three Common Mistakes of the First Time Tech Lead.

From https://www.thoughtworks.com/insights/blog/5-tips-being-effective-tech-lead

Chưa phân loại, Craftsmanship

TDD – From the Inside Out or the Outside In?

Often the hardest part of programming is knowing where to start. With test-driven development the right place to begin is with a test, but when faced with a blank page, it can be daunting.

Is it best to start with the detail of what you are building, and let the architecture form organically using an Inside Out approach? Or, do you start with the big picture and let the details reveal themselves using Outside In?

Inside Out TDD (Bottom Up/Chicago School/Classic Approach)

Although all developers should be mindful of the bigger picture, Inside Out TDD allows the developer to focus on one thing at a time. Each entity (i.e. an individual module or single class) is created until the whole application is built up. In one sense the individual entities could be deemed worthless until they are working together, and wiring the system together at a late stage may constitute higher risk. On the other hand, focussing on one entity at a time helps parallelise development work within a team.

Taking the game Tic-Tac-Toe as an example, one solution could include at least three entities-a Board, a Prompt, and a Game.

Using the Inside Out approach, the Board and the Prompt are easily identifiable as standalone, whereas the Game integrates the entities across the whole system.

Starting with the Board, the developer can think of the functionality required for this one entity, and implement those responsibilities one test at a time.

For example, the board will need to be updated with a player’s move, so a test similar to the below can be added, and the functionality implemented.

public class BoardTest {

    @Test
    public void updateBoardWithUsersMove() {
        Board board = new Board("- - - " +
                                "- - - " +
                                "- - -");

        Board updatedBoard = board.update(1, X);

        assertThat(updatedBoard.symbolAt(1), is(X));
    }
}

The board will need to identify winning combinations, so these tests could be added one at a time in order to drill out that functionality.

    @Test
    public void hasWinningRow() {
        Board board = new Board("X X X " +
                                "- - - " +
                                "- - -");

        boolean hasWinningLine = board.hasWinningLine();

        assertThat(hasWinningLine, is(true));
    }

    @Test
    public void hasWinningColumn() {
        Board board = new Board("X - - " +
                                "X - - " +
                                "X - -");

        boolean hasWinningLine = board.hasWinningLine();

        assertThat(hasWinningLine, is(true));
    }

    @Test
    public void hasWinningDiagonal() {
        Board board = new Board("X - -" +
                                "- X -" +
                                "- - X");

        boolean hasWinningLine = board.hasWinningLine();

        assertThat(hasWinningLine, is(true));
    }

Once the Board is deemed complete, the next entity can be considered. The Prompt, which is unrelated to the Board, can be started and the developer can test that the correct wording is displayed to the screen when asking for the player’s input.

public class PromptTest {

    @Test
    public void promptsForNextMove() {
        Writer writer = new StringWriter();
        Prompt prompt = new Prompt(writer);

        prompt.askForNextMove();

        assertThat(writer.toString(), is("Please enter move:"));
    }
}

The developer is thus tackling one isolated piece of functionality at a time.

When it comes to the Game, which is the top level, all the pieces must be put together, with the individual entities interacting with each other.

public class GameTest {

   @Test
   public void gameIsOverWhenWinningMoveMade() {
     Writer writer = new StringWriter();
     Reader reader = new StringReader("6\n");
     Prompt prompt = new Prompt(reader, writer);

     Game game = new Game(prompt, new Board("X - - " +
                                            "X O O " +
                                            "- - -"));

     Board updatedBoard = game.play();

     assertThat(writer.toString(), containsString("Please enter move:"));
     assertThat(writer.toString(), containsString("Player X won!"));
     assertThat(updatedBoard.symbolAt(6), is(X));
   }
}

Because Inside Out TDD focuses initially on the individual entities of the system, the risk of these entities not interacting correctly with each other is pushed to a later stage. If the entities do not communicate as expected, there will be re-work.

From the above test case, it has become clear that a winning message needs to be printed by the prompt, detailing whether player X or O won the game. As the winning symbol is not currently available from the Board, it would need to be implemented retrospectively by adding another test to the Board entity.

    @Test
    public void hasCorrectWinningSymbol() {
        Board board = new Board("X - - " +
                                "X - - " +
                                "X - -");

        PlayerSymbol winningSymbol = board.getWinningSymbol();

        assertThat(winningSymbol, is(PlayerSymbol.X));
    }

The prompt would then require updating to provide a method which takes this winning symbol, and announces the winner.

    @Test
    public void displaysCongratulatoryMessage() {
        Writer writer = new StringWriter();
        Reader reader = new StringReader("");
        Prompt prompt = new Prompt(reader, writer);

        prompt.displayWinningMessageForPlayer(X);

        assertThat(writer.toString(), is("Player X won!"));
    }

This example demonstrates that when using Inside Out TDD, full understanding of the system design is not required at the beginning. Only one entity needs to be identified to get started. The inner details of that entity emerge through the use of specific unit tests, leading to a design that adheres well to the Single Responsibility Principle (SRP). At the initial stage, it is not always clear what behaviour needs to be exposed on an entity. This could result in more, or less behaviour being exposed than is required.

With Inside Out, if there is a cluster of entities expressing a behaviour, such as the Game, unit tests can span more than one entity (as the Board and Prompt are also being used). This means that collaborating entities can be replaced without changing the test, providing a framework for safe refactoring.

For example, if a PrettyWriter was to be used in place of a StringWriter in the Game, apart from injecting the right instance into the Game on creation, the rest of the test remains untouched.

    @Test
    public void gameIsOverWhenWinningMoveMade() {
        Writer writer = new PrettyWriter();
        Reader reader = new StringReader("6\n");
        Prompt prompt = new Prompt(reader, writer);

        Game game = new Game(prompt, new Board("X - - " +
                                               "X O O " +
                                               "- - -"));

        game.play();

        assertThat(writer.toString(), containsString("Player X won!"));
    }

It is worth noting that bug finding can prove more difficult with Inside Out as several entities need to be considered when investigating issues.

Finally, when new to a programming language then Inside Out is a good starting point. The developer only needs to focus on one entity at a time, building knowledge of the language and test framework as they go. Inside Out generally has no requirement for test doubles because the entities are all identified up front so the real implementations are available for use.

Outside In TDD (Top Down/London School/Mockist Approach)

Outside In TDD lends itself well to having a definable route through the system from the very start, even if some parts are initially hardcoded.

The tests are based upon user-requested scenarios, and entities are wired together from the beginning. This allows a fluent API to emerge and integration is proved from the start of development.

By focussing on a complete flow through the system from the start, knowledge of how different parts of the system interact with each other is required. As entities emerge, they are mocked or stubbed out, which allows their detail to be deferred until later. This approach means the developer needs to know how to test interactions up front, either through a mocking framework or by writing their own test doubles. The developer will then loop back, providing the real implementation of the mocked or stubbed entities through new unit tests.

Using the same Tic-Tac-Toe example, the implementation starts with a failing high level acceptance test for the scenario “Given the winning move is taken, the game should display a winning message”.

public class GameTest {

    @Test
    public void gameShouldEndIfThereIsAWinningRowInTheGrid() {
        Board board = new Board("X X - " +
                                "O - O " +
                                "- - -");

        PromptSpy promptSpy = new PromptSpy("2");
        Game game = new Game(promptSpy, board);

        game.play();

        assertThat(promptSpy.hasAnnouncedWinner(), is(true));
    }

This test will result in many entities being created, although initially the result could be hardcoded with the expected outcome.

public class Game {

    private Prompt prompt;

    public Game(Prompt prompt, Board board) {
        this.prompt = prompt;
    }

    public void play() {
        prompt.displaysWinningMessageFor(X);
    }
}

A PromptSpy is used in order to defer the real implementation of the Prompt until later. The GameTest can verify that the Prompt is communicating correctly. Once the interface of Prompt is defined, the developer can switch to writing unit tests for the real Prompt implementation in isolation.

Often test frameworks offer mocking functionality out of the box, and some developers prefer to write their own. This is a surprisingly straightforward task for languages such as Java, where there is strict typing, but can prove more difficult in dynamic or functional orientated languages.

class PromptSpy implements Prompt {
    boolean hasDisplayedWinningMessage = false;

    public PromptSpy(String playersMove) {
    }

    public void displaysWinningMessage() {
        hasDisplayedWinningMessage = true;
    }

    public boolean hasAnnouncedWinner() {
        return hasDisplayedWinningMessage;
    }
}

The next test shows players making moves until the game is drawn. At this point, smarter logic needs to be implemented so that the game can read in the players’ moves.

  @Test
    public void playersTakeTurnsUntilTheGameIsDrawn() {
      String seriesOfMoves = "1\n2\n5\n3\n6\n4\n7\n9\n8\n";
      PromptSpy promptSpy = new PromptSpy(seriesOfMoves);

      Board board = new Board("- - - " +
                              "- - - " +
                              "- - -");
      Game game = new Game(promptSpy, board);

      game.play();

      assertThat(promptSpy.hasAnnouncedDraw(), is(true));
      assertThat(promptSpy.numberOfTimesPlayersPromptedForMove(), is(9));
    }

This means the PromptSpy needs updating to count the number of times the players are prompted to enter their move, as well as ensuring the draw message has been displayed.

class PromptSpy implements Prompt {
    private boolean hasDisplayedWinningMessage = false;
    private boolean hasDisplayedDrawMessage = false;
    private int numberOfTimesUsersPrompted = 0;
    private final BufferedReader reader;

    public PromptSpy(String playersMove) {
        reader = new BufferedReader(new StringReader(playersMove));
    }

    public int read() {
        try {
            return Integer.valueOf(reader.readLine());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void displaysWinningMessage() {
        hasDisplayedWinningMessage = true;
    }

    public void displaysDrawMessage() {
        hasDisplayedDrawMessage = true;
    }

    public void promptUserForMove() {
        numberOfTimesUsersPrompted++;
    }

    public boolean hasAnnouncedWinner() {
        return hasDisplayedWinningMessage;
    }

    public boolean hasAnnouncedDraw() {
        return hasDisplayedDrawMessage;
    }

    public int numberOfTimesPlayersPromptedForMove() {
        return numberOfTimesUsersPrompted;
    }
}

At this point, the Game class could look something like the following.

 public class Game {

    private final Board board;
    private Prompt prompt;

    public Game(Prompt prompt, Board board) {
      this.prompt = prompt;
      this.board = board;
    }

    public void play() {

      while (board.hasFreeSpaces() && !board.hasWinner()) {
        prompt.promptUserForMove();
        board.update(prompt.read(), nextSymbol());
      }

      if (board.hasWinner()) {
        prompt.displayWinningMessageForPlayer(board.getWinningSymbol());
      } else {
        prompt.displayDrawMessage();
      }
    }
}

It can be seen through this example that when using Outside In TDD the developer needs some prior knowledge of how the entities in the system will communicate. Focus is usually on how the entities interact rather than their internal details, hence the use of high level acceptance tests. Outside In solutions often apply the Law of Demeter-a new entity is never created without the primary entity asking what it wants from it. This adheres well to the “Tell Don’t Ask” principle, and results in state only being exposed if required by other entities.

With Outside In TDD the implementation details of the design are in the tests. A change of design usually results in the tests also being changed. This may add more risk, or take more confidence to implement.

Conclusion

Both approaches form part of a developer’s tool kit. If the programming language and the domain are well known, then either approach can be successful. Because both approaches advocate good testing, they provide a safe refactoring environment which helps lead to a robust design.

Inside Out TDD favours developers who like to build up functionality one piece at a time. It can be easier to get started, following a methodical approach of identifying an entity, and drilling out its internal behaviour. With Outside In TDD, the developer starts building a whole system, and breaks it down into smaller components when refactoring opportunities arise. The path can feel more exploratory, and is ideal for situations where there is a general idea of the goal, but the finer details of implementation are less clear.

Ultimately the decision comes down to the task at hand, individual preference, and the methodology of team collaboration. If the tests are very difficult to configure, it may be a sign that the design is too complicated. Entities must be continually reviewed to look for refactoring opportunities.

The goal of each approach is the same-to build a working, reliable system with a maintainable internal design.

https://8thlight.com/blog/georgina-mcfadyen/2016/06/27/inside-out-tdd-vs-outside-in.html