What and Why Golang?

- 15 mins

Gần đây Golang nổi lên mạnh mẻ như một ngôi sao trong làng lập trình hệ thống với các lợi ích, chức năng cực kì powerful. Bài viết này mình sẻ lược qua một số điểm đáng chú ý sau của Golang, để các bạn có thể phần nào xem xét chọn Go cho dự án của mình nhé:

  1. Xét về khía cạnh technical:
    • Mức độ trưởng thành, hoàn thiện của Golang
    • Tốc độ của Golang
    • Concurrency Model và mức độ sử dụng memory resource của Golang
    • Error Handling trong Golang
    • Các Paradigms và Design Parterns mà Go hổ trợ
    • Code transparency
  2. Xét về khía cạnh business:
    • Mức độ hạnh phúc của developers
    • Tốc độ phát triển
    • Khía cạnh Human Resource
  3. Conclusion:

A. Xét về khía cạnh technical:

1. Mức độ trưởng thành, ổn định của Golang:

Để make một decision chọn một ngôn ngữ, công nghệ cho việc build một hệ thống, một service có thể chạy ổn định từ năm này qua tháng nọ thì mức độ trưởng thành, hoàn thiện của công nghệ đó là một khía cạnh đáng xem xét.

Go tuy là một ngôn ngữ còn khá trẻ, được phát triển bởi Google bắt đầu từ năm 2007 và ra phiên bản đầu tiên vào tháng 12 năm 2012. Tuy nhiên lại có độ trưởng thành và ổn định cao. Sinh sau đẻ muộn nhưng sự phát triển mạnh mẻ của cộng đồng Gopher hiện tại thực sự đáng gờm đối với các hệ sinh thái Java, C#. Go cung cấp một bộ thư viện chuẩn phong phú cùng với một hệ sinh thái open source giàu có nhờ cộng đồng lớn.

Tuy không thể so sánh được với Java, C# về độ stable nhưng với các ngôn ngữ non trẻ như Node.js chẳng hạn thì Go thực sự già dơ hơn nhiều. Go ít sự thay đổi hơn và dù có thay đổi cũng ít khi gây ảnh hưởng lớn đến version củ.

Do đó xét về mức độ trưởng thành, ổn định Go hoàn toàn xứng đáng được chọn là công nghệ chỉ xếp sau Java, C#.

2. Tốc độ của Golang:

Về điểm này thì theo cái nhân mình Go xứng đáng được đánh giá là chỉ xếp sau C, Elixir và Rust trong các ngôn ngữ phổ biến cho Back End.

Go code được complile trực tiếp sang mã máy do đó có một tốc độ bàn thờ. Trong lúc các ngôn ngữ như Java, Node.js có các yếu tố trung gian làm ảnh hưởng phần nào đến tốc độ.

Node.Js là runtime sử dụng bộ V8 của Google biên dịch code Javascript sang mã máy. Có thể nói Node.Js là một nữa thông dịch một nữa biên dịch dựa vào V8. Mặc dù Node.js optimize quá trình biên dịch bằng cách dùng cache để biên dịch nhanh hơn. Nhưng nhìn chung Node.js vẫn chủ yếu thông dịch nên có tốc độ thấp hơn đáng kể so với các ngôn ngữ biên dịch như Java hay Go.

Bên cạnh đó thì code Java được biên dịch sang các binary file. Các binary file đó lại được sử dụng trên Java Virtual Machine(JVM) cho việc thực thi. Java bytecode được thông dịch bằng JVM cuối cùng JVM mới chuyển Java bytecode sang mã máy sử dụng một Just-In-Time (JIT) compiler sau đó mới thực thi. Việc có một chút yếu tốc thông dịch cũng như yếu tố trung gian như JIT Compiler khiến cho Java có phần chậm hơn Go.

3. Concurrency Model và mức độ sử dụng memory resource của Golang

Ngoài một tốc độ bàn thờ ra thì lợi thế mạnh nhất của Golang đó chính là chức năng hổ trợ concurrency dựng sẳn trong ngôn ngữ cùng với khả năng tận dụng bộ xử lí đa lõi.

Ngày nay phần cứng máy tính đã phát triển để có nhiều lõi CPU và nhiều sức mạnh hơn, nhưng sức mạnh của máy tính hiện đại không thể được tận dụng bằng cách sử dụng các ngôn ngữ lập trình chỉ support đơn core.

Trong một số môi trường lập trình, concurrency và parallelism cho hiệu quả và hiệu năng tốt, nhưng các tính năng này là một thư viện hay framework riêng biệt, chứ không phải là một tính năng tích hợp sẳn ở cấp độ ngôn ngữ. Do đó để lập trình concurrency hay parallelism đôi lúc lại làm tăng thêm sự phức tạp khi bạn viết các ứng dụng concurrent.

Trong Go, concurrency được xây dựng sẳn và được thiết kế để viết các ứng dụng concurrent hiệu suất cao cho các máy tính hiện đại, có thể tận dụng multi proccessor.

Với hiểu biết cá nhân mình thì hiện tại các ứng dụng web sử dụng 3 Concurrency model chủ yếu đó là Assembly Line model, Parallel Worker model(đây gọi là parallel thì đúng hơn nhưng cứ tạm gọi là Concurrency model cho thuận miệng) và Communicating Sequential Processes model(CSP).

Trong quá trình học tập với Java mình chủ yếu được giới thiệu về mô hình Parallel Worker. Với mô hình này chúng ta sẻ config trước một thread pool với số lượng thread có hạn, đồng thời stack size của mỗi thread cũng được config cứng(default là 1Mb) mỗi một request tới sẻ được assign cho một worker(OS thread). Với model này trong Java chúng ta sẻ có một số vấn đề:

Mình đang làm việc chủ yếu với Node.js với concurrency model là Assembly Line(cũng được gọi là Reactive model hoặc Event Driven model). Node.js đạt được tính concurrecy nhờ vào cái Event Loop. Với mô hình này thì Node.js thực sự mạnh mẻ trong việc sử lí I/O với cơ chế Non-Blocking I/O. Nhìn chung Node.js ít gặo các vấn đề mà Java gặp phãi tuy nhiên lại gặp vấn đề lớn hơn đó là các request sẻ bị block lẫn nhau khi sử dụng các CPU-intensive programming tasks(tác vụ tính toán chuyên sâu). Nếu một service tính toán nhiều mà sử dụng Node.js thì thực sự độ trể sẻ rất cao khi có nhiều request đồng thời đến.

Sử dụng Event Loop cho quá trình xử lí concurrent request về lí thuyết sẻ giúp Node.js sử dụng ít memory hơn tuy nhiên trong thực tế trình dọn rác của Node.js tương đối kém dẫn đến ngốn ram, cpu sau một thời gian chạy mà không rõ nguyên do dù đã detect rất kĩ các nguyên nhân dẫn đến memory leak.

Golang thì sao?, concurrency model trong Golang có những điểm gì mạnh mẻ?

Go đạt được tính concurrency bằng việc sử dụng Communicating Sequential Processes(CSP) model dựa trên các tính năng được build sẳn trong Go như Go Runtine, Channel, các câu lệnh select,…

Mô hình này được implement dựa trên việc gửi và nhận message giứa các tiến trình(Go Runtines), các synchronous communication được thực hiện thông qua các channel, các channel cùng với việc sử dụng các câu lệnh select cũng giúp chúng ta chủ động hơn trong việc scheduling. Tuy rằng trong Go cũng có các vấn đề về Deadlock, Race Condition tuy nhiên Go Tool cũng support các công cụ thực sự mạnh mẻ cho việc detect các vấn đề này sớm.

Bên cạnh đó Go cũng rất tiết kiệm memory khi sử dụng các Go Rountine rất rẻ với 4kb Stack Size chi phí khởi tạo ban đầu và các Go Rountine cũng scale rất dynamic, chúng có thể scale lên đến 1Gb.

Nhìn chung về yếu tố concurrency và mức độ sử dụng memory go đang khá lợi thế với các ngôn ngữ khác. Build-in Concurrency là lý do chính cho việc sử dụng Go như một ngôn ngữ để xây dựng các hệ thống phần mềm hiệu quả cao với hiệu năng cao hơn.

Mình chưa biết Rust nên không dám phán nhiều :)))

5. Error Handling trong Golang

Golang yêu cầu kiểm tra lỗi một cách rõ ràng, mỗi một hàm nên trả lỗi và check lỗi ngay khi gọi hàm. Việc check lỗi khắp mọi nơi, nhìn chung khá vất vã. Tuy nhiên, với cá nhân mình thấy việc xử lý lỗi trên Golang là rất nhất quán và hoàn hảo, không như cách implement throw/catch truyền thống trên Node.js và Java, ngày trước mình rất bực với những exception như “null pointer exception”.

6. Các Paradigms và Design Parterns mà Go hổ trợ

Golang có thể được gọi là multi paradigm programming language.

Với các tín đồ Functional Programming, Go hổ trợ first-class functions, anonymous functions, closures gíup dễ implement các technique trong functional. Hơn nữa Gopher ưu tiên composition over inheritance phù hợp với các tín đồ functional.

Với tín đồ OOP, Go hổ trợ struct được sử dụng với một số chức năng giống với class, kế thừa dựa vào việc sử dụng các embedded struct. Bên cạnh đó Interface cũng là công cụ mạnh mẻ để implement tính Polymorphism trong OOP cũng như implement theo nguyên tắc Dependency Inversion.

7. Code Transparency

Về cú pháp Go support một code format tool chuẩn và code generate tool chuẩn đó là fmt tool. Bộ tool này phần nào giúp thống nhất code convention của tất cả Gopher thay vì dựa vào các convention các ông lớn đưa ra như AirBnB convention trong Javascript chẳng hạn. Thứ hai là một chương trình Go sẻ không compile được nếu import một package mà không sử dụng phần nào giúp code đở rối.

Về các quy ước tổ chức modules, packages thì Go nói không với circular dependencies. Mình thực sự bực mình với các thể loại circular dependencies, mỗi khi có bug hoặc vấn đề gì đó detect rất cực. Với một chương trình viết bằng Go thì chúng ta sẻ không thể compile nếu tồn tại circular dependencies.

B. Xét về khía cạnh business:

1. Mức độ hạnh phúc của developer

Tại sao mình lại đặt mức độ hạnh phúc của Developer trong khía cạnh business. Rõ ràng nếu các Engineer thực sự vui vẻ hạnh phúc thì chất lượng cũng như tốc độ phát triển sẻ cải thiện hơn so với việc sử dụng một ngôn ngữ gây khó chịu ức chế cho Developer rồi.

Golang là một ngôn ngữ tối giản, có độ biểu cảm(expressive) cao cùng với sự support tương thích với các paradigms phần nào giúp developer vui vẻ hạnh phúc hơn khi làm việc với Go. Khi tìm hiểu bạn có thể thấy được sự đơn giản trong tất cả các tính năng của Go bao gồm cả hệ thống kiểu dữ liệu, cú pháp,… . Nhiều ngôn ngữ lập trình cung cấp quá nhiều tính năng giúp Dev dễ dàng làm việc hơn nhưng vô hình chung làm cho nó trở nên phức tạp hơn, ức chế hơn. Mục tiêu thiết kế của Go là một ngôn ngữ đơn giản và chỉ cung cấp tất cả các tính năng cần thiết tối thiểu để phát triển các hệ thống phần mềm một hiệu quả, đó cũng giúp dev vui vẻ hạnh phúc hơn.

Đối với các Javascript developer thì họ cực kì thích Go ở việc Go là ngôn ngữ được xây dựng khá giống như C - ngôn ngữ mà Javascript xây dựng dựa trên đó. Họ thực sự yêu thích Golang nhờ nó cực kì strictly typing. Là ngôn ngữ static type nên khi lập trình với Go gần như là không có runtime error(trừ khi bạn quá lạm dụng reflect).

Đối với các Java/C++ developers cũng vậy, với các Java/C++ developers họ cực kì mệt mỏi vì thời gian build quá lâu. Đối với Go, là một ngôn ngữ biên dịch và static type tuy nhiên khi làm việc với Go chúng ta có cảm giác như đang làm việc với một ngôn ngữ Dynamic Type hơn. Điều đó khiến các lập trình viên Back End với Java khi chuyển quá làm Go thực sự sướng.

Bên cạnh đó Go cũng có một số thiếu xót làm các Engineer ức chế, ví dụ như không support Generic, không support các constructs như Map, Reduce,… Là một ngôn ngữ biên dịch, static type mà lại không support Generic như Java làm các Developer khó viết code reusable hơn, việc duplicate code làm họ thực sự khó chịu. Tuy nhiên cũng có một số kĩ thuật giúp chúng ta viết code generic hơn như sử dụng các Closure, Callback, Higher-Order Function và Reflect cũng phần nào nguôi ngoai được thiếu xót từ Generic và các constructs.

2. Tốc độ phát triển product

Đây là một mục tiêu rất quan trọng việc phát triển các product. Thời gian ra thị trường nhanh giúp các product tự tin thực hiện các chiến lược business hơn. Đối với các ngôn ngữ mạnh trong khoản mì ăn liền như Javascript, Ruby thì Go không có cửa so sánh. Tuy nhiên đối với các ngôn ngữ như Java, C#, C++ thì có thể Go có lợi thế hơn.

Với việc là một ngôn ngữ biên dịch, static type nhưng cảm giác như là ngôn ngữ thông dịch, dynamic type khiến cho tốc độ phát triển sản phẩm nhanh hơn đôi chút so với Java. Cùng với đó là hệ sinh thái open source ngày càng màu mở cũng nâng cao tốc độ phát triển sản phẩm hơn trước.

Lợi thế trong việc mang lại sự vui vẻ hạnh phúc cho developer cũng giúp rút ngắn thời gian ra thị trường hơn đối với các ứng dụng được xây dựng với Golang.

3. Human Resource

Golang được biết đến là ngôn ngữ đa năng, Go có thể build mobile app, system infrastructure, web app, back end,…Tuy nhiên Go vẫn chỉ sử dụng nhiều nhất cho việc xây dựng Back End cho các hệ thống. Với Go chúng ta không thể apply fullstack culture như đối với Javascript.

Tuy nhiên tính đơn giản, thực dụng của Go cũng mang lại nhiều lợi ích đáng kể trong vấn đề Human Resource. Go quá tối giản do đó việc học Go là rất nhanh, với mình một người khá chậm tuy nhiên mình tự tin sau tầm 2 tuần là tự tin làm việc được trong dự án. Do đó với Go các công ty dễ dàng đào tạo một bạn sinh viên trở thành một junior developer chất lượng sau 1-3 tháng. Cũng nhờ tính đơn giản, biểu cảm và dễ hiểu, việc transfer một service, ứng dụng với Golang cũng diễn ra rất nhanh giúp người quản lí dễ dàng hơn, linh hoạt hơn trong các giải pháp chuyển giao, backup…

Tuy nhiên với một ngôn ngữ trẻ như Go với số lượng it Developer có kinh nghiệm cũng gây khó khăn cho nhà tuyển dụng.

C. Conclusion:

Nhìn chung Go khá là imperative cá nhân mình không thích style này. Tuy nhiên với cái nhìn của một Back End developer, mình thấy ở Go là một ngôn ngữ expressive, tối giản và hiệu quả cùng với tính năng concurrent built-in và khả năng tận dụng multi-core thì Go thực sự đáng được lựa chọn cho việc xây dựng các ứng dụng back end với hiệu xuất và concurrency cao. Go support tốt các paradim, flexible và dễ module hoá, dễ layered sẻ thực sự hữu ích cho việc dựng architecture. Cùng với đó, Go là một ngôn ngữ biên dịch, static type nhưng lại flexible như một ngôn ngữ thông dịch, dynamic type sẻ giúp nâng cao hiệu suất làm việc hơn. Còn đối với các bạn thì sao, nếu có cách nhìn nào khác thì giúp mình góp ý nhé.

comments powered by Disqus
rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora