Con muốn trở thành một Software Architect

Công Nghệ
Con muốn trở thành một Software Architect
Bài viết được sự cho phép của tác giả Tino Phạm Một developer trẻ nói với Chú của mình về việc cậu ta muốn trở thành một Software Architecture trong tương lai. Sau đây là cuộc nói chuyện giữa hai chú cháu. Con muốn sau này trở thành một Software Architecture (kiến trúc sư phần mềm). Con có định hướng cho mục tiêu nghề nghiệp vậy là tốt lắm đó. 10 Công cụ Go-To Tech dành riêng cho các Software Developer Biến Git và GitHub trở thành công cụ đắc lực cho Software Engineer Con muốn được dẫn đầu một nhóm và đưa ra các quyết định quan trọng như chọn loại Database nào, Framework nào, Web API thế nào và dùng những công nghệ nào cho dự án. Khá đó chứ. Nhưng nghe có vẻ như con không phải muốn trở thành Software Architecture nữa. Tất nhiên là con muốn chứ. Con muốn trở thành một người quyết định tất cả những thứ quan trọng. Chú biết vậy, nhưng mà con đang liệt kê những thứ không quan trọng. Chính xác hơn là những thứ con liệt kê nó không liên quan đến quyết định của một Software Architecture. Ý của Chú là sao? Database mà không quan trọng sao? Chú có biết phải chi bao nhiêu tiền cho chúng không? Có lẽ là rất nhiều, nhưng mà lựa chọn database không phải là một trong những quyết định quan trọng. Sao Chú nói vậy? Database là trái tim của toàn hệ thống. Nó là nơi dữ liệu được lưu trữ, sắp xếp, đánh index và được truy cập. Không có nó thì sẽ không có hệ thống. Database đơn thuần chỉ là một thiết bị IO. Nó chỉ là một công cụ hữu ích để sắp xếp, truy...

Bài viết được sự cho phép của tác giả Tino Phạm

Một developer trẻ nói với Chú của mình về việc cậu ta muốn trở thành một Software Architecture trong tương lai. Sau đây là cuộc nói chuyện giữa hai chú cháu.

Con muốn sau này trở thành một Software Architecture (kiến trúc sư phần mềm).

Con có định hướng cho mục tiêu nghề nghiệp vậy là tốt lắm đó.

Con muốn được dẫn đầu một nhóm và đưa ra các quyết định quan trọng như chọn loại Database nào, Framework nào, Web API thế nào và dùng những công nghệ nào cho dự án.

Khá đó chứ. Nhưng nghe có vẻ như con không phải muốn trở thành Software Architecture nữa.

Tất nhiên là con muốn chứ. Con muốn trở thành một người quyết định tất cả những thứ quan trọng.

Chú biết vậy, nhưng mà con đang liệt kê những thứ không quan trọng. Chính xác hơn là những thứ con liệt kê nó không liên quan đến quyết định của một Software Architecture.

Ý của Chú là sao? Database mà không quan trọng sao? Chú có biết phải chi bao nhiêu tiền cho chúng không?

Có lẽ là rất nhiều, nhưng mà lựa chọn database không phải là một trong những quyết định quan trọng.

Sao Chú nói vậy? Database là trái tim của toàn hệ thống. Nó là nơi dữ liệu được lưu trữ, sắp xếp, đánh index và được truy cập. Không có nó thì sẽ không có hệ thống.

Database đơn thuần chỉ là một thiết bị IO. Nó chỉ là một công cụ hữu ích để sắp xếp, truy vấn và báo cáo nhưng đó chỉ là những phụ trợ cho kiến trúc hệ thống.

Phụ trợ hả? Chú giởn với con đúng không.

Chú nói thật, nó là phụ trợ thôi. Những nghiệp vụ (Business logics) của hệ thống có thể được sử dụng một trong các công cụ đó, nhưng những công cụ đó không phải là bản chất của các nghiệp vụ. Nếu cần con có thể thay thế Database này thành Database khác hoặc chuyển sang dùng Framework khác, nhưng các nghiệp vụ trong hệ thống của con vẫn như vậy.

Ý của Chú là sao?

Vấn đề của con là tin rằng các nghiệp vụ của phần mềm phụ thuộc vào các công cụ của Database. Sẽ không có chuyện đó hoặc có ít thôi nếu con cung cấp kiến trúc phần mềm tốt.

Chú nói nghe khó hiểu quá. Làm sao để xây dựng các nghiệp vụ mà lại không dùng đến các công cụ mà chúng phải dùng chứ.

Chú không có nói chúng ta không dùng các công cụ của Database, Chú nói chúng ta không nên phụ thuộc vào các công cụ để phát triển dự án. Các quy tắt nghiệp vụ sẽ không cần biết loại Database nào sẽ được dùng.

Vậy làm sao để có được các nghiệp vụ sử dụng các công cụ mà lại không biết về các công cụ?

Con hãy đảo ngược sự phụ thuộc này lại. Nghĩa là con có database phụ thuộc vào các nghiệp vụ, bây giờ con làm cho các nghiệp vụ không còn phụ thuộc vào database.

Vô lý quá vậy Chú.

Bình tĩnh, Chú đang nói với tư cách là một Software Architecture. Trong thiết kế phần mềm có một nguyên lý gọi là Dependency Inversion Principle. Nguyên lý này nói là những thứ low level sẽ phụ thuộc vào những thứ high level hơn, không được ngược lại.

Khó hiểu quá! những thứ high level ( Con đoán ý Chú là các nghiệp vụ – business logics) gọi xuống những thứ low level ( Con đón ở đây là database nè). Thế thì những thứ high level phụ thuộc vào low level cũng giống như callers thì phụ thuộc vào callees. Ai cũng hiểu vậy hết chơn hết chội (ai cũng hiểu vậy cả).

Tại thời điểm runtime thì đúng (lúc chạy chương trình). Nhưng tại thời điểm compile time (lúc biên dịch code hay viết code) chúng ta muốn đảo ngược các phụ thuộc này. Source code của high level (các nghiệp vụ) sẽ không cần biết source code ở low level (code để kết nối, thao tác với database)

Sao được Chú! mình gọi một cái gì đó mà không cần biết đến nó sao được.

Được chứ. Cái đó gọi là lập trình hướng đối tượng (OOP).

Con biết lập trình hướng đối tượng nè. Lập trình hướng đối tượng là việc tạo các classes (hay objects) từ thế giới thực vào trong phần mềm, các đối tượng (objects) thì có các thuộc tính (properties) và các hành vi (behaviors). Các đối tượng tương tác với nhau bằng cách gọi các functions của nhau. OOP là một cách để tổ chức code trực quan hơn.

Con biết chỉ có vậy thôi hả?

Ai cũng biết vậy mà Chú. Nó đúng mà.

Con nói không sai. Tuy nhiên, việc sử dụng các nguyên lý của lập trình hướng đối tượng sẽ giúp cho con gọi một cái gì đó mà không cần biết tới nó.

Con đồng ý luôn, Vậy làm thế nào đây?

Con có biết trong lập trình hướng đối tượng, các đối tượng có thể gửi tin nhắn cho nhau không?

Dạ, con biết chứ.

Rồi, con có biết là sender (đối tượng gửi message) không cần biết gì về kiểu dữ liệu của receiver (đối tượng nhận message)?

Cái này còn tùy vào ngôn ngữ mình đang dùng. Trong Java thì sender ít nhất cũng biết được base type của receiver. Trong Ruby thì sender ít nhất cũng phải biết receiver có thể handler được message.

Đúng vậy, nhưng  cả hai trường hợp sender không hề biết chính xác kiểu dữ liệu của receiver.

Dạ, đúng như vậy.

Vì vậy sender có thể gọi một hàm bên trong receiver mà không cần biết chính xác kiểu dữ liệu của receiver đó.

Dạ, đúng. Con hiểu điều đó. Nhưng sender vẫn phụ thuộc và receiver.

Tại thời điểm chạy chương trình (runtime) thì đúng, nhưng lúc viết code (compile time) thì không. Source code của sender không hề biết cũng không hề phụ thuộc vào source code của receiver. Thức tế thì source code của receiver lại phụ thuộc vào source code của sender. 

Không đời nào! con nghĩ là Sender vẫn phụ thuộc vào class mà nó đang gửi message.

Xem thêm tuyển dụng Software Developer hấp dẫn trên Station D

Có lẽ chúng ta nên dùng vài dòng code để làm rõ vấn đề hơn. Chú sẽ viết cái này với Java. Đầu tiên là package sender:

package sender;

public class Sender {
  private Receiver receiver;

  public Sender(Receiver r) {
    receiver = r;
  }

  public void doSomething() {
    receiver.receiveThis();
  }

  public interface Receiver {
    void receiveThis();
  }
}

Tiếp theo sẽ là package receiver:

package receiver;

import sender.Sender;

public class SpecificReceiver implements Sender.Receiver {
  public void receiveThis() {
    //do something interesting.
  }
}

Con hãy để ý là package receiver đang phụ thuộc vào package sender. Cụ thể là class SpecificReceiver phụ thuộc vào Sender. Con cũng thấy là package Sender không hề biết bất cứ thứ gì trong package Receiver.

Dạ, nhưng Chú đã cheated code. Chú đã đặt interface của receiver bên trong class sender.

Con bắt đầu hiểu vấn đề rồi đó, khá nhanh đấy chứ.

Mà hiểu cái gì vậy Chú? ahihi

Đó là các nguyên lý của kiến trúc phần mềm. Senders sở hữu các interfaces mà receivers phải implement.

Chà..! vậy là con phải dùng các lớp lồng nhau (nested-classes).

Nested-classes chỉ là một trong những cách để đạt được điều đó. Còn nhiều cách khác nữa.

OK Chú. Bây giờ quay lại vấn đề với database mà Chú cháu mình đã nói lúc đầu đi. Chú giải quyết nó thế nào.

Con hãy xem code sau đây nhé. Đầu tiên là source code dành cho business rule.

package businessRules;

import entities.Something;

public class BusinessRule {
  private BusinessRuleGateway gateway;

  public BusinessRule(BusinessRuleGateway gateway) {
    this.gateway = gateway;
  }

  public void execute(String id) {
    gateway.startTransaction();
    Something thing = gateway.getSomething(id);
    thing.makeChanges();
    gateway.saveSomething(thing);
    gateway.endTransaction();
  }
}

Code cho nghiệp vụ ít quá vậy Chú.

Ví dụ đơn giản cho dễ hiểu thôi con trai. Con có thể thêm nhiều class mới, viết code implement cho nhiều nghiệp vụ khác nếu con muốn.

Dạ, vậy Gateway là gì thế Chú?

Nó cung cấp tất cả các phương thức (methods) để cho business rule truy cập xuống database. Code implemented của nó như sau:

package businessRules;

import entities.Something;

public interface BusinessRuleGateway {
  Something getSomething(String id);
  void startTransaction();
  void saveSomething(Something thing);
  void endTransaction();
}

Con hãy chú ý là nó nằm trong package businessRules.

Dạ, con thấy rồi. Còn lớp Something là gì vậy Chú?

Nó là  1 object của business. Chú đặt nó trong package tên là entities.

package entities;

public class Something {
  public void makeChanges() {
    //...
  }
}

Cuối cùng là viết code implement cho BusinessRuleGateway. Đây là class biết về database thực sự đang dùng. Trong ví dụ này, Chú sẽ dùng MySql.

package database;

import businessRules.BusinessRuleGateway;
import entities.Something;

public class MySqlBusinessRuleGateway implements BusinessRuleGateway {
  public Something getSomething(String id) {
    // use MySql to get a thing.
  }

  public void startTransaction() {
    // start MySql transaction
  }

  public void saveSomething(Something thing) {
    // save thing in MySql
  }

  public void endTransaction() {
    // end MySql transaction
  }
}

Một lần nữa, con hãy để ý là các business rules (nghiệp vụ) gọi database lúc runtime (chạy chương trình), nhưng lúc compile time (lúc viết code) thì database package lại phụ thuộc vào businessRules package.

Dạ dạ, con nghĩ là con đã hiểu. Chú dùng đa hình (polymorphism) để ẩn đi implementation của database package từ businessRules package. Nhưng Chú vẫn phải có một interface để cung cấp tất cả các thứ trong database mà business rule cần.

Không phải  tất cả. Chúng ta không cung cấp tất cả các thứ trong database cho business rule. Thay vào đó, chúng ta tạo các interface trong business rule chỉ cung cấp những thứ liên quan đến database mà nó cần. Các implemenations của các interfaces này có thể gọi đến các chức năng cụ thể như: insert, delete, update trên database tương ứng mà nó đang dùng.

Dạ! nhưng mà nếu như business rules cần tất cả các chức năng liên quan đến database, như vậy thì Chú phải đặt tất cả các methods đó vào trong gateway interface.

Haizz, hình như con vẫn chưa hiểu vấn đề.

Hiểu gì nữa chứ? Con hiểu quá rõ vấn đề rồi mà.

Mỗi business rule định nghĩa 1 interface để thao tác với database mà nó cần.

Chờ đã, Chú nói cái gì con chưa rõ lắm?

Cái này gọi là Interface Segregation Principle. Mỗi class business rule sẽ chỉ dùng một số chức năng để thao tác với database. Và do đó, mỗi business rule sẽ cung cấp một interface và expose một số methods để thao tác với database.

Nhưng như vậy thì Chú phải có rất nhiều interfaces và phải có rất nhiều class để implement cho các interfaces đó.

À, đúng rồi. Chú thấy giờ con đang bắt đầu hiểu rồi đó.

Nhưng code sẽ nhiều hơn, tốn thời gian hơn? Tại sao mình phải làm vậy chứ?

Thật ra, đó là cách giúp con viết code rõ ràng và tiết kiệm thời gian.

Thôi mà Chú. Điều đó làm code phình to lên và viết nhiều code hơn thì có.

Ngược lại, đây là những quyết định kiến trúc quan trọng cho phép con trì hoãn các quyết định không liên quan.

Chú nói vậy nghĩa là sao?

Nà, có phải lúc đầu con nói là con muốn trở thành một Software Architecture? Con muốn đưa ra những quyết định quan trọng phải không?

Dạ, đó là những gì con muốn.

Trong số các quyết định con đưa ra là về: database, web api và các frameworks.

Dạ đúng rồi, nhưng Chú lại nói là những quyết định đó không quan trọng. Chúng là những thứ không liên quan.

Chính xác, những quyết định này không quan trọng cũng không liên quan. Những quyết định quan trọng mà một Software Architecture đưa ra là những quyết định giúp con KHÔNG đưa ra quyết định về database nào, web api thế nào, dùng framework nào quá sớm.

Nhưng Chú cũng phải đưa ra những quyết định này trước khi làm!

Không, không nên đâu con. Thực sự thì, con cần phải làm mọi cách để làm thế nào để có thể trì hoãn các quyết định đó càng trễ càng tốt, bởi vì làm như vậy sẽ giúp con có thêm nhiều thông tin hơn.

Điều tệ hại là nếu 1 kiến trúc sư, anh ta đã quyết định sử dụng database ngay ban đầu, và sau đó nhận ra rằng chỉ cần lưu files là đủ.

Điều tệ hại là nếu 1 kiến trúc sư, anh ta ngay từ ban đầu suy nghĩ rằng sẽ build ứng dụng trên web-server, nhưng sau đó mới nhận ra rằng, tất cả các teams thực sự chỉ cần là 1 socket interface đơn giản.

Điều tệ hại là nếu 1 kiến trúc sư, anh ta và team của mình đã sớm lựa chọn framework cho dự án, và sau đó nhận ra rằng framework cung cấp nhiều cái mà họ không cần và lại ko đáp ứng hết cái họ cần rồi tự đặt mình vào thế khó.

May mắn là team mà các kiến trúc sư đã xây dựng lên kiến trúc bằng cách nào đó cho phép họ trì hoãn các quyết định đến khi họ thực sự có đủ thông tin để đưa ra lựa chọn cuối cùng.

May mắn là team mà các kiến trúc sư là người biết cách tách kiến trúc của họ ra khỏi các device IO chậm chạp, tốn resouce và các framework để có thể tạo ra các bộ test case nhanh và nhẹ.

May mắn là team mà các kiến trúc sư chỉ quan tâm đến các vấn đề thực sự quan trọng, trì hoãn những cái không quan trọng khác.

Thua luôn, con hết hiểu nổi Chú đang nói cái gì luôn rồi.

Có lẽ con sẽ cần vài năm nữa hoặc hơn… nếu con vẫn chưa thực sự đặt chân vào công việc của 1 kiến trúc sư thực thụ, cậu bé à.

Bài viết dựa theo mẫu chuyện A Little Architecture của Uncle Bob.

Bài viết gốc được đăng tải tại thangphampt.wordpress.com

Có thể bạn quan tâm:

Xem thêm việc làm IT hấp dẫn trên Station D

Bài viết liên quan

Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream

Bộ cài đặt Laravel Installer đã hỗ trợ tích hợp Jetstream

Bài viết được sự cho phép của tác giả Chung Nguyễn Hôm nay, nhóm Laravel đã phát hành một phiên bản chính mới của “ laravel/installer ” bao gồm hỗ trợ khởi động nhanh các dự án Jetstream. Với phiên bản mới này khi bạn chạy laravel new project-name , bạn sẽ nhận được các tùy chọn Jetstream. Ví dụ: API Authentication trong Laravel-Vue SPA sử dụng Jwt-auth Cách sử dụng Laravel với Socket.IO laravel new foo --jet --dev Sau đó, nó sẽ hỏi bạn thích stack Jetstream nào hơn: Which Jetstream stack do you prefer? [0] Livewire [1] inertia > livewire Will your application use teams? (yes/no) [no]: ... Nếu bạn đã cài bộ Laravel Installer, để nâng cấp lên phiên bản mới bạn chạy lệnh: composer global update Một số trường hợp cập nhật bị thất bại, bạn hãy thử, gỡ đi và cài đặt lại nha composer global remove laravel/installer composer global require laravel/installer Bài viết gốc được đăng tải tại chungnguyen.xyz Có thể bạn quan tâm: Cài đặt Laravel Làm thế nào để chạy Sql Server Installation Center sau khi đã cài đặt xong Sql Server? Quản lý các Laravel route gọn hơn và dễ dàng hơn Xem thêm Tuyển dụng lập trình Laravel hấp dẫn trên Station D

By stationd
Principle thiết kế của các sản phẩm nổi tiếng

Principle thiết kế của các sản phẩm nổi tiếng

Tác giả: Lưu Bình An Phù hợp cho các bạn thiết kế nào ko muốn làm code dạo, design dạo nữa, bạn muốn cái gì đó cao hơn ở tầng khái niệm Nếu lập trình chúng ta có các nguyên tắc chung khi viết code như KISS , DRY , thì trong thiết kế cũng có những nguyên tắc chính khi làm việc. Những nguyên tắc này sẽ là kim chỉ nam, nếu có tranh cãi giữa các member trong team, thì cứ đè nguyên tắc này ra mà giải quyết (nghe hơi có mùi cứng nhắc, mình thì thích tùy cơ ứng biến hơn) Tìm các vị trí tuyển dụng designer lương cao cho bạn Nguyên tắc thiết kế của GOV.UK Đây là danh sách của trang GOV.UK Bắt đầu với thứ user cần Làm ít hơn Thiết kế với dữ liệu Làm mọi thứ thật dễ dàng Lặp. Rồi lặp lại lần nữa Dành cho tất cả mọi người Hiểu ngữ cảnh hiện tại Làm dịch vụ digital, không phải làm website Nhất quán, nhưng không hòa tan (phải có chất riêng với thằng khác) Cởi mở, mọi thứ tốt hơn Bao trừu tượng luôn các bạn, trang Gov.uk này cũng có câu tổng quát rất hay Thiết kế tốt là thiết kế có thể sử dụng. Phục vụ cho nhiều đối tượng sử dụng, dễ đọc nhất nhất có thể. Nếu phải từ bỏ đẹp tinh tế – thì cứ bỏ luôn . Chúng ta tạo sản phẩm cho nhu cầu sử dụng, không phải cho người hâm mộ . Chúng ta thiết kế để cả nước sử dụng, không phải những người đã từng sử dụng web. Những người cần dịch vụ của chúng ta nhất là những người đang cảm thấy khó sử dụng dịch...

By stationd
Hiểu về trình duyệt – How browsers work

Hiểu về trình duyệt – How browsers work

Bài viết được sự cho phép của vntesters.com Khi nhìn từ bên ngoài, trình duyệt web giống như một ứng dụng hiển thị những thông tin và tài nguyên từ server lên màn hình người sử dụng, nhưng để làm được công việc hiển thị đó đòi hỏi trình duyệt phải xử lý rất nhiều thông tin và nhiều tầng phía bên dưới. Việc chúng ta (Developers, Testers) tìm hiểu càng sâu tầng bên dưới để nắm được nguyên tắc hoạt động và xử lý của trình duyệt sẽ rất hữu ích trong công việc viết code, sử dụng các tài nguyên cũng như kiểm thử ứng dụng của mình. Cách để npm packages chạy trong browser Câu hỏi phỏng vấn mẹo về React: Component hay element được render trong browser? Khi hiểu được cách thức hoạt động của trình duyệt chúng ta có thể trả lời được rất nhiều câu hỏi như: Tại sao cùng một trang web lại hiển thị khác nhau trên hai trình duyệt? Tại sao chức năng này đang chạy tốt trên trình duyệt Firefox nhưng qua trình duyệt khác lại bị lỗi? Làm sao để trang web hiển thị nội dung nhanh và tối ưu hơn một chút?… Hy vọng sau bài này sẽ giúp các bạn có một cái nhìn rõ hơn cũng như giúp ích được trong công việc hiện tại. 1. Cấu trúc của một trình duyệt Trước tiên chúng ta đi qua cấu trúc, thành phần chung và cơ bản nhất của một trình duyệt web hiện đại, nó sẽ gồm các thành phần (tầng) như sau: Thành phần nằm phía trên là những thành phần gần với tương tác của người dùng, càng phía dưới thì càng sâu và nặng về xử lý dữ liệu hơn tương tác. Nhiệm...

By stationd
Thị trường EdTech Vietnam- Nhiều tiềm năng nhưng còn bị bỏ ngỏ tại Việt Nam

Thị trường EdTech Vietnam- Nhiều tiềm năng nhưng còn bị bỏ ngỏ tại Việt Nam

Lĩnh vực EdTech (ứng dụng công nghệ vào các sản phẩm giáo dục) trên toàn cầu hiện nay đã tương đối phong phú với nhiều tên tuổi lớn phân phối đều trên các hạng mục như Broad Online Learning Platforms (nền tảng cung cấp khóa học online đại chúng – tiêu biểu như Coursera, Udemy, KhanAcademy,…) Learning Management Systems (hệ thống quản lý lớp học – tiêu biểu như Schoology, Edmodo, ClassDojo,…) Next-Gen Study Tools (công cụ hỗ trợ học tập – tiểu biểu như Kahoot!, Lumosity, Curriculet,…) Tech Learning (đào tạo công nghệ – tiêu biểu như Udacity, Codecademy, PluralSight,…), Enterprise Learning (đào tạo trong doanh nghiệp – tiêu biểu như Edcast, ExecOnline, Grovo,..),… Hiện nay thị trường EdTech tại Việt Nam đã đón nhận khoảng đầu tư khoảng 55 triệu đô cho lĩnh vực này nhiều đơn vị nước ngoài đang quan tâm mạnh đến thị trường này ngày càng nhiều hơn. Là một trong những xu hướng phát triển tốt, và có doanh nghiệp đã hoạt động khá lâu trong ngành nêu tại infographic như Topica, nhưng EdTech vẫn chỉ đang trong giai đoạn sơ khai tại Việt Nam. Tại Việt Nam, hệ sinh thái EdTech trong nước vẫn còn rất non trẻ và thiếu vắng nhiều tên tuổi trong các hạng mục như Enterprise Learning (mới chỉ có MANA), School Administration (hệ thống quản lý trường học) hay Search (tìm kiếm, so sánh trường và khóa học),… Với chỉ dưới 5% số dân công sở có sử dụng một trong các dịch vụ giáo dục online, EdTech cho thấy vẫn còn một thị trường rộng lớn đang chờ được khai phá. *** Vừa qua Station D đã công bố Báo cáo Vietnam IT Landscape 2019 đem đến cái nhìn toàn cảnh về các ứng dụng công...

By stationd