Home Blog Page 14

Ngôn ngữ Ruby là gì? Tìm hiểu chi tiết về ngôn ngữ lập trình Ruby

Ngôn ngữ Ruby

Trong thế giới lập trình đa dạng, Ruby nổi lên như một ngôn ngữ lập trình độc đáo và đầy tiềm năng. Được ra mắt vào năm 1995 bởi Yukihiro Matsumoto, ngôn ngữ Ruby nhanh chóng thu hút sự chú ý của giới lập trình viên bởi sự linh hoạt, dễ sử dụng và khả năng hướng đối tượng mạnh mẽ.

Bài viết này sẽ giúp bạn hiểu rõ hơn về ngôn ngữ lập trình Ruby, từ khái niệm, các đặc điểm nổi bật, cho đến những ứng dụng thực tiễn và lý do tại sao Ruby là ngôn ngữ bạn nên học. Hãy cùng khám phá và tìm hiểu chi tiết về ngôn ngữ lập trình đầy tiềm năng này.

Ngôn ngữ lập trình Ruby là gì?

Ruby là một ngôn ngữ lập trình hướng đối tượng, linh hoạt và dễ đọc, được phát triển bởi Yukihiro Matsumoto vào giữa những năm 1995. Mục tiêu của Ruby là mang lại sự đơn giản và hiệu quả, giúp lập trình viên có thể viết mã một cách tự nhiên và dễ hiểu. Với cú pháp rõ ràng và gần gũi với ngôn ngữ tự nhiên, Ruby giúp giảm bớt gánh nặng lập trình và tăng cường khả năng sáng tạo của người viết mã.

Ngôn ngữ lập trình Ruby

Đặc biệt, Ruby nổi tiếng với framework Ruby on Rails, một công cụ mạnh mẽ giúp phát triển ứng dụng web nhanh chóng và hiệu quả. Sự kết hợp giữa tính đơn giản, mạnh mẽ và cộng đồng hỗ trợ nhiệt tình đã làm cho Ruby trở thành một lựa chọn phổ biến trong giới lập trình viên.

Ứng dụng của ngôn ngữ Ruby

Ngôn ngữ Ruby được ứng dụng rộng rãi trong nhiều lĩnh vực nhờ tính linh hoạt, dễ sử dụng và khả năng mở rộng mạnh mẽ. Dưới đây là một số ứng dụng tiêu biểu của Ruby:

1. Phát triển Web với Ruby on Rails

Ruby on Rails (RoR): Đây là framework web nổi tiếng nhất của Ruby, giúp các nhà phát triển xây dựng các ứng dụng web một cách nhanh chóng và hiệu quả. Ruby on Rails cung cấp các công cụ mạnh mẽ và thư viện phong phú, giúp giảm bớt công việc lặp đi lặp lại và tập trung vào logic kinh doanh.

Các dự án nổi bật: Nhiều ứng dụng và website lớn đã được xây dựng bằng Ruby on Rails, bao gồm GitHub, Airbnb, Shopify, và Basecamp. Những dự án này minh chứng cho khả năng mở rộng và tính ổn định của Ruby on Rails.

2. Xử lý dữ liệu và scripting

Data Processing

Ruby được sử dụng rộng rãi trong việc viết các script để tự động hóa các tác vụ lặp lại, xử lý dữ liệu và tạo báo cáo. Khả năng dễ đọc và viết của Ruby giúp việc xử lý dữ liệu trở nên dễ dàng hơn.

Data Processing: Ruby có thể được sử dụng để phân tích và xử lý dữ liệu, đặc biệt là với các thư viện mạnh mẽ như Nokogiri để xử lý XML và HTML, hay CSV để xử lý các tập tin CSV.

3. Automation và DevOps

Ruby được sử dụng trong các công cụ tự động hóa và quản lý cấu hình như Chef và Puppet. Những công cụ này giúp quản lý các hệ thống và cấu hình máy chủ một cách tự động, giảm thiểu sai sót và tiết kiệm thời gian.

Chef và Puppet: Đây là hai công cụ DevOps nổi tiếng được viết bằng Ruby, giúp quản trị viên hệ thống tự động hóa việc quản lý cấu hình, triển khai ứng dụng và giám sát hệ thống.

4. Phát triển ứng dụng di động

RubyMotion: Đây là một công cụ cho phép các nhà phát triển viết ứng dụng iOS và Android bằng Ruby. RubyMotion cung cấp một môi trường phát triển tích hợp, cho phép viết mã Ruby và biên dịch thành các ứng dụng di động gốc.

Nhờ vào tính linh hoạt và dễ sử dụng, Ruby đã trở thành một công cụ mạnh mẽ trong nhiều lĩnh vực khác nhau, từ phát triển web, xử lý dữ liệu, tự động hóa đến phát triển ứng dụng di động. Sự phổ biến của Ruby và Ruby on Rails minh chứng cho khả năng và tiềm năng của ngôn ngữ này trong ngành công nghệ.

  Lộ trình trở thành Ruby Developer cho người mới bắt đầu

  Những điều cần biết về Ruby on Rail developer

Ưu và nhược điểm của ngôn ngữ lập trình Ruby

Ruby là ngôn ngữ lập trình tuyệt vời với nhiều ưu điểm nổi bật. Tuy nhiên, cũng cần lưu ý đến một số nhược điểm của Ruby trước khi sử dụng. Hãy cùng TopDev điểm qua một số ưu nhược điểm nổi bật của Ruby dưới đây:

1. Ưu điểm của ngôn ngữ Ruby

  • Cú pháp dễ đọc và dễ viết: Ruby có cú pháp gần gũi với ngôn ngữ tự nhiên, giúp lập trình viên dễ dàng hiểu và viết mã. Điều này làm giảm bớt thời gian học tập và tăng năng suất làm việc.
  • Tính hướng đối tượng mạnh mẽ: Ruby là ngôn ngữ lập trình hướng đối tượng, với mọi thứ đều là đối tượng. Điều này giúp cấu trúc mã trở nên rõ ràng, dễ bảo trì và mở rộng.
  • Ruby on Rails: Framework Ruby on Rails là một trong những lý do chính khiến Ruby trở nên phổ biến. Rails giúp việc phát triển các ứng dụng web trở nên nhanh chóng và hiệu quả, với nhiều công cụ và thư viện hỗ trợ sẵn có.
  • Cộng đồng mạnh mẽ: Ruby có một cộng đồng lập trình viên rất tích cực và hỗ trợ, với nhiều tài liệu, thư viện (gems), và plugin được phát triển liên tục. Điều này tạo điều kiện thuận lợi cho việc học tập và giải quyết các vấn đề kỹ thuật.
  • Thư viện phong phú: Ruby có nhiều thư viện và gem hỗ trợ cho hầu hết các nhu cầu lập trình, từ web development, automation, đến data processing.
  • Khả năng mở rộng và tùy biến: Ruby cho phép lập trình viên mở rộng và tùy biến các thành phần của ngôn ngữ, từ các lớp cơ bản đến các thư viện và framework. Điều này giúp đáp ứng tốt các yêu cầu đặc thù của dự án.

Ruby on Rails

2. Nhược điểm của ngôn ngữ Ruby

  • Hiệu suất: So với một số ngôn ngữ lập trình khác như C++ hay Java, Ruby có hiệu suất thấp hơn. Điều này có thể là một vấn đề khi xử lý các tác vụ yêu cầu tính toán cao hoặc xử lý nhiều dữ liệu lớn.
  • Tiêu thụ tài nguyên: Ruby tiêu thụ nhiều tài nguyên hệ thống hơn, đặc biệt là bộ nhớ. Điều này có thể gây ra vấn đề khi triển khai ứng dụng trên các hệ thống có tài nguyên hạn chế.
  • Độ phổ biến và nhu cầu thị trường: So với các ngôn ngữ phổ biến khác như JavaScript, Python, hay Java, Ruby có ít cơ hội việc làm hơn, đặc biệt là ở một số thị trường nhất định. Điều này có thể làm giảm khả năng tìm kiếm việc làm cho lập trình viên Ruby.
  • Khó khăn trong việc bảo trì mã nguồn: Do tính linh hoạt cao, mã Ruby có thể trở nên khó bảo trì nếu không được viết cẩn thận. Các tính năng như monkey patching có thể dẫn đến các lỗi khó phát hiện và sửa chữa.

Tham khảo tuyển dụng Ruby on rails lương cao trên TopDev

So sánh Ruby với Python: Nên chọn ngôn ngữ lập trình nào?

RubyPython đều là những ngôn ngữ lập trình hướng đối tượng, dễ họcphổ biến, được sử dụng rộng rãi trong nhiều lĩnh vực như phát triển web, phân tích dữ liệu, lập trình khoa học và tự động hóa. Tuy nhiên, hai ngôn ngữ này cũng có những điểm khác biệt riêng về cú pháp, hiệu suất, cộng đồng và ứng dụng, dẫn đến những lựa chọn phù hợp cho từng đối tượng người dùng khác nhau.

Dưới đây là bảng so sánh chi tiết giữa Ruby và Python:

Ruby Python
Cú pháp Linh hoạt, gần gũi với ngôn ngữ tự nhiên Rõ ràng, nhất quán, dễ đọc và dễ bảo trì
Hiệu suất Chậm hơn so với nhiều ngôn ngữ khác, đặc biệt là trong tác vụ yêu cầu cao Tốt hơn Ruby trong nhiều trường hợp, có thể tối ưu hóa với thư viện như NumPy
Cộng đồng Nhiệt tình, đặc biệt xung quanh Ruby on Rails Rất lớn và đa dạng, nhiều tài liệu học tập và tài nguyên miễn phí
Ứng dụng thực tiễn Phát triển web (Ruby on Rails), Automation và DevOps (Chef, Puppet) Khoa học dữ liệu, học máy (Pandas, TensorFlow, Scikit-learn), phát triển web (Django, Flask), Automation và scripting
Khả năng mở rộng và bảo trì Linh hoạt, nhưng có thể khó bảo trì nếu không được quản lý tốt Nhất quán và rõ ràng, dễ bảo trì và mở rộng
Tiêu thụ tài nguyên Tiêu thụ nhiều tài nguyên hệ thống, đặc biệt là bộ nhớ Sử dụng ít tài nguyên hơn so với Ruby, nhưng không phải ngôn ngữ tiết kiệm nhất
Framework phổ biến Ruby on Rails Django, Flask
Thư viện phổ biến Nhiều gem hỗ trợ phát triển web và DevOps Thư viện mạnh mẽ cho khoa học dữ liệu, học máy, xử lý dữ liệu
Cơ hội việc làm Ít cơ hội hơn so với Python, nhưng vẫn phổ biến trong phát triển web Rất nhiều cơ hội trong nhiều lĩnh vực khác nhau

Tiềm năng phát triển và mức lương của lập trình viên Ruby

Nhu cầu tuyển dụng lập trình viên Ruby tại Việt Nam đang tăng cao do sự phát triển mạnh mẽ của ngành công nghệ thông tin, đặc biệt là lĩnh vực phát triển web và ứng dụng di động. Ruby on Rails, framework web phổ biến nhất được xây dựng dựa trên Ruby, ngày càng được nhiều doanh nghiệp lựa chọn cho các dự án của mình.

Bên cạnh đó, Ruby có cộng đồng lập trình viên lớnhoạt động tích cực tại Việt Nam, luôn sẵn sàng chia sẻ kiến thức và hỗ trợ lẫn nhau. Điều này giúp các lập trình viên Ruby dễ dàng học hỏi, nâng cao kỹ năng và tìm kiếm cơ hội việc làm.

Về mức lương, lập trình viên Ruby có mức lương cao so với mặt bằng chung của ngành lập trình. Theo BÁO CÁO THỊ TRƯỜNG IT VIỆT NAM 2023 của TopDev, mức lương của Ruby Developer cấp bậc Junior (1 – 2 năm) và Middle Level (3-4 năm) lần lượt là 888 USD và 1.590 USD.

Kết luận

Vậy là TopDev đã tổng hợp đầy đủ các thông tin chi tiết về ngôn ngữ Ruby. Hy vọng những chia sẻ này sẽ giúp bạn đưa ra lựa chọn phù hợp cho con đường lập trình của mình. Nếu có hứng thú về ngành công nghệ thông tin, hãy đón chờ thêm nhiều bài viết hấp dẫn khác từ TopDev nhé!

Xem thêm:

Xem thêm các việc làm IT lương cao hấp dẫn tại TopDev

Tất tần tật về các loại toán tử trong Python

toán tử trong Python

Trong lập trình, toán tử có thể hiểu là một hàm với các toán hạng là các giá trị đầu vào (input), thực hiện một số các phép toán cụ thể và trả về một giá trị đầu ra (output). Mỗi toán tử được quy định với các ký hiệu, biểu tượng riêng đặc trưng trong từng ngôn ngữ lập trình.

Hầu hết các ngôn ngữ lập trình đều sẽ hỗ trợ các loại toán tử cơ bản giống nhau. Với một ngôn ngữ mạnh về khả năng tính toán như Python, việc nắm được các loại toán tử và sử dụng chúng là điều cực kỳ quan trọng để tối ưu source code dự án. Bài viết hôm nay chúng ta cùng tìm hiểu xem Python hỗ trợ những loại toán tử nào và cách sử dụng chi tiết từng loại toán tử đó nhé. 

Giới thiệu về toán tử Python

Trong Python, các toán tử được khai báo bằng các biểu tượng, từ khóa tương tự như các ký hiệu toán học giúp dễ dàng ghi nhớ và sử dụng. Các phép toán cơ bản cộng (+), trừ (-), nhân (*) hay chia (/) được sử dụng với ý nghĩa tương tự như khi chúng ta làm toán. Ngoài ra còn có các toán tử thao tác logic giúp chúng ta dễ dàng xử lý với biến được Python thêm vào để sử dụng.

toán tử Python

 

Thành phần của một toán tử bao gồm các toán hạng và ký hiệu toán tử tương ứng. Trong Python, khái niệm toán tử một ngôi là phép toán hoạt động với chỉ một toán hạng, tức là chỉ có duy nhất một giá trị đầu vào. Ví dụ như phép phủ định hay thao tác đảo ngược bit. Tương tự thì toán tử hai ngôi là phép toán hoạt động với 2 toán hạng, là loại toán tử phổ biến nhất.

Python còn có khái niệm toán tử ba ngôi (ternary operator) được sử dụng trong việc viết rút gọn mã nguồn, chẳng hạn như câu điều kiện (if/ else). Tuy nhiên loại này mình sẽ không được đề cập trong bài viết này nhé.

Các loại toán tử trong Python

Dựa trên chức năng, toán tử trong Python được chia thành 7 loại bao gồm:

1. Toán tử số học – Arithmetic Operators

Toán tử số học là những phép tính gần gũi với chúng ta nhất, được sử dụng để thực hiện các phép toán số học trên các toán hạng. 

Ví dụ với 2 biến a = 12b = 5, chúng ta có các toán tử như bảng dưới đây:

Ký hiệu Toán tử Mô tả Ví dụ
+ Phép cộng Cộng 2 toán hạng với nhau a+b = 17
Phép trừ Trừ 2 toán hạng với nhau a-b = 7
* Phép nhân Nhân 2 toán hạng với nhau a*b = 60
/ Phép chia Chia 2 toán hạng với nhau a/b = 2.4
% Phần dư Lấy phần dư còn lại sau khi thực hiện chia 2 toán hạng a%b = 2
** Phép mũ Thực hiện phép tính mũ toán hạng bởi số mũ a**b = 248832
// Làm tròn Thực hiện làm tròn xuống phép chia 2 toán hạng a//b = 2

2. Toán tử quan hệ – Relational Operators

Toán tử quan hệ là những phép toán thực hiện việc so sánh giá trị của hai toán hạng; kết quả đầu ra sẽ chỉ cho ra giá trị đúng (True) hoặc sai (False).

 Ví dụ với 2 biến a = 12b = 5, chúng ta có các toán tử như bảng dưới đây:

Lưu ý: toán tử <> (có giá trị tương tự với toán tự !=) đã bị bỏ đi ở Python 3 nên mình không liệt kê vào đây.

Ký hiệu Toán tử Mô tả Ví dụ
== So sánh bằng Trả về True nếu 2 toán hạng bằng nhau a==b => False
!= So sánh khác Trả về True nếu 2 toán hạng khác nhau a!=b => True
< Nhỏ hơn Trả về True nếu toán hạng bên trái nhỏ hơn toán hạng bên phải a<b => False
> Lớn hơn Trả về True nếu toán hạng bên trái lớn hơn toán hạng bên phải a>b => True
>= Lớn hơn hoặc bằng Trả về True nếu toán hạng bên trái lớn hơn hoặc bằng toán hạng bên phải a>=b => True
<= Nhỏ hơn hoặc bằng Trả về True nếu toán hạng bên trái nhỏ hơn hoặc bằng toán hạng bên phải a<=b => False

3. Toán tử gán – Assignment Operators

Toán tử gán là những phép toán lấy đầu vào là giá trị ở phía bên phải của nó và gán giá trị đó cho toán hạng ở phía bên trái. Python hỗ trợ toán tử gán bằng (=) và một số toán tử gán phức hợp khác (thực hiện phép toán trước khi gán) tương tự như các ngôn ngữ lập trình khác.

Ví dụ với biến a = 12, chúng ta có các toán tử như bảng dưới đây:

Ký hiệu Toán tử Mô tả Ví dụ
= Gán bằng Gán giá trị của một đối tượng cho một giá trị a=13 => Giá trị a = 13
+= Cộng bằng Thực hiện phép cộng rồi gán a+=2 => a = 14
-= Trừ bằng Thực hiện phép trừ rồi gán a-=2 => a = 10
*= Nhân bằng Thực hiện phép nhân rồi gán a*=2 => a = 24
/= Chia bằng Thực hiện phép chia rồi gán a/=3 => a = 4
%= Phần dư bằng Thực hiện phép lấy phần dư rồi gán a%=5 => a = 2
**= Mũ bằng Thực hiện phép mũ rồi gán a**=2 => a = 144
//= Chia làm tròn bằng Thực hiện phép chia làm tròn rồi gán a//=1 => a = 1

  Cấu trúc dữ liệu List trong Python và các thao tác cơ bản

  Phương thức List append() trong Python

4. Toán tử logic – Logical Operators

Toán tử logic là những toán tử thực hiện phép toán logic trên các toán hạng. Khác với một số ngôn ngữ dùng ký tự cho phép toán logic như C, Java, JS, … thì Python sử dụng từ khóa tường minh cho toán tử logic.

Ký hiệu Toán tử Mô tả Ví dụ
and Phép và Trả về kết quả True khi cả 2 điều kiện đều True 5>4 and 4<3 => False
or Phép hoặc Trả về kết quả True khi 1 trong 2 điều kiện là True 5>4 or 4<3 => True
not Phép phủ định Đảo ngược trạng thái logic của toán hạng not(4<3) => True

5. Toán tử bitwise – Bitwise Operators

Toán tử bitwise là các phép toán được thực hiện trên các chuỗi bit hay số nhị phân tại cấp độ của từng bit riêng biệt. Thao tác trên từng bit được thực hiện nhanh và hỗ trợ trực tiếp bởi CPU.

Ví dụ với 2 biến a = 12b = 15, khi biểu diễn dưới hệ nhị phân chúng ta có: a = 00001100b = 00001111.

Ký hiệu Toán tử Mô tả Ví dụ
& Thao tác bit AND Sao chép một bit tới kết quả nếu bit này tồn tại trong cả hai toán hạng a&b = 00001100 => 12
| Thao tác bit OR Sao chép một bit tới kết quả nếu bit này tồn tại trong bất kỳ toán hạng nào a|b = 00001111 => 14
^ Thao tác bit XOR Sao chép những bit 1 chỉ tồn tại trong một toán hạng a^b = 00000010 => 2
~ Thao tác bit NOT Thao tác đảo ngược bit 1 thành 0 và ngược lại ~a = -00001101 => -13
<< Dịch chuyển trái Dịch chuyển sang trái 1 số lượng bit được xác định a<<2 = 00110000 => 48
>> Dịch chuyển phải Dịch chuyển sang trải 1 số lượng bit được xác định a>>2 = 00000011 => 3

6. Toán tử định danh – Indentity Operators

Toán tử định danh trong Python giúp so sánh vị trí ô nhớ của 2 đối tượng trong Python, bao gồm 2 toán tử:

  • is: Trả về True nếu như các biến ở 2 bên toán tử trỏ về cùng 1 đối tượng
  • is not:  Trả về False nếu các biến ở 2 bên toán tử trỏ về cùng 1 đối tượng

Ví dụ: a=10; b=25; c=10;

  • a is b => False
  • a is c => True
  • a is not b => True

7. Toán tử membership – Membership Operators

Toán tử membership trong Python có đầu vào gồm 2 toán hạng, nó giúp kiểm tra xem một biến có nằm trong một dãy hay không. Có 2 toán tử membership bao gồm:

  • in: Trả về True nếu biến nằm trong dãy các biến
  • not in: Trả về True nếu biến không nằm trong dãy các biến

Ví dụ: a=10; b=25; list=[10,20,30,40,50];

  • a in list => True
  • b in list => False
  • b not in list => True

Tuyển dụng Python mọi cấp độ tại đây!

Thứ tự ưu tiên của các toán tử trong Python

Trong một biểu thức chứa nhiều toán tử, chúng ta cần xác định được mỗi toán tử trong biểu thức đó thực hiện công việc gì và thứ tự mà chúng thực hiện. Thứ tự thực hiện các phép tính trong biểu thức đó gọi là độ ưu tiên của toán tử – Operator Precedence.

toán tử Python

Trong Python thứ tự ưu tiên của các toán tử được thể hiện như ở bảng dưới đây, thứ tự ưu tiên từ cao xuống thấp (cao sẽ được thực hiện trước):

Toán tử Mô tả
** Toán tử mũ
~ + – Phần bù,phép cộng, trừ cho toán tử một ngôi
* / % // Phép nhân, chia, lấy phần dư, làm tròn
+ – Phép cộng/ trừ
>> << Dịch bit trái/ phải
& Phép và
^ | Phép XOR, OR
<= < > >= Toán tử so sánh
== != Toán tử so sánh bằng
= %= /= //= -= += *= **= Toán tử gán
is is not Toán tử định danh
in not in Toán tử Membership
not or and Toán tử Logic

Kết bài

Hy vọng qua bài viết này, bạn đã có thể nắm được đầy đủ các toán tử cơ bản trong Python; các ký hiệu toán học, các loại toán tử cùng thứ tự ưu tiên để thực hiện chính xác một phép toán phức tạp khi lập trình. Cảm ơn các bạn đã đọc bài và hẹn gặp lại trong các bài viết tiếp theo của mình.

Tác giả: Phạm Minh Khoa

Xem thêm:

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

Hướng dẫn tạo hiệu ứng văn bản sử dụng Gradient Text CSS

Hướng dẫn tạo hiệu ứng văn bản sử dụng Gradient Text CSS

Bài viết được sự cho phép của tác giả Nguyễn Thành Nam

Hiệu ứng văn bản với gradient text là một cách tuyệt vời để tạo điểm nhấn cho văn bản trên trang web của bạn. Sử dụng CSS, bạn có thể dễ dàng áp dụng hiệu ứng gradient text để làm cho văn bản trở nên hấp dẫn và nổi bật. Dưới đây là một ví dụ sử dụng hiệu ứng gradient text được tạo bằng CSS.

Để làm được như trên, bạn làm theo các bước hướng dẫn dưới đây:

Bước 1: Tạo HTML cơ bản

Đầu tiên, chúng ta cần tạo 1 khối HTML để chứa văn bản.

<div>
  <p>thanhnamnguyen.dev</p>
</div>

Bước 2: Thêm CSS Gradient

Sử dụng CSS sau để tạo hiệu ứng chuyển màu trên văn bản (gradient text). Mình sử dụng thuộc tính background: linear-gradient để tạo dải màu sắc tương ứng. Gradient này chạy từ trái qua phải và bao gồm bốn màu: #7953cd#00affa#0190cd, và #764ada (các mã màu này đang áp dụng ở chế độ darkmode). Các con số (20%, 30%, 70%, 80%) xác định vị trí của màu trong gradient.

  • -webkit-background-clip và background-clip: Định nghĩa việc clip gradient vào văn bản.
  • -webkit-text-fill-color và text-fill-color: Đặt màu chữ trong suốt để hiển thị gradient.
  • background-size: Đặt kích thước của background gradient là 500% theo chiều ngang và tự động theo chiều dọc.
  • Sử dụng animation textShine với thời gian 5 giây, kiểu easing-in-out, lặp vô hạn và thay đổi đối diện.
p {
  background: linear-gradient(to right, #7953cd 20%, #00affa 30%, #0190cd 70%, #764ada 80%);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
  text-fill-color: transparent;
  background-size: 500% auto;
  animation: textShine 5s ease-in-out infinite alternate;
}

Cùng với CSS ở trên, chúng ta cũng cần thêm hiệu ứng bằng cách sử dụng @keyframes textShine { ... }: Định nghĩa animation textShine. Nó bắt đầu với một vị trí background ở 0% theo chiều ngang và 50% theo chiều dọc, và kết thúc ở vị trí 100% theo chiều ngang và 50% theo chiều dọc, tạo hiệu ứng di chuyển gradient từ trái sang phải.

@keyframes textShine {
  0% {
    background-position: 0% 50%;
  }
  100% {
    background-position: 100% 50%;
  }
}

  3 Cách Làm Border Gradient Trong CSS Mà Bạn Nên Biết

  7 thư viện CSS Animation cực hay cho lập trình viên Frontend

Bước 3. Kết quả

Và bây giờ, bạn đã tạo thành công hiệu ứng gradient text trên văn bản. Thử nghiệm và tùy chỉnh gradient màu sắc và góc theo ý muốn.

Việc này chỉ là một ví dụ đơn giản, và bạn có thể tùy chỉnh nó theo nhu cầu của bạn để tạo ra hiệu ứng gradient text độc đáo cho trang web của bạn.

Đó là cách bạn có thể tạo hiệu ứng văn bản với gradient text sử dụng CSS. Hãy thử và sáng tạo để làm cho trang web của bạn trở nên thú vị hơn!

Bài viết gốc được đăng tải tại blog.thanhnamnguyen.dev

Xem thêm:

Xem thêm Việc làm IT hấp dẫn tại TopDev

Khi nào nên sử dụng cluster trong Node.js – đa luồng trong Node.js

Bài viết được sự cho phép của tác giả Sơn Dương

Từ trước tới nay, các bạn được học về Node.js đều được bảo là Node.js chỉ xử lý đơn luồng. Tức là tại một thời điểm, chỉ có một Thread được thực hiện.

Nói đơn giản cho dễ hiểu: bạn có CPU 8 nhân, 16 threads. Giờ bạn muốn duyệt một 1 triệu records để tìm phần tử lớn nhất. Với node.js, sẽ chỉ có 1 thread của CPU là thực hiện công việc duyệt tìm vì mặc định Node.js là single-thread. 1 thread chạy cắm đầu, 7 threads kia ngồi cười khúc khích.

Nhưng với Java, công việc được chia đều ra cho các threads, nên tốc độ sẽ xử lý trong bài toán ví dụ này sẽ nhanh hơn.

Đến đây, mình tin là bạn sẽ bật ra thắc mắc: Vậy không có cách nào để Node.js thực hiện đa luồng à?

Thế mạnh của Node.js là cơ chế none-blocking I/O, giúp ứng dụng có tốc độ rất nhanh. Tuy nhiên, có những bài toán yêu cầu phải xử lý đa luồng để tận dụng sức mạng CPU đa nhân. Tất nhiên là có thể làm được nhờ sự trợ giúp của cluster.

Bài viết này, chúng ta sẽ cùng nhau tìm hiểu về Cluster trong Node.js

Cluster trong Node.js
Cluster trong Node.js

Khi nào nên sử dụng Cluster

Như mình đã đề cập ở trên, thế mạnh của Node.js là none-blocking I/O, điều này giúp cho ứng dụng mặc dù chỉ sử dụng 1 thread để chạy nhưng tốc độ thì không hề tồi chút nào. Đơn giản vì Node.js tận dụng được thời gian nhàn rỗi của CPU.

Tuy nhiên, điều này chỉ phù hợp với các ứng dụng mà mỗi tác vụ chỉ thực hiện trong thời gian ngắn. Kiểu như các ứng dụng chat, ứng dụng chạy Real-Time…

Còn với các ứng dụng nặng về tính toán như xử lý ảnh, crawler data,… thì đơn luồng như Node.js không phù hợp.

Nếu bạn vẫn “chày cối” chọn Node.js thì vẫn có cách. Đó là sử dụng cluster để Node.js có thể xử lý đa luồng, tận dụng các nhân CPU còn nhàn rỗi.

Cluster trong Node.js hoạt động như thế nào?

Cluster trong Node.js được tạo một cách đơn giản, bạn sử dụng một module cùng tên: Cluster module.

Cơ chế hoạt động của nó cũng khá đơn giản. Cluster module cho phép Node.js tạo số luồng nhỏ hơn hoặc bằng số lõi của CPU, tự động phân chia công việc để tận dụng sức mạnh của CPU.

Cách sử dụng Cluster

Lý thuyết thì cơ bản vậy thôi, chúng ta sẽ cùng nhau thực hành tạo cluster để xử lý đa luồng trong Node.js

Đoạn code dưới mình sẽ tạo một server lắng nghe cùng một port thông qua cluster.

/*
 Đoạn code demo tạo clusters
*/
'use strict';

// Importing các Modules cần thiết
const http = require('http'),
    cluster = require('cluster'),
    os = require('os').cpus().length;

/*
Chúng ta sẽ tạo số cluster tương ứng với số nhân của CPU.
*/
if (cluster.isMaster) {

    for (let i = 0; i < os; i++) {
        cluster.fork();
        console.log(`The Worker number: ${i + 1} is alive`);
    }

    cluster.on('exit', (worker) => {
        console.log(`The Worker number: ${worker.id} has died`);
    });

} else {

    // Chúng ta sẽ tạo các cluster cùng lắng cùng một port
    http.createServer((sol, res) => {
        res.end('Hi, we are harnessing the power of clusters :)');
    }).listen(3000, () => console.log('The server is running on the port:3000'));

    console.log(`The Worker number: ${cluster.worker.id} is running`);
}

Như đoạn code trên, cluster đầu tiên được tìm thấy sẽ là master cluster. Sau đó thì sẽ nhân bản ra các cluster từ master cluster, đó chính là cách mà chúng ta chia sẻ port. Một listener cũng được thêm vào cluster để biết được trạng thái stop/failed của một worker.

Sử dụng Cluster kết hợp với Express.js

Ở ví dụ trên, chúng ta đã biết tạo cluster với http module. Giờ chúng ta sẽ làm một ví dụ về cách sử dụng cluster khi kết hợp http và express.js

/*
 Creating clusters and serving an application that uses express

*/
'use strict';

// importing the modules
const cluster = require('cluster'),
 os = require('os').cpus().length,
 server = require('./serverHttp');

/*
 We see if it is the master cluster in case it is,
 we will clone the cluster amount at the same time as the cores
 of the processor.
*/
if(cluster.isMaster){

const Master = require('./work');
const master = new Master({cluster:cluster});

for(let i = 0; i < os; i++){
 master.liftWorker();
}

 cluster.on('exit', (worker)=>{
 console.log(worker)
 console.log(`The Worker number: ${worker.id} is dead.`);
 master.liftWorkerError();
});

}else{

 // Creating a server with http and express.
 let app = new server();
 app.initiate();
 console.log(`cluster ${cluster.worker.id} is running.`)

}

Bạn thấy đấy, cách viết code cũng tương tự như lúc trước. Chỉ khác là lần này chúng ta sẽ chia công việc thành nhiều module.

  Xử lý ERROR trong NodeJS sao cho đúng?

  Một thủ thuật nhỏ để tối ưu code nodejs

// Class to pick cluster workers
class Master {
    constructor(config){

     this.config = config || {};
     this.cluster = this.config.cluster;

    }

    // Pick up a new Worker
    liftWorker(){

      let worker = this.cluster.fork();
      console.log(`The worker ${worker.id} is started.`);

    }

    // Raise a worker when one dies in case of errors
    liftWorkerError(){
      let worker = this;

      setTimeout(()=>{
        worker.liftWorker();
      }, 200);

    }
  }

 module.exports = Master;

Về cơ bản là chúng ta sẽ tạo riêng một file là work.js. Mục đích của module này là cung cấp các phương thức để tạo mới một hoặc nhiều workers khi một worker bị die.

Cuối cùng là chúng ta sẽ có module chính để tạo server và lắng nghe một port.

'use strict';

const http = require('http'),
  express = require('./express');

// Creating the server with http
class Servidor{
  constructor(config){
    this.config = config || {};

    this.app = new express();

    this.server = http.createServer(this.app.server);

    this.app.gets();

  }

  // Starting the server
  initiate(){

    this.server.listen(3000, ()=> console.log('The server is running on port 3000'));

  }
}

module.exports = Servidor;
'use strict';

const express = require('express');

class Server {
  constructor(config){
    this.config = config || {};
    this.server = express();
  }

  // Serving the routes get
  gets(){

    this.server.get('/', (sol, res, next)=>{

      res.send(`This route is served by the workes`);

    });

    this.server.get(`/hello`,(sol, res, next)=>{

      res.send('This route too 🙈');

    });

  }

}

module.exports = Server;

Kết luận

Node.js là giải pháp thích hợp để xử lý các ứng dụng có lượng traffic lớn. Tuy nhiên, với các ứng dụng nặng về tính toán thì Node.js cũng có thể làm tốt.

Mình biết về cluster trong Node.js cũng khá lâu rồi. Nhưng hồi đó cluster còn chưa ổn định, và ngon lành như bây giờ. Giờ thì ngon lành rồi.

Tất nhiên, cũng như các ngôn ngữ, giải pháp khác, việc xử lý đa luồng chưa bao giờ là dễ cả, code sẽ cần nhiều logic hơn. Nhưng nhìn chung, cluster sẽ giúp bạn đơn giản hóa rất nhiều việc xử lý đa luồng trong Node.js

Cảm nhận của bạn về cluster khi sử dụng trong dự án như thế nào? Để lại bình luận bên dưới nhé.

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

Xem thêm:

Xem thêm các việc làm công nghệ hấp dẫn trên TopDev

Giới thiệu về RedisJSON – Mảnh ghép hoàn hảo cho RediSearch

Giới thiệu về RedisJSON - Mảnh ghép hoàn hảo cho RediSearch

Bài viết được sự cho phép của tác giả Tống Xuân Hoài

Vấn đề

Tôi đã có một bài viết về vấn đề blog của tôi sử dụng RediSearch làm cơ sở dữ liệu chính ở RediSearch là gì? Estacks đang sử dụng RediSearch làm cơ sở dữ liệu!, bên cạnh đó là lý do tôi dùng RediSearch vì tính năng Tìm kiếm fulltext trong RediSearch mà tôi luôn muốn tìm kiếm của blog trở nên mạnh mẽ và hữu ích hơn cho bạn đọc.

Cho đến hiện tại mọi thứ vẫn đang hoạt động rất tốt, chỉ có một điều Redis không có kiểu dữ liệu JSON trong khi tôi lại muốn thao tác với dữ liệu dạng JSON một cách thân thiện nhất. Do đó trong quá trình tìm hiểu tôi phát hiện ra Redis cung cấp một module có tên là RedisJSON đã giúp tôi làm được điều đó. Nếu như bạn đang dùng Redis hay RediSearch mà muốn thao tác với dữ liệu JSON thì đây quả là một điều tuyệt vời.

RedisJSON là gì?

RedisJSON là một module cung cấp hỗ trợ JSON cho Redis. RedisJSON cho phép bạn lưu trữ, cập nhật và truy xuất các giá trị JSON trong cơ sở dữ liệu Redis tương tự như bất kỳ kiểu dữ liệu Redis nào khác. RedisJSON cũng hoạt động với RediSearch để cho phép bạn lập chỉ mục và truy vấn các tài liệu JSON.

127.0.0.1:6379> JSON.SET obj $ '{"title": "Chào các Developer - Hôm nay uống gì và code gì?", "url": "https://2coffee.dev"}'
"OK"
127.0.0.1:6379> JSON.GET obj $
[{"title":"Chào các Developer - Hôm nay uống gì và code gì?","url":"https://2coffee.dev"}]

Cách sử dụng

Để sử dụng RedisJSON trước tiên bạn cần cài đặt Redis v6.x trên server của mình. Redis cung cấp nhiều cách khác nhau để tải module RedisJSON. Hai cách phổ biến là:

  • Sửa file cấu hình redis.conf:
loadmodule /path/to/module/target/release/librejson.so
  • Sử dụng Command-line:
$ redis-server --loadmodule /path/to/module/librejson.so

Với /path/to/module là đường dẫn đến thư mục cài đặt Redis của bạn. Ví dụ:

$ redis-server --loadmodule /usr/lib/redis/module/librejson.so

Chi tiết hơn bạn có thể xem thêm tại trang tài liệu.

Cú pháp cơ bản

Như đã giới thiệu ở trên, RedisJSON cung cấp cho chúng ta nhiều cú pháp để lưu trữ, cập nhật hay truy xuất các giá trị JSON.

127.0.0.1:6379> JSON.SET obj $.year 2022
OK
127.0.0.1:6379> JSON.SET obj $.users '["admin"]'
OK
127.0.0.1:6379> JSON.ARRAPPEND obj $.users '"hoaitx"'
2
127.0.0.1:6379> JSON.GET obj $
[{"title":"Chào các Developer - Hôm nay uống gì và code gì?","url":"https://2coffee.dev","year":2022,"users":["admin","hoaitx"]}]
127.0.0.1:6379> JSON.DEL obj
"OK"

Để xem đầy đủ các cú pháp thao tác với dữ liệu JSON các bạn vào trang tài liệu Commands.

  JSON Web Token là gì?

  Giới thiệu về JSON Binding trong Jakarta EE

Sử dụng với RediSearch

Để sử dụng RedisJSON với RediSearch bạn cần tìm nạp hai module RediSearch v2.2 trở lên và RedisJSON v2.0 trở trên trong máy chủ Redis v6.x.

Sau đó tạo SCHEMA trong RediSearch để phục vụ tìm kiếm:

127.0.0.1:6379> FT.CREATE article ON JSON PREFIX 1 article: SCHEMA $.title AS title TEXT $.content as content TEXT $.view AS view NUMERIC
OK

Để thêm dữ liệu vào Schema ta sử dụng lệnh JSON.SET:

127.0.0.1:6379> JSON.SET article:1 $ '{"title": "2coffee", "content": "Chào các Developer - Hôm nay uống gì và code gì?", "view": 0}'

Sau đó chúng ta có thể tìm kiếm fulltext bằng các cú pháp của RediSearch:

127.0.0.1:6379> FT.SEARCH article '@title:%coffee%'
1
article:1000
$
{"title":"2coffee","content":"Chào các Developer - Hôm nay uống gì và code gì?","view":0}

Từ RediSearch 2.6.0 trở đi bạn cũng có thể tìm kiếm fulltext với các thuộc tính là một mảng các chuỗi.

127.0.0.1:6379> JSON.SET article:1 $ '{"title": ["2coffee", "hicoffee"], "content": "Chào các Developer - Hôm nay uống gì và code gì?", "view": 0}'
127.0.0.1:6379> FT.SEARCH article '@title:%coffee%'

Từ RediSearch 2.6.1 trở đi bạn có thể tìm kiếm trên thuộc tính là một mảng các số (NUMERIC).

127.0.0.1:6379> JSON.SET article:1 $ '{"title": ["2coffee", "hicoffee"], "content": "Chào các Developer - Hôm nay uống gì và code gì?", "view": [0, 1, 2]}'
127.0.0.1:6379> FT.SEARCH article '@view:[0 1]'

Cú pháp trên sẽ trả về các bản ghi có giá trị bất kì nào trong view thoả mãn >= 0 và <= 1.

Ngoài ra còn nhiều cú pháp khác hỗ trợ đánh index và tìm kiếm tài liệu tại Trang tài liệu.

Xem thêm các việc làm JSON hấp dẫn trên TopDev

Tổng kết

Nếu đã quen làm việc với NoSQL thì RedisJSON cung cấp cho chúng ta một cách thuận tiện cho việc thao tác với các dữ liệu dạng JSON mà không lo sai sót dữ liệu. SQL cũng đã tích hợp kiểu dữ liệu JSON từ lâu giúp cho chúng ta có nhiều lựa chọn hơn trong việc tổ chức dữ liệu.

RedisJSON dễ dàng tích hợp với RediSearch để lập chỉ mục và tìm kiếm, việc này vừa mang lại tính thuận tiện trong lưu trữ, cộng với khả năng tìm kiếm fulltext mạnh mẽ của RediSearch và tốc độ của Redis. Tôi đang sử dụng bộ 3 công cụ này còn bạn có dự định gì cho dự án sắp tới chưa? 😀

Bài viết gốc được đăng tải tại 2coffee.dev

Xem thêm:

Xem thêm việc làm CNTT hấp dẫn trên TopDev

Áp dụng quy tắc IRAC trong công việc cho developers

Áp dụng quy tắc IRAC trong công việc cho developers

Bài viết được sự cho phép của tác giả Duy Phan

IRAC (Issue – Rule – Analysis – Conclusion) là một phương pháp phổ biến và quen thuộc với sinh viên luật và dân luật nói chung. Cá nhân mình thấy phương pháp này khá hay và hoàn toàn có thể áp dụng vào bất cứ công việc hoặc ngành nghề nào.

Áp dụng quy tắc IRAC trong công việc cho developers

Giới thiệu

Phương pháp IRAC (đọc là eye-rack hoặc ai rách haha) là một cái sườn giúp bạn có thể sắp xếp câu trả lời cho một vấn đề nào đó một cách chi tiết và rõ ràng. Thực ra phương pháp này bắt đầu được đưa ra và áp dụng bởi các công ty luật ở Mỹ.

Cấu trúc của một câu trả lời chuẩn IRAC bao gồm các thành phần cơ bản: Issue – Vấn đềRule – Quy phạmAnalysis – Phân tích và Conclusion – Kết luận.

Mình là lập trình viên, nên sẽ cố gắng giải thích một cách đơn giản và non-legal hết sức có thể ^_^

  • Issue: các vấn đề mà khách hàng đưa ra cho chúng ta mà chúng ta cần giải quyết và tư vấn cho họ.
  • Rule: các quy tắc và những thứ common sense cần tuân thủ trong quá trình thực hiện yêu cầu. Các quy tắc ở đây có thể là một vài tiêu chuẩn chung hoặc những quy định cụ thể từ phía khách hàng.
  • Analysis: phân tích, làm rõ ràng các yêu cầu của khách hàng. Dựa vào các Rule mà chúng ta liệt kê ra các solutions hợp lý để giải quyết Issue.
  • Conclusion: từ kết quả Analysis ở trên, chúng ta tổng kết lại các phương pháp tốt nhất hoặc phù hợp nhất để khách hàng có thể áp dụng.

Trong một số trường hợp, chúng ta có thể gộp chung phần Analysis và Conclusion lại với nhau mà không cần phải tách biệt chúng.

  Code convention là gì? Một số quy tắc chung khi viết code lập trình

  Quy tắc viết code dễ đọc, tối ưu và dễ bảo trì nhất

Ví dụ áp dụng

Issue

Khách hàng Trung Nghĩa đã có một website bán hàng online. Trung Nghĩa liên hệ và yêu cầu Duy PT phát triển thêm tính năng sản phẩm đa phiên bản.

Rule

  • Không ảnh hưởng tới dữ liệu hiện có do website đã có lượng traffic cao cùng với lượng khách truy cập đông đảo (common sense).
  • Tốc độ tải trang nhanh chóng, ít nhất là như trang hiện tại.
  • Validate dữ liệu đầy đủ phía backend (common sense).

Analysis

Yêu cầu của khách hàng khá mơ hồ nên cần làm rõ ràng, chi tiết hơn:

  • Các phiên bản sản phẩm có khả dụng trong việc tìm kiếm hay không?
  • Các thuộc tính của mỗi phiên bản sản phẩm có giới hạn hay không?
  • Khi một sản phẩm có số lượng thuộc tính quá lớn thì xử lý như thế nào?
  • Việc cập nhật thông tin phiên bản sản phẩm có ảnh hưởng tới những đơn hàng trước đó không? Nếu có thì cách xử lý là gì?
  • Cách thức để tạo một sản phẩm có nhiều phiên bản là như thế nào?
  • Cách chọn phiên bản sản phẩm ở phía người dùng cuối như thế nào? Có thể đưa ra một số cách thức mà Shopee, Lazada hoặc các trang TMĐT khác đã làm sẵn.

Xem thêm các việc làm PHP lương cao trên TopDev

Thông thường đây là quá trình tốn nhiều thời gian nhất trong quá trình lấy yêu cầu. Chúng ta cần phải tưởng tượng ra một big picture về chức năng khách hàng mong muốn, sau đó dần xoáy sâu vào phần details.

Trong quá trình này, để tiết kiệm thời gian cũng như giúp khách hàng dễ nắm bắt ý kiến của mình, chúng ta có thể đưa ra một số bản mockup mô tả chức năng. Dựa vào các bản mockup này, khách hàng sẽ có thể giúp bạn thay đổi, hiệu chỉnh một số thứ cho phù hợp. Khách hàng khá thích làm việc với những người làm việc rõ ràng như vậy, nên các dev nào có ý muốn chuyển sang hướng manager hãy chú ý nhé ^_^.

Hãy cố gắng đặt càng nhiều câu hỏi càng tốt, khách hàng sẽ không thấy phiền lòng đâu. Bạn càng đặt nhiều câu hỏi thì điều đó càng chứng tỏ bạn đang hiểu rõ hơn về thứ mà khách hàng mong muốn. Tuy nhiên, hãy tránh hỏi những câu hỏi ngu ngốc.

Đừng quên keep track tất cả những thông tin mà bạn nhận được. Bạn sẽ cần nó để viết documents lại sau này. Mình khuyên bạn nên keep track mọi thứ qua email nếu có thể.

Conclusion

Sau quá trình phân tích thông tin và clear requirements với khách hàng, lúc này bạn cần viết một bản tổng kết nội dung, kèm theo FSD (Functional Specification Document) rồi gửi cho khách hàng. Có thể sẽ có một vài chỉnh sửa nho nhỏ nào đó.

Việc tiếp theo là ngồi rung đùi chờ khách hàng sign-off rồi bắt tay vào làm thôi. Với một số công ty nhỏ và quy trình không quá strictly thì bạn cũng có thể làm luôn được rồi.

Bài viết của mình đến đây là hết, cám ơn các bạn đã theo dõi nhé 😀

Bài viết gốc được đăng tải tại duypt.dev

Xem thêm:

Cập nhật tin tuyển dụng IT lương cao tại TopDev

Cách làm cho Github Profile Readme của bạn thu hút hơn

Cách làm cho Github Profile Readme của bạn thu hút hơn

Bài viết được sự cho phép của tác giả Nguyễn Thành Nam

Github không chỉ là một nơi để lưu trữ mã nguồn mở và làm việc nhóm, mà còn là một nền tảng mạng xã hội cho các nhà phát triển và chuyên gia công nghệ. Và giới thiệu mới nhất của Github chính là Github Profile README – một cách tuyệt vời để cá nhân hóa trang cá nhân của bạn và giới thiệu về bản thân mình một cách sáng tạo. Trong bài viết này, chúng ta sẽ cùng nhau khám phá tính năng mới này và làm thế nào để tận dụng tối đa.

1. Github Profile là gì?

Github Profile README là một trang README.md đặc biệt được hiển thị ngay ở phần đầu trang của trang cá nhân GitHub của bạn. Điều này cung cấp cho bạn một không gian để tạo ra một bảng tự giới thiệu động với văn bản, hình ảnh, liên kết và thậm chí là các biểu tượng đặc sắc. Nó giúp bạn nổi bật hơn trong cộng đồng GitHub và tạo ấn tượng mạnh mẽ từ những người đang xem trang cá nhân của bạn.

Đây là trang github profile của mình

Github Profile Readme

2. Làm thế nào để tạo Github Profile?

Để tạo Github Profile, ta cần tạo một Repository đặc biệt:

  • Tạo một repository có tên chính là tên người dùng Github của bạn.
  • Thêm một file README.md vào repository mới tạo.
  • Chỉnh sửa README.md theo ý thích của bạn.

tạo github profile

Sau đó, ta

  • Sử dụng ngôn ngữ đánh dấu Markdown để tạo nội dung trang cá nhân của bạn.
  • Thêm hình ảnh, liên kết và biểu tượng để tạo ra một trang cá nhân động và sinh động.
  • Lưu và commit các thay đổi của bạn vào repository.

👉 Khi hoàn tất, trang cá nhân của bạn sẽ hiển thị README.md ở đầu trang.

Một số ý tưởng cho GitHub Profile

  • Bảng tự giới thiệu: tạo một bảng với tên, ảnh đại diện và một câu khẩu hiệu ngắn.
  • Dự án nổi bật: liệt kê các dự án quan trọng mà bạn đang làm và đặt liên kết đến chúng.
  • Kinh nghiệm và kỹ năng: mô tả về kinh nghiệm làm việc, giáo dục và kỹ năng chuyên môn.
  • Liên kết xã hội và blog: thêm liên kết đến các trang xã hội của bạn và blog cá nhân.

  Viết blog sử dụng markdown, pelican, github pages

  8 tips giúp tăng hiệu suất làm việc với Github

Một số công cụ giúp bạn tạo Github Profile:

3. Kết luận

Github Profile README là một cách tuyệt vời để làm cho trang cá nhân của bạn nổi bật trong cộng đồng phát triển. Việc tạo ra một trang cá nhân độc đáo không chỉ giúp bạn chia sẻ thông tin về bản thân mình mà còn là cơ hội để thể hiện sự sáng tạo của bạn. Hãy bắt đầu sáng tạo ngay hôm nay và để cho trang cá nhân của bạn trở nên độc đáo và ấn tượng trên Github!

Bài viết gốc được đăng tải tại blog.thanhnamnguyen.dev

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

Xem thêm Việc làm Developer hấp dẫn trên TopDev

Sự khác biệt giữa API và Webhook là gì?

Sự khác biệt giữa API và Webhook

Bài viết được sự cho phép của tác giả Duy Phan

Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều được kích hoạt bởi các events.

Một API cho phép giao tiếp hai chiều giữa các ứng dụng phần mềm thông qua các requests. Một Webhook là một API nhẹ, hỗ trợ chia sẻ dữ liệu một chiều và thường được kích hoạt bởi các events.

Khi kết hợp cùng nhau, chúng cho phép các application chia sẻ dữ liệu và function, giúp cho các services đạt được kết quả to lớn hơn tổng các thành phần của chúng.

API và Webhook đều cho phép các hệ thống phần mềm khác nhau đồng bộ và chia sẻ thông tin. Khi các ứng dụng phần mềm trở nên ngày càng kết nối, điều quan trọng là các nhà phát triển hiểu rõ sự khác biệt giữa hai phương tiện này để chia sẻ dữ liệu và lựa chọn công cụ phù hợp nhất với nhu cầu của công việc đang thực hiện.

API là gì?

API là viết tắt của cụm từ Application Programming Interface.

Một API giống như một cổng thông tin mà thông qua đó thông tin và chức năng có thể được chia sẻ giữa các services. Từ interface là chìa khóa để hiểu rõ mục đích của một API. Giống như một trình duyệt web là một interface cho người sử dụng cuối để nhận, gửi và cập nhật thông tin trên web server, một API là một interface cung cấp chức năng tương tự cho các ứng dụng phần mềm.

Có nhiều loại và danh mục khác nhau của API (chúng ta sẽ khám phá sau), nhưng nói chung, API là cách phổ biến nhất để các hệ thống phần mềm khác nhau kết nối và chia sẻ thông tin.

Webhook là gì?

Một webhook có thể được coi là một loại API được kích hoạt bởi các events thay vì requests.

Thay vì một service tạo một request để nhận một phản hồi từ service khác, một webhook là một dịch vụ cho phép một service gửi dữ liệu đến một service khác ngay sau khi một event cụ thể được emit. Webhooks đôi khi được coi là “API đảo ngược,” vì giao tiếp được khởi tạo bởi service gửi dữ liệu thay vì service nhận nó.

Với sự phát triển mạnh mẽ của các distributed system (hệ thống xử lý phân tán), webhook đang trở nên phổ biến hơn khi là một giải pháp gọn nhẹ cho việc kích hoạt notification và cập nhật dữ liệu theo thời gian thực mà không cần phải phát triển một API toàn diện.

Chẳng hạn, nếu bạn muốn nhận notification trên Slack khi có tweet đề cập đến một tài khoản cụ thể và chứa một #hashtag nhất định được publish, thay vì Slack liên tục yêu cầu Twitter về bài viết mới đáp ứng các tiêu chí này, việc Twitter gửi một thông báo đến Slack chỉ khi event này xảy ra là một lựa chọn tốt hơn nhiều.

Đây chính là mục đích của một webhook – thay vì phải liên tục yêu cầu dữ liệu, service nhận dữ liệu có thể ngồi lại và xử lý những gì nó cần mà không cần gửi các request lặp đi lặp lại đến hệ thống khác.

API cho khả năng tích hợp mạnh mẽ

Một đặc điểm quan trọng của API là chúng cung cấp giao tiếp hai chiều giữa các service khác nhau thông qua một chu kỳ request – response, thường sử dụng thông qua giao thức HTTP.

Trong một trường hợp sử dụng API điển hình, một service sẽ yêu cầu một tập hợp cụ thể dữ liệu từ một service khác bằng cách sử dụng yêu cầu HTTP GET request. Miễn là yêu cầu hợp lệ, hệ thống nhận sẽ gửi về response bằng dữ liệu được yêu cầu ở định dạng có thể đọc bằng máy, thường là XML hoặc JSON. Điều này làm cho các service có thể chia sẻ dữ liệu mà không cần quan tâm đến ngôn ngữ lập trình cá nhân hoặc các đặc tả nội bộ của chúng.

Tính chất phổ quát của tương tác API có thể tạo ra vô số kịch bản, từ người dùng iPhone kiểm tra nhiệt độ địa phương thông qua API của AccuWeather đến tài xế Grab điều hướng đến vị trí đón tiếp theo thông qua API của Google Maps.

Ngoài việc nhận dữ liệu, API cũng có thể xử lý toàn bộ các hoạt động “CRUD” (Create, Read, Update và Delete) giữa hai ứng dụng. Nói cách khác, API không chỉ để hiển thị dữ liệu cho người dùng trong một interface mà còn có thể được sử dụng để thay đổi dữ liệu trong service nơi nó được lưu trữ. Đây là cách mà API cho phép các hệ thống phần mềm mở rộng dịch vụ và chức năng của chúng, cũng như tích hợp với các nền tảng khác một cách toàn diện và có ý nghĩa.

Sự linh hoạt của API khiến chúng trở thành công cụ mạnh mẽ cho developers để mở rộng khả năng của ứng dụng.

Hầu hết các dịch vụ web hiện đại bao gồm API cho phép dữ liệu và chức năng của họ được tích hợp vào các công cụ khác – thực tế, rất hiếm khi gặp một dịch vụ web doanh nghiệp nào không tận dụng một API từ ít nhất một ứng dụng khác một cách nào đó.

  Bỏ túi một số quy tắc thiết kế API hữu ích

  Một số phương pháp bảo mật hiệu quả dành cho webhook

Webhook cho phép chia sẻ dữ liệu một cách gọn nhẹ

Nhiều người có thể nghĩ rằng vì webhook là reatime event nên chúng khó triển khai từ mặt kỹ thuật.

Trên thực tế, một ưu điểm chính của webhook là chúng dễ thiết lập hơn và tốn ít tài nguyên hơn so với API. Việc tạo một API là một quy trình phức tạp, trong một số trường hợp có thể khó khăn như việc thiết kế và xây dựng cấu trúc của service, nhưng triển khai một webhook đôi khi chỉ đơn giản là thiết lập một HTTP POST request duy nhất ở đầu gửi, thiết lập một URL ở đầu nhận để tiếp nhận và sau đó thực hiện một số hành động trên dữ liệu đó.

Các trường hợp sử dụng phổ biến cho webhook bao gồm:

  • gửi danh sách email subscriptions và unsubscriptions đến một hệ thống CRM,
  • tự động cập nhật phần mềm kế toán khi hóa đơn được thanh toán,
  • hoặc thiết lập bất kỳ loại thông báo nào.

Trong mỗi loại event này, data chỉ đi theo một hướng và không cần nhận hay xử lý dữ liệu được cập nhật.

Những đặc tính giống nhau khiến cho việc triển khai webhook tương đối dễ dàng cũng là lý do tại sao chúng giới hạn hơn nhiều so với APIs.

Việc cập nhật dữ liệu mà một webhook gửi đòi hỏi việc cấu hình lại nó hoàn toàn để lắng nghe event khác, và trong hầu hết các trường hợp, việc tạo một webhook mới sẽ hiệu quả hơn.

Khác với APIwebhook không cho phép hệ thống gửi thêm, cập nhật và xóa dữ liệu ở đầu nhận, điều này là lý do tại sao webhook một mình quá hạn chế để cung cấp việc tích hợp đầy đủ giữa các service.

Tham khảo Web Developer Jobs HOT tại TopDev

Kiến trúc của API – hiện tại và tương lai

API có thể được phân loại dựa trên các giao thức và kiến trúc xác định cách chúng gửi – nhận dữ liệu.

Lịch sử cho thấy, mẫu kiến trúc phổ biến nhất cho thiết kế API là REST (Representational State Transfer), đặc biệt là đối với các API phục vụ ứng dụng dựa trên nền tảng WEB.

REST, được đặt ra bởi Roy Fielding vào năm 2000, cho phép giao tiếp giữa hai ứng dụng qua HTTP, tương tự như cách trình duyệt tương tác với máy chủ. REST không phải là một tiêu chuẩn chính thức mà là một bộ hướng dẫn về cách thiết kế API và các web serivce khác. Một API được coi là RESTful nếu thiết kế của nó tuân theo những đề xuất sau:

  1. Client-Server (Khách hàng-Máy chủ): Tương tự như browser yêu cầu một trang web từ server, trong một API RESTful, một ứng dụng (client) yêu cầu một URL được lưu trữ trên một service khác (server) thông qua HTTP. Máy chủ đánh giá yêu cầu và response bằng dữ liệu được yêu cầu hoặc một thông báo lỗi.
  2. Stateless (Không lưu trạng thái): Server không cần biết gì về state của client yêu cầu để cung cấp một response thích hợp. Một request từ client cần chứa đủ thông tin để server gửi response.
  3. Cacheability (Có thể lưu trữ vào bộ nhớ đệm): Response từ server nên chỉ ra liệu client có nên lưu trữ dữ liệu vào bộ nhớ đệm hay không.
  4. Layered Systems (Hệ thống đa lớp): API không phụ thuộc vào một hệ thống cụ thể để thực hiện yêu cầu; nó có thể gửi phản hồi qua các lớp khác nhau. Điều này có nghĩa là hệ thống nhận có thể là một client, một proxy, hoặc bất kỳ trung gian nào khác.

Ví dụ đơn giản sau đây https://www.boredapi.com/api/activity tuân theo quy ước REST. Khi bạn truy cập URL, browser của bạn sẽ hiển thị một activity được đề xuất để tham gia nếu bạn đang rảnh đến nhức cả trứng =)), được định dạng dưới kiểu JSON:

{
    "activity": "Shop at support your local farmers market",
    "type": "relaxation",
    "participants": 1,
    "price": 0.2,
    "link": "",
    "key": "8979931",
    "accessibility": 0.1
}
Mặc dù REST đã được sử dụng rộng rãi và vẫn còn phổ biến, những phương pháp và kiến trúc mới đang dần xuất hiện.

Một lựa chọn đáng chú ý khác là GraphQL, được phát triển bởi Facebook.

GraphQL cung cấp một cách linh hoạt và hiệu quả hơn cho khách hàng yêu cầu dữ liệu cụ thể mà họ cần, giảm việc lấy quá nhiều hoặc quá ít dữ liệu. Nó cho phép khách hàng xác định cấu trúc của phản hồi, tạo điều kiện cho tương tác linh hoạt và cá nhân hóa hơn.

mutation {
  qrAssign(
    connectorId: "23024"
    poolName: "joint-tech"
    qrId: "AMPJ-1120311132"
    useCustom: true
  ) {
    id
    qrId
    charger {
      chargerUri
    }
  }
}

Trong tương lai, chúng ta có thể mong đợi sự tiếp tục phát triển trong kiến trúc API, với sự tập trung vào khả năng mở rộng, khả năng realtime và sự thích ứng với nhu cầu đa dạng của khách hàng.

Bài viết gốc được đăng tải tại duypt.dev

Xem thêm:

Tin tuyển dụng IT mọi cấp độ trên TopDev đang chờ bạn ứng tuyển!

Room Database trong Android – hướng dẫn sử dụng chi tiết

Room Database trong Android

Bài viết được sự cho phép bởi tác giả Sơn Dương

Các bài trước mình đã hướng dẫn các bạn sử dụng Sqlite và Realm database. Tuy nhiên, vẫn còn một giải pháp thao tác với database cũng rất hay ho khác. Đó chính là Room database trong Android.

Vậy Room Database là gì? Cách sử dụng Room database như thế nào?

Chúng ta sẽ cùng nhau tìm hiểu thông qua một dự án ví dụ nhé.

#Giới thiệu Room database trong Android

Room database được phát triển và cải tiến từ sqlite. Room database giúp đơn giản hoá việc code,và giảm thiểu các công đoạn liên quan đến cơ sở dữ liệu.

Bản chất Room database là abstract layer gồm cơ sở dữ liệu chuẩn SQLite được Android thông qua.

Với 3 thành phần chính là: Database, DAO (Data Access Object) và entity. Mỗi thành phần đều có nhiệm vụ và chức năng riêng.

#Xây dựng ứng dụng sử dụng Room database trong Android

1. Cài đặt thư viện

Đầu tiên các bạn import thư viện vào file build.gradle

dependencies {
...
    implementation 'android.arch.persistence.room:runtime:' + rootProject.archRoomVersion;
...
}

2. Xây dựng layout

Ứng dụng demo có giao diện để khi nhập các thông tin và lưu xong data sẽ tự đọc ra và fill vào textview.

Giao diện của ứng dụng sẽ giống như bên dưới:

Giao diện Demo ứng dụng sử dụng Room database
Giao diện Demo ứng dụng sử dụng Room database

Toàn bộ code của layout như sau:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:orientation="vertical">

    <EditText
        android:id="@+id/etName"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:layout_marginTop="10dp"
        android:ems="10"

        android:hint="Employ Name"
        android:inputType="textPersonName|textCapWords"
        android:singleLine="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        tools:layout_editor_absoluteY="7dp" />

    <EditText
        android:id="@+id/etDesignation"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="8dp"
        android:layout_marginRight="8dp"
        android:ems="10"
        android:hint="Designation"
        android:inputType="textPersonName|textCapWords"
        android:singleLine="true"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        tools:layout_editor_absoluteY="75dp" />

    <Button
        android:background="@android:color/holo_blue_bright"
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        android:text="Save"
        app:layout_constraintTop_toBottomOf="@+id/editText2" />

    <ScrollView
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:padding="16dp">

    <TextView
        android:text="data"
        android:id="@+id/txt_list"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    </ScrollView>

</LinearLayout>

3. Tạo cấu trúc rom database trong Android

Chúng ta sẽ chia phần tương tác với database thành 3 class:

  • Employee: Entity nơi định nghĩa bảng và trường của Database. Mỗi 1 Entity tương đương với 1 bảng trong Database.
  • EmployDao: Interface định nghĩa các câu truy vấn Database
  • AppDatabase: Class này extends từ RoomDatabase là nơi thao tác trực tiếp và thực hiện các truy vấn xuống Database.

Bây giờ mình sẽ hường dẫn các bạn tạo từng class một.

Lưu ý: Mỗi bảng cơ sở dữ liệu sẽ tương ứng với mỗi class được chú thích với @Entity

Đầu tiên các bạn tạo class Employee.

@Entity
public class Employee {
    @PrimaryKey(autoGenerate = true)
    public long employId;
    @ColumnInfo(name = "employ_name")
    public String name;
    public String designation;
}

Sau đó các bạn tạo interface để thực hiện truy vấn.

DAO là interface được chú thích với @Dao, nó đóng vai trò trung gian truy cập vào các đối tượng trong cơ sở dữ liệu và các bảng của nó.

Có bốn chú thích cụ thể cho các hoạt động cơ bản của DAO: @Insert@Update@Delete, and @Query.

@Dao
public interface EmployDao {
    @Insert(onConflict = REPLACE)
    void insertEmploy(Employee employee);

    @Insert(onConflict = IGNORE)
    void insertOrReplaceEmploy(Employee... employees);

    @Update(onConflict = REPLACE)
    void updateEmploy(Employee employee);

    @Query("DELETE FROM Employee")
    void deleteAll();

    @Query("SELECT * FROM Employee")
    public List<Employee> findAllEmploySync();
}

Và cuối cùng các bạn tạo AppDatabase.

Thành phần Database là một abstract class đã được chú giải bằng @Database. Nó extend RoomDatabase Class và trong đó định nghĩa một danh sách các Entities và các DAO.

@Database(entities = {Employee.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
    private static AppDatabase INSTANCE;
    public abstract EmployDao employDao();
    public static AppDatabase getInMemoryDatabase(Context context) {
        if (INSTANCE == null) {
            INSTANCE = 
Room.inMemoryDatabaseBuilder(context.getApplicationContext(), AppDatabase.class)
                           // To simplify the codelab, allow queries on the main thread.
                           // Don't do this on a real app! See PersistenceBasicSample for an example.
                           .allowMainThreadQueries()
                           .build();
        }
         return INSTANCE;
    }
    public static void destroyInstance() {
        INSTANCE = null;
    }
}

  RxJava – Thời đại lập trình Reactive programming ứng dụng Android đã tới

  Lập trình Android bằng Java: Hướng dẫn toàn diện

4. Tạo các hàm trong  MainActivity để xử lý logic

Sau khi các bạn ánh xạ giao diện xong chúng ta bắt đầu code logic. Khi click vào button lưu mình sẽ gọi hàm insert.

Khi insert thành công thì đọc luôn database để hiển thị lên giao diện.

//Hàm xử lý click
Employee employee = new Employee();
employee.name = name;
employee.designation = designation;
mDb.employDao().insertEmploy(employee);
Toast.makeText(this, "Saved successfully", Toast.LENGTH_SHORT).show();
etName.setText("");
etDesignation.setText("");
etName.requestFocus();
populateEmployList();

Kết quả chúng ta thu được ứng dụng như demo bên dưới:

Demo ứng dụng sử dụng Room Persistence Library
Demo ứng dụng sử dụng Room Persistence Library

Tham khảo thêm về cách xử lý sự kiện trong android: Xử lý sự kiện trong Android (Event Listeners) bằng Kotlin

Tìm việc làm Android lương cao trên TopDev!

#Tạm kết

Như vậy, mình đã hướng dẫn các bạn từng bước sử dụng Room database trong Android. Với Room database, nhưng thao tác đọc, ghi database trở lên dễ dàng hơn bao giờ hết.

Bạn có thấy như vậy không? Toàn bộ source code của bài hướng dẫn, các bạn download ở đây nhé. Download Complete Code

Hy vọng bài viết sẽ giúp các bạn làm được và hiểu chi tiết cấu trúc và làm các dự án nâng cao hơn sau này!

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

Xem thêm:

Tìm việc làm IT mọi cấp độ tại TopDev!

Tuyệt chiêu để team member và khách hàng lắng nghe bạn

Tuyệt chiêu để team member và khách hàng lắng nghe bạn

Bài viết được sự cho phép của tác giả Duy Phan

Kỹ năng lập trình không phải là thứ quan trọng nhất. Ở bất cứ ngành nghề nào, giao tiếp giữa người với người luôn luôn được đánh giá cao.

Khi trò chuyện với các project manager, bạn thỉnh thoảng sẽ nghe đến vài câu chuyện khủng khiếp về các lập trình viên mà họ từng làm việc chung.

Bạn được kể về những cử chỉ thô lỗ mà các lập trình viên đối xử với khách hàng, khiến cho các project manager hiếm khi dám mang các lập trình viên tham dự các cuộc họp của họ. Bạn cũng nghe về các lí do tồi tệ mà các lập trình viên đưa ra khi không hoàn thành một thứ gì đó cũng như việc trả lời khách hàng thô lỗ qua email.

Dù cho bạn có là lập trình viên hay đảm nhận bất cứ vị trí nào khác ở bất kỳ ngành nghề nào, điều này thực sự rất tồi tệ. Nó chắc chắn sẽ giới hạn khả năng của bạn, khiến bạn rất rất khó bức phá đến một vị trí cao cấp hơn. Có một kỹ năng giao tiếp tốt luôn luôn tốt hơn là chỉ có mỗi kỹ năng nghề nghiệp xuất sắc, và nó cũng cực kỳ giúp ích cho bạn để phát triển sự nghiệp bản thân sau này.

Nếu bạn có thể trở thành một người mà mọi người yêu quý, thì họ sẽ muốn làm việc chung với bạn, thuê và giới thiệu bạn với những đồng nghiệp hay những người quen khác, hay thậm chí dành cho bạn nhiều sự ưu ái, hay bất cứ gì khác hơn mà bạn không nghĩ đến. Họ cũng sẽ sẵn sàng nói ra những điều tốt đẹp về bạn khi bạn muốn phỏng vấn ở những nơi khác.

Bạn cần phải có kiến thức tốt, nhưng đừng chỉ dừng lại ở đây. Kỹ năng giao tiếp sẽ luôn là trụ cột quan trọng thứ hai cho sự nghiệp của hầu hết mọi người.

Tuyệt chiêu để team member và khách hàng lắng nghe bạn

Một chiến lược quan trọng để mọi người lắng nghe bạn – đó chính là bạn cần học cách lắng nghe họ.

Bất kể bạn có nắm giữ tất cả thông tin quan trọng và đang đứng thuyết trình giữa 20 con người khác trong một cuộc họp, nếu bạn không lắng nghe họ, họ cũng sẽ không có nghĩa vụ phải lắng nghe bạn.

Phát triển phần mềm là một dự án nhóm – team work

Các team tồi tệ nhất là team có nhiều người nóng tính và hay hờn dỗi. Họ không sẵn sàng chia sẻ suy nghĩ hay cảm xúc của họ. Họ tổ chức các cuộc họp không cấu trúc, không kế hoạch. Các thành viên lười nói chuyện, lười lắng nghe. Ai cũng có công việc riêng và không sẵn sàng chia sẻ. Không có sự lắng nghe sẽ không có sự hiểu biết. Không có sự hiểu biết sẽ không có sự hợp tác.

Ở một chiều hướng ngược lại, các team tuyệt vời luôn có những điếm nhấn cá nhân và đoàn thể riêng. Mọi người chờ mong cuộc họp, ai ai cũng chuẩn bị tốt hết sức có thể. Cuộc họp làm cho họ cảm thấy tốt, được đánh giá cao, có giá trị và có sự lắng nghe. Điều đó làm cả team có động lực, thoải mái và vui vẻ. Bạn sẽ dễ dàng tìm thấy sự hài hước của các thành viên trong các team như thế này.

Nếu bạn muốn trở nên tốt và tốt hơn khi làm việc với team, lắng nghe là kỹ năng số một mà bạn cần thành thạo. Hãy lắng nghe một cách tích cực và đưa ra những câu hỏi thông minh.

Trở thành người chủ động lắng nghe

Trở thành người chủ động lắng nghe

Nếu người bạn muốn nói chuyện cảm thấy thông điệp của họ được truyền tải, họ được lắng nghe và thấu hiểu, lúc đó họ sẽ cởi mở hơn khi lắng nghe những câu chuyện của bạn.

Trở thành một người biết chủ động lắng nghe là cách để bạn có được những gì bạn muốn.

Nếu muốn nhận được từ ai đó thứ gì, thì mình cần phải sẵn sàng cho người khác thứ mà họ cần.

Nói cách khác, bạn cần lắng nghe họ nếu bạn muốn họ giúp bạn điều gì đó. Thậm chí, khi bạn biết lắng nghe, họ sẽ giới thiệu một giải pháp tốt hơn với cái bạn nghĩ đến. Điều đó luôn luôn có thể xảy ra.

Điều quan trọng không phải ai là người có cái tôi lớn hơn, hay ai sẽ là người chiến thắng. Đó chính là quá trình làm việc hiệu quả và học hỏi lẫn nhau để trở nên tốt hơn. Bạn không bao giờ đạt được chúng nếu bạn cứ khư khư nghĩ rằng mình đã có toàn bộ câu trả lời mình muốn.

Một số nghiên cứu cho thấy có khoảng 60% những người tự cho mình là đúng thường có xu hướng đạt hiệu quả kém. Sự tự tin thái quá của họ đã ngăn cản việc thấu hiểu động lực của đối tác cũng như cả sự thành công của họ.

Nếu bạn nghĩ bạn biết tất cả, bạn là người đang thua cuộc.

Tôi càng học được nhiều bao nhiêu thì tôi lại càng nhận ra được mình thiếu hiểu biết bấy nhiêu. – Albert Einstein

Cuộc trò chuyện cũng như vậy. Bạn có thể nghĩ rằng bạn hiểu đối phương đang muốn gì, hay thậm chí có thể diễn giải mọi điều họ nói như minh chứng cho sự tự tin của mình. Nhưng hành vi này người ta gọi là thành kiến xác nhận – confirmation bias.

Wikipedia định nghĩa nó như sau:

Thành kiến xác nhận là xu hướng tìm kiếm, giải thích, ủng hộ cũng như nhớ lại thông tin theo cách tiếp cận, tự củng cố hay giả thuyết của bản thân. Nó là một kiểu thành kiến nhận thức.

Không có gì đặt một mối quan hệ bên bờ vực nguy hiểm nhanh hơn sự kém cỏi trong lắng nghe đối phương. Không mất quá nhiều thời gian để người khác nhận ra được thành ý của bạn khi nghe họ nói.

Bạn có biết chỉ có 7% thông điệp là những lời bạn nói hay không? (Nghiên cứu của giáo sư tâm lý học UCLA, Albert Mehrabian, phát hiện ra rằng 7% thông điệp được lấy qua từ ngữ, 38% qua ngữ điệu và 55% qua biểu cảm khuôn mặt hoặc ngôn ngữ cơ thể.)

Rất khó để thuyết phục người khác bạn đang lắng nghe họ trong khi bản thân bạn đang bán đứng chính mình.

  Team Leader là gì? Những kỹ năng nào mà một Team Leader cần có?

  5 câu hỏi phỏng vấn Project Manager nhà tuyển dụng hay hỏi nhất

Lắng nghe để trả lời hay lắng nghe để thấu hiểu?

Có một ranh giới giữa mỏng manh giữa lắng nghe để trả lời hay thấu hiểu.

Khi chúng ta lắng nghe để trả lời, chúng ta thường sẽ chăm chú tìm kiếm những sai sót trong ngôn từ của đối phương. Ngay khi chúng ta phát hiện ra một vài điều gì đó, cuộc trò chuyện sẽ bị gián đoạn, chúng ta trở nên như những con sói vồ vập xông vào cắn xé đối phương để bảo vệ niềm tin của mình.

Chúng ta ai cũng đều có thể làm như thế, và tôi cũng vậy. Cách duy nhất để ngăn chặn điều đó là ý thức được về nó.

Bạn sẽ bỏ lỡ rất nhiều thông tin giá trị nếu bạn xem nhẹ vấn đề này.

Chúng ta có một số mẹo nhỏ để vượt qua vấn đề, và khiến bạn dần trở nên một người biết tích cực lắng nghe.

  • Giữ trạng thái tò mò khi lắng nghe người khác trình bày, đừng vội giả định và đưa ra kết luận
  • Khi người kia nói, hãy lặp lại vài từ cuối cùng của họ. Làm điều đó với một giọng điệu tò mò, và giữ im lặng. Chỉ cần lặp lại ba từ cuối cùng và im lặng. Lặp đi lặp lại nhiều từ hơn sẽ khiến đối phương nghĩ bạn không hiểu và bắt đầu giải thích điều họ đang nói.
  • Bắt đầu câu hỏi với “Cái gì – What” và “Như thế nào – How“. Làm cách nào để chúng ta giải quyết vấn đề này? Bạn đã áp dụng các bước như thế nào để đạt được điều đó?…
  • Tránh bắt đầu câu hỏi với mệnh đề “Tại sao – Why“. Bạn liệu có nhớ khi còn bé, mẹ bạn bắt đầu la hét bạn: “Tại sao con lại phá đồ của mẹ?”. Khi lớn lên, bạn quay ra hỏi đồng nghiệp của mình: “Tại sao bạn lại sử dụng kiến trúc này?”, “Tại sao bạn không học thêm về lập trình web?”… Những câu hỏi như vậy đem lại cảm giác như lời buộc tội, kể cả khi bạn có ý định tốt. Tốt hơn hết, bạn nên đặt câu hỏi nào đó như: “Thư viện mà anh chọn có gì khác với những thư viện khác không?”, hoặc “Kiến trúc ABC có đặc điểm nào tốt hơn kiến trúc XYZ mà chúng ta thảo luận trước đó không?”…
  • Đừng sử dụng “Tôi hiểu – I understand” khi người khác đang giải thích. Nó giống như một lối tắt kém cỏi để thuyết phục người khác rằng bạn đang hiểu đúng hướng.

Nhiều tin tuyển dụng Project Manager lương cao trên TopDev, ứng tuyển ngay!

Cụm từ “Tôi hiểu – I understand” hay “Tôi biết rồi – I know” thường thường sẽ đi kèm với mệnh đề “Nhưng – But”. Đại loại nó mang ý nghĩa “Tôi hiểu rồi nhưng bạn vui lòng lắng nghe những gì tôi nói sau đây…“.

Khi người khác nói với bạn “Tôi hiểu”, thì thực sự họ dường như không có khái niệm gì về những vấn đề của bạn. Họ chỉ muốn bạn ngừng nói để họ có thể cho chúng ta biết ý kiến của họ. Họ mong đợi chúng ta nghĩ rằng mình đã được lắng nghe, nhưng họ đã làm tổn hại cuộc giao tiếp hơn họ nghĩ. Chúng ta không cần thiết phải làm điều đó.

Nếu bạn muốn cho người khác biết bạn đang tập trung lắng nghe, hãy sử dụng các từ mang tính chất xác nhận ngắn hạn, như “OK”, “Uhm”, “Ah”, “Vâng/Dạ – Yes”… Hoặc sử dụng các cụm câu “Có vẻ như bạn đang muốn…”, “Hình như điều này đang khiến bạn…”, “Dường như bạn đang khá thất vọng về…”. Đây là những cụm từ mang ý nghĩa hên xui, bạn có thể đúng hoặc sai. Quan trọng nhất, nó khiến ngươi khác thoải mái, do đối tượng hướng đến ở đây là họ, không phải nói về bạn. Thử đi rồi họ sẽ đưa lượt cho bạn.

  • Tóm tắt, tóm tắt, và tóm tắt. Sau khi bạn đã có được một bức tranh cơ bản về vấn đề và quan điểm của họ, bước tiếp theo là lặp lại cho họ hiểu “thế giới” của họ như thế nào.
  • Bạn sẽ đến lượt phát biểu của mình sau khi người khác nói với bạn: “Đúng rồi đấy – That’s right!”. Khi họ nói như vậy, bạn biết rằng bạn đã chốt và hiểu được một chút. Nhưng đừng nhầm lẫn khi họ nói “Anh đúng rồi – You’re right!”. Khi họ nói vậy có nghĩa là họ đang muốn thoát khỏi cuộc trò chuyện, và họ muốn bạn để họ một mình.

Khi bạn đã thể hiện được kỹ năng lắng nghe tích cực của mình, đây là lúc bạn bắt đầu trình bày quan điểm của bạn về vấn đề này. Và khi đối phương cảm thấy được bạn đã lắng nghe và hiểu được quan điểm của họ, họ sẽ sẵn sàng lắng nghe bạn hơn.

Họ cũng sẽ cởi mở hơn để hợp tác vào cuộc trò chuyện, thậm chí nhận định rằng cách của bạn là tốt nhất. Đó là mục đích của cuộc giao tiếp khi mà thành quả mọi người đạt được sẽ là “Win – Win”.

Bài viết gốc được đăng tải tại duypt.dev

Xem thêm:

Xem thêm nhiều việc làm IT hấp dẫn, lương cao tại TopDev

7 mẹo tạm biệt dirty code trong lập trình JS

7 mẹo tạm biệt dirty code trong lập trình JS

Bài viết được sự cho phép của tác giả Duy Phan

Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.

Tạm biệt dirty code trong lập trình JS
Tạm biệt dirty code trong lập trình JS

Khi chúng ta bước chân vào thế giới lập trình, chúng ta có thể thấy được những điều hữu ích mà nó đem lại cho hàng triệu người. Chỉ bằng việc thao tác với các đoạn code, lập trình đã giúp cho cuộc sống của chúng ta trở nên dễ dàng hơn.

Tuy nhiên, “năng lực lớn đi đôi với trách nhiệm lớn“. Trong thế giới lập trình, trách nhiệm lớn nhất của chúng ta không phải chỉ làm cho code chạy được, mà còn phải đảm bảo rằng các đoạn code mà chúng ta viết có thể dễ dàng kiểm tra và bảo trì trong một khoảng thời gian dài.

Có một số thói quen nhỏ trong lập trình có thể gây tác động tiêu cực liên tục đến code mà chúng ta viết và sản phẩm mà chúng ta tạo ra. Mình đã trải nghiệm những vấn đề này trực tiếp.

Hôm nay mình sẽ chia sẻ những vấn đề này và lý do tại sao bạn nên tránh chúng bằng mọi giá.

1. Sử dụng var thay vì let và const

Bạn nên chỉ sử dụng let và const bởi một vài lý do sau:

  • Scope rõ ràng hơn.
  • Nó không tạo ra các đối tượng global.
  • Với const – nó hiển thị lỗi ngay khi chúng ta cố gắng khai báo lại một biến.
// Sử dụng var:
var x = 10;
if (true) {
  var x = 20;
}
console.log(x); // Output: 20
// Khi chúng ta sử dụng var, biến có thể được khai báo lại và ghi đè giá trị của nó trong cùng phạm vi.

// Sử dụng let:
let y = 10;
if (true) {
  let y = 20;
}
console.log(y); // Output: 10
// Khi chúng ta sử dụng let, biến chỉ có thể được khai báo lại trong cùng khối lệnh và không ghi đè giá trị của nó ở ngoài khối lệnh đó.

// Sử dụng const:
const z = 10;
z = 20; // Error: Assignment to constant variable.
// Khi chúng ta sử dụng const, biến không thể được khai báo lại và không thể được ghi đè giá trị của nó.

Kể cả khi bạn muốn code của mình hoạt động ổn định với các trình duyệt cũ như IE11 thì bạn cũng không nên vứt bỏ nó. Hãy sử dụng let/const kèm với polyfill. Tuy vậy, 2023 rồi ai mà xài IE cũ nữa đâu, cả Microsoft cũng đã có kế hoạch xoá sạch IE rồi 😀

2. Dùng comments để mô tả code

Comments (hay chú thích) là một phần cơ bản trong quá trình xây dựng phần mềm, nó giúp chúng ta hiểu rõ hơn về đoạn mã mà chúng ta đang đọc.

Tuy nhiên, chúng ta không nên mắc phải sai lầm khi giải thích từng bước mà code của chúng ta đang làm, mà chúng ta phải tạo ra code dễ đọc. Comments chỉ nên cung cấp context (bối cảnh).

  • Tránh sự lặp lại trong comments của bạn. Đừng viết những gì bạn đang làm, hãy viết lý do tại sao bạn làm nó.
  • Hãy đặt các tên biến/function/class mô tả một cách rõ ràng công việc của chúng, thay vì ngồi viết một đống comments.
  • Hãy cố gắng viết code rõ ràng và clean hết sức có thể. Hãy nhớ, không phải code càng ngắn càng tốt, mà code rõ ràng, sạch sẽ, dễ thay đổi, dễ quản lý mới là tốt.
  • Viết comments rõ ràng, tốt nhất là cùng một ngôn ngữ (tiếng Anh, tiếng Việt…). Đừng viết chỗ này tiếng Anh, chỗ kia tiếng Việt, chỗ khác lại phang tiếng Trung Quốc vô 😀
  • Comments nên súc tích, gọn gàng. Theo thời gian, comments thường không được bảo trì, code lại thay đổi thường xuyên.

3. Sử dụng so sánh bằng (==) thay vì so sánh bằng nghiêm ngặt (===)

Mặc dù chúng có vẻ rất giống nhau về hình thức, tuy nhiên chúng lại có những điều khác nhau về cách hoạt động.

Toán tử so sánh bằng (==) sẽ cố gắng chuyển đổi các phần tử so sánh về cùng kiểu, sau đó thực hiện so sánh xem có giống nhau hay không. Điều này có thể gây ra một vài lỗi vớ vẩn không đáng có.

So sánh bằng nghiêm ngặt (===) luôn kiểm tra xem các toán hạng có các kiểu dữ liệu và giá trị khác nhau hay không.

Nên tránh sử dụng toán tử so sánh bằng (==) vì nó có thể gây ra các kết quả không mong muốn khi các phần tử so sánh có kiểu dữ liệu khác nhau. Nếu bạn sử dụng toán tử so sánh bằng nghiêm ngặt (===), bạn sẽ có thể kiểm tra xem các phần tử so sánh có giống nhau hoàn toàn không, bao gồm cả kiểu dữ liệu của chúng.

let x = 5;
let y = "5";

console.log(x == y); // true
console.log(x === y); // false

console.log([] == 0); // true
console.log([] === 0); // false

4. Không sử dụng optional chaining

Toán tử optional chaining (?) cho phép chúng ta đọc giá trị của một thuộc tính nằm sâu trong chuỗi các đối tượng liên kết mà không cần phải kiểm tra từng tham chiếu trong chuỗi đó.

const person = {
  name: "John",
  address: {
    city: "New York",
    street: "5th Avenue",
    zip: 12345
  }
};

const zipCode = person?.address?.zip; // 12345
const anotherInvalidAccess = person.invalidAddress.zip // Error
const anotherInvalidAccess = person.invalidAddress?.zip // undefined

Chúng ta nên sử dụng optional chaining trong các tình huống khi chúng ta không chắc chắn rằng một thuộc tính nào đó tồn tại trong đối tượng hoặc nó có giá trị là gì.

Sử dụng optional chaining giúp chúng ta tránh được những lỗi không mong muốn khi truy cập vào một thuộc tính không tồn tại, đồng thời cũng làm cho mã của chúng ta trở nên ngắn gọn và dễ đọc hơn.

  Kinh nghiệm để viết Clean Code trong JavaScript

  7 mẹo tạm biệt dirty code trong lập trình JS
Đừng viết switch case như này nữa!”]

5. Sử dụng magic strings, magic numbers…

Magic numbers và magic strings là các con số hoặc chuỗi được sử dụng trực tiếp trong code mà thường không có ngữ cảnh rõ ràng nhưng lại có mục đích.

Việc tốt nhất là gán các giá trị này cho các hằng số, vì nếu không làm như vậy, chúng có thể trở nên khó hiểu và gây ra lỗi trong quá trình debug.

function calculateArea(radius) {
  return 3.14 * radius * radius; // 3.14 là một magic number
}

Trong đoạn code trên, số 3.14 được gọi là magic number vì nó được sử dụng trực tiếp trong code mà không có một giải thích rõ ràng cho nó.

Chúng ta sửa lại như sau thì code sẽ clean hơn 😀

const PI = 3.14;
function calculateArea(radius) {
  return PI * radius * radius;
}

6. Truyền nhiều params vào function hay một single object chứa các params?

Việc truyền nhiều tham số hay truyền một đối tượng chứa nhiều tham số vào một hàm sẽ phụ thuộc vào từng trường hợp cụ thể và cách tiếp cận lập trình của từng người.

Tuy nhiên, khi truyền một đối tượng chứa nhiều params vào một hàm thì có thể giúp cho code dễ đọc hơn và dễ bảo trì hơn.

Ví dụ, việc truyền một đối tượng options vào hàm render() của một component có thể giúp cho việc hiểu rõ hơn những thiết lập khác nhau được truyền vào thành phần đó. Điều này thậm chí còn tốt hơn nếu chúng ta dùng kèm với Typescript.

Ngoài ra, việc truyền một object có thể giúp tránh tình trạng quên truyền params hoặc truyền params sai vị trí. Tuy nhiên, khi quá nhiều tham số được truyền vào một object, code có thể trở nên khó hiểu và khó bảo trì.

Do đó, cần cân nhắc và sử dụng phương pháp phù hợp với từng trường hợp cụ thể để có được code dễ đọc, dễ bảo trì và dễ mở rộng.

export interface IStartChargingSessionActionOptions {
  driverId: string
  chargerId: string
  projection: IFieldMapProjection
  input: IStartChargingSessionInput
}

@Injectable()
export class StartChargingSessionAction
  implements DomainActionObservable<IStartChargingSessionActionOptions>
{
  public constructor(private readonly _dataApiService: DataApiService) {}

  public handle({
    driverId,
    input,
    projection,
  }: IStartChargingSessionActionOptions): Observable<ChargingSession> {
    return scheduled(
      this._dataApiService.mutation<{
        chargingSessionCreate: ChargingSession
      }>({
        chargingSessionCreate: [
          {
            input: {
              ...input,
              chargerId,
              driverId,
              timeStart: new Date(),
            },
          },
          projection,
        ],
      }),
      asyncScheduler
    ).pipe(map(({ chargingSessionCreate }) => chargingSessionCreate))
  }
}

Xem thêm việc làm JavaScript hấp dẫn trên TopDev

7. Viết tắt khi check các giá trị falsy

Chúng ta đã từng gặp tình huống kiểm tra xem một biến có tồn tại hay không hoặc nó có chứa giá trị khác với null hoặc undefined không. Vì thế, chúng ta thường phải thực hiện kiểm tra rất dài như thế này:

if (x !== '' && x !== null && x !== undefined) {
  // Do something
}

Có một cách viết đơn giản và trang nhã hơn như sau:

if (!!x) {
  // Do something
}

Clean hơn nhiều đúng không 😀

Túm cái váy lại

Viết code sạch luôn là trách nhiệm của chúng ta. Mình đã học được rằng việc có một code dễ bảo trì và dễ đọc sẽ tiết kiệm được rất nhiều giờ làm việc cho bạn và team của bạn.

Hãy nhớ rằng chúng ta dành nhiều thời gian để đọc code hơn là viết code. Mình hy vọng những mẹo nhỏ này sẽ giúp cho bạn tạo ra những sản phẩm tuyệt vời và kỳ diệu.

Bài viết gốc được đăng tải tại duypt.dev

Xem thêm:

Xem thêm Việc làm IT hấp dẫn trên TopDev

Tổng quan về CQRS – Thiết kế hệ thống chịu tải lớn và dễ bảo trì

Tổng quan về CQRS – Thiết kế hệ thống chịu tải lớn và dễ bảo trì

Bài viết được sự cho phép của tác giả Lê Nhật Thanh

Target của bài viết: Những bạn muốn trở thành Senior backend developer hoặc mong muốn tìm hiểu CQRS là gì.

Một số thuật ngữ mình dùng trong bài viết các bạn có thể search thêm cụ Google để nắm hơn:

  • High availability: Một hệ thống website có tính sẵn sàng cao. Hoạt động liên tục 24/7 trong mọi điều kiện, kể cả khi có sự cố xảy ra.
  • High consistency: Tính nhất quán về dữ liệu, tất cả request của user đều thấy được dữ liệu mới nhất nếu nó được update.
  • Trade-off: Đánh đổi khi thiết kế hệ thống lớn

Bài viết này rất dài, có thể sẽ mất của bạn vài chục phút đến vài giờ để đọc và hiểu nội dung. Nhưng nó sẽ rất đáng nếu bạn bỏ ra từng ấy thời gian vì những gì bạn sẽ thu lại được. Mình đã cố gắng viết nó ra thì bây giờ đến lượt bạn, cố gắng đọc hiểu nó và góp ý thêm cho mình nha.

Let’s go!

Trước khi bắt đầu khám phá CQRS là gì, hãy xem xét một ứng dụng ví dụ sử dụng mô hình truyền thống (ví dụ MVC). Chúng ta sẽ sử dụng một dự án Rest API service với Java và Spring Boot framework.

MÔ HÌNH TRUYỀN THỐNG (VÍ DỤ SỬ DỤNG MVC)

Ở mức đơn giản, chúng ta thường có một cấu trúc thư mục quen thuộc với các tầng như ControllerServiceRepository và Model.

Trước khi vào bài thì mình có một yêu cầu nhỏ. Các bạn phải từng làm qua một framework backend rồi nha. Ví dụ NestJs, Laravel, .Net MVC hay gì cũng được. Hoặc các bạn đã nắm được về kiến trúc MVC. Hiểu thế nào là viewmodelcontrollerrepositoryservice, …

Trong bài viết này, mình sẽ lấy ví dụ với Java (Spring boot framework). Các bạn cũng đừng lo lắng. Vì nếu các bạn nắm được MVC rồi hoặc 1 trong các backend framework. Thì chúng ta cũng không cần quan tâm tới ngôn ngữ mình thể hiện trong bài viết nữa. Đừng quá phụ thuộc vào chúng, hãy cố gắng nắm được nội dung và hiểu nó.

MVC

Chúng ta sẽ tập trung vào tầng Model trước! Nếu bạn đã làm việc với hệ thống Backend thì bạn cũng đã thao tác rất nhiều với các Model.

À, từ đây đến hết bài viết, mình sẽ chia các HTTP request thành 2 loại:

  • Write side – hay còn gọi là Command side: Bao gồm tất cả các request chỉnh sửa vào database (POST, PUT, DELETE request)
  • Read side – hay còn gọi là Query side: Bao gồm tất cả các request dùng để lấy dữ liệu từ database (GET request)

Lưu ý là mình sẽ sử dụng 2 từ read side và write side trong xuyên suốt bài viết.

ĐI VÀO CODE MỘT CHÚT

Ok, mình sẽ lấy ví dụ triển khai một ứng dụng web báo điện tử. Ví dụ như VnExpress hay 24h,…

Giả sử mình có một model Article. Và khi các bạn thực hiện các API như createArticleupdateArticledeleteArticlegetArticleByIdgetAll, … thì bạn vẫn cứ phải thao tác với model Article.

Ví dụ vào code nha. Lưu ý là chúng ta chỉ quan tâm hàm create thôi nha.

Chúng ta có một cấu trúc thư mục cực kì quen thuộc với hầu hết các bạn.

com.lenhatthanh.blog/
|-- controller/
|   |-- ArticleController.java
|   `-- ...
|-- service/
|   |-- ArticleService.java
|   `-- ...
|-- repository/
|   |-- ArticleRepository.java
|   `-- ...
`-- model/
    |-- ArticleEntity.java
    `-- ...

Các bạn có thể đọc lướt qua cũng được. Vì các bạn đã quá quen thuộc với kiểu viết API backend như vậy.

// ArticleController.java
@RestController
@RequestMapping("/api/v1/articles")
@AllArgsConstructor
public class ArticleController {
    private ArticleServiceInterface articleService;

    @PostMapping
    @ResponseStatus(HttpStatus.CREATED)
    public void create(@RequestBody ArticleDto article) {
        articleService.create(article);
    }

    // Một số API khác như update, delete, getAll, getById, getByAuthor, ....
}
// ArticleService.java
@AllArgsConstructor
@Service
public class ArticleService {
    private ArticleRepository articleRepository;
    private UserRepository userRepository;

    public void create(ArticleDto articleRequest) {
        Optional<User> user 
                = userRepository.findById(articleRequest.getUserId());
        if (user.isEmpty()) {
            throw new UserNotFoundException("APPLICATION-ERROR-0001");
        }

        Article article = new Article(
                UUID.randomUUID().toString(),
                articleRequest.getTitle(),
                articleRequest.getContent(),
                user.get().getId(),
                articleRequest.getSummary(),
                articleRequest.getThumbnail(),
                articleRequest.getSlug(),
                // ...
        );

        articleRepository.save(article);
    }

    // Một số API khác như update, delete, getAll, getById, getByAuthor, ....
}
// ArticleRepository
@Repository
public interface ArticleRepository 
    extends JpaRepository<ArticleEntity, String> {
}

Repository trong Spring Boot thì khá lạ. Vì bạn chẳng thấy các method CRUD (create, read, update, delete) đâu cả. Vì ở đây Repository đang được kế thừa JpaRepository của Spring Data JPA trong Spring Boot. Và trong interface đó đã có hết toàn bộ những method CRUD và mở rộng hơn.

Bây giờ chúng ta sẽ đi qua model chính trong ứng dụng đơn giản này.

// ArticleEntity.java
@AllArgsConstructor
@NoArgsConstructor
@Data
@Builder
@Entity
@Table(name="articles")
public class ArticleEntity implements Serializable {
    @Serial
    private static final long serialVersionUID = 6009937215357249661L;

    @Id
    @Column(nullable = false, unique = true, length = 100)
    private String id;

    @Column(nullable = false)
    private String title;

    @Column(columnDefinition = "TEXT", length = 20000)
    private String content;

    @ManyToOne(fetch = FetchType.LAZY)
    private UserEntity user;

    @Column(columnDefinition = "TEXT", length = 1000)
    private String summary;

    @Column(nullable = false, unique = true)
    private String thumbnail;

    @Column(nullable = false, unique = true, length = 100)
    private String slug;

    // Một số properties khác nữa
    // ...
    // Bên dưới là business logic
    // Ví dụ: Slug chỉ được phép chứa các kí tự a-z, A-Z và dấu _
}

Ở trên đây, model Article của chúng ta làm tới 2 nhiệm vụ là mapping với một ORM để thao tác trực tiếp với database table. Và nhiệm vụ thứ 2 là lưu trữ state (trạng thái) của hệ thống. Ở đây là lưu trữ state của một Article trong vòng đời của một request.

Vấn đề ở đây là gì?

  Thiết kế hệ thống - Các hệ thống lớn như Facebook hoạt động như thế nào?

  MicroServices đôi khi không phải sự lựa chọn hoàn hảo

CODEBASE LỚN, KHÓ BẢO TRÌ NẾU KHÔNG DÙNG CQRS

Model trong một ứng dụng enterprise sẽ làm khá nhiều nhiệm vụ:

  • Lưu trữ trạng thái (như mình nói ở trên)
  • Mapping với database (cũng giống mình nói ở trên)
  • Cái tiếp theo là thông thường trong model sẽ chứa business logic. Mà business logic của những model lớn thường sẽ rất phức tạp. Về thuật ngữ business logic (hay domain logic, hay nghiệp vụ) thì các bạn có thể search google để biết nha. Cái này cũng khá là dễ hiểu.

Rõ ràng chúng ta chỉ có một model Article. Vì vậy các thao tác read side và write side đều phải thao tác qua model này.

Nghĩa là một model sẽ phải chứa tất cả business logic cho cả CRUD. Và khi ứng dụng càng lớn, business logic càng nhiều. Và thay đổi càng nhiều thì sẽ khiến cho model càng ngày càng phức tạp. Kể cả các tầng khác như Controller, Service, hay Repository cũng sẽ phức tạp hơn rất nhiều. Codebase lúc này sẽ phình to ra và dẫn tới việc bảo trì và mở rộng khó khăn hơn.

ĐẶC BIỆT LÀ KHI BẠN SỬ DỤNG ORM ĐỂ TƯƠNG TÁC VỚI DATABASE

  • Write side: Khi bạn thực hiện các API write side (create, update, delete) thì bạn dùng ORM để mapping database khá là đơn giản. Ví dụ create thì lưu 1 lần xuống toàn bộ thông tin của entity (ứng dụng lớn thì lưu cả cụm aggregate). Vì vậy thao tác về mặt code sẽ khá tường minh và đơn giản (cho dù có liên kết n-n hay 1-n,…).
  • Read side: Câu này mình sẽ nhắc nhiều trong bài viết: Ở read side thì số lượng use case (có thể coi 1 use case là 1 API đi cho dễ) sẽ vô cùng nhiều và đặc biệt khó dự đoán được. Ví dụ một số use case
    • Lấy danh sách bài viết cùng với summary để hiển thị ở khu vực recommend hoặc homepage (chỉ lấy title, thumbnail, summary)
    • Lấy danh sách bài viết của một tác giả (chỉ lấy title, thumbnail, summary)
    • Lấy danh sách bài viết trong tháng này.
    • Lấy danh sách bài viết có lượng truy cập cao trong (ngày, tuần, tháng, …)
    • Lấy danh sách bài viết theo category, kết hợp với ngày tháng, tác giả, …
    • v/v (còn rất nhiều use case khác nữa)

CHO NÊN

Khi bạn dùng ORM đối với rất nhiều use case như vậy và tương tác với chỉ một entity Article thì toang. Business logic trong model này sẽ trở nên phức tạp. Chưa nói là phải join tùm lum bảng (kết hợp nhiều entity). Và chưa nói tiếp tới vụ dư thừa dữ liệu và phức tạp khi join các bảng mà dùng ORM.

Và code base ở các file service, controller, repository cũng sẽ trở nên phức tạp theo. Vì có nhiều use case mà như mình có nói hồi nảy.

Và khi đó, đôi khi chúng ta phải thực hiện query thuần cho những API bên read side.

DƯ THỪA DỮ LIỆU

Trước khi mình nói về vấn đề dư thừa dữ liệu. Thì mình muốn nói thêm một ý khá quan trọng:

Write side chúng ta thường tao tác với hầu hết các field (trường dữ liệu) trong model (entity). Ví dụ tạo một article thì chúng ta sẽ thao tác gần như tất cả các field trong một entity. Nhưng read side thì không như vậy, đôi khi chỉ thao tác với một vài trường dữ liệu trong một entity. Hoặc kết hợp nhiều entity với nhau (join nhiều bảng một lần) – như mình nói ở các use case read site ở trên.

Ngoài ra thì hầu hết các hệ thống web application, các request read side thường chiếm phần lớn trong hệ thống. Ví dụ một trang thương mại điện tử, người bán hàng tạo một sản phầm và publish nó (write side). Và người bán chỉ tạo một lần đó thôi, còn lại hầu hết các request từ user khác đến sản phẩm đó là read side, ví dụ xem chi tiết sản phẩm, sản phẩm tương tự, search, …

Cũng vì lý do read side và write side đều được xử lý thông qua một model duy nhất. Nên đôi khi sẽ làm chúng ta bị dư thừa dữ liệu, đặc biệt ở read side.

Tham khảo Web Developer Jobs HOT tại TopDev

MÌNH LẤY VÍ DỤ

  • Giả sử ArticleEntity ở trên có khoảng vài chục trường dữ liệu (ở trên thì mình chỉ lấy ví dụ có vài trường dữ liệu thôi). Thì khi chúng ta thực hiện tạo mới một article, thì rõ ràng khá bình thường, chúng ta sẽ lưu cả entity xuống database (cùng với đó là thêm thông tin userId để biết đang của tác giả nào).
  • Nhưng khi ở read side, giả chúng ta chỉ lấy vài trường dữ liệu để hiển thị. Nhưng chúng ta phải query hết toàn bộ dữ liệu rồi map vào entity. Và rồi loại bỏ dữ liệu dư thừa rồi trả ra view cho user. Và như mình nói thì ở read side rất đa dạng các kiểu get dữ liệu lên. Mà mỗi lần get dữ liệu lên lại phải get hết thông qua entity thì bị dư thừa (còn tạo nhiều model khác ứng với mỗi trường hợp get dữ liệu thì codebase sẽ loạn lên). Hoặc là kiểu join nhiều bảng, ráp một ít dữ liệu của entity này và một ít dữ liệu của entity khác. Tình trạng dư thừa dữ liệu khi get data lên (rồi mapping thông qua ORM) là rất nhiều.

KHẢ NĂNG CHỊU TẢI KÉM

Chúng ta chỉ thao tác với một database duy nhất nên việc khả năng chịu tải kém lá đúng. Đột nhiên một lúc nào đó, hàng triệu request read side tới hệ thống thì hệ thống sẽ tạch ngay. Cho dù bạn có scale hệ thống bằng cách như tăng cấu hình phần cứng, load balancing, … thì request cao vẫn sẽ tạch, vì database connection lúc này rất nhiều. Database lúc này sẽ trở thành điểm bottlenecks (nút thắt cổ chai).

Ở ngay đây (hơi ngoài lề một chút), nhiều bạn sẽ cho rằng, chúng ta sẽ dùng một cache server để handle.

Và thông thường các bạn chưa có kinh nghiệm sẽ triển khai một ứng dụng với Cache database như thế này.

  • Ở read side, khi có request tới cache, nếu không có trong cache (miss cache) thì chui xuống database để lấy thông tin. Cách này, cũng tạm được, sẽ giảm tải được khá nhiều cho database, nhưng ở ngoài hệ thống lớn, người ta không làm như vậy.
  • Lý do là vì: khi hàng triệu use truy xuất tới một endpoint bị miss cache và đều chui xuống database thì trường hợp này cũng sẽ tạch. Ví dụ mấy sàn thương mại điện tử vào dịp 9/9 hay 10/10 tổ chức flash sale. Thì các trường hợp hàng triệu user truy cập vào một endpoint là điều bình thường.

Cho nên triển khai như vậy sẽ không hợp lý đối với một hệ thống real world.

CQRS (Command Query Responsibility Segregation) là một mô hình kiến trúc phát triển ứng dụng. Nổi tiếng với khả năng tách biệt quyền truy vấn (Query) và quyền thực hiện lệnh (Command).

Nói cách dễ hiểu hơn! Thì read side và write side được tách biệt hoàn toàn không còn dính tới nhau nữa. Khác hoàn toàn với cách xử lý truyền thống ở trên.

Và bên write side người ta gọi là command, bên read side người ta gọi là query.

Biết được CQRS là gì rồi, tiếp thôi nào!

LỢI ÍCH CỦA CQRS LÀ GÌ?

  • Tăng khả năng mở rộng: CQRS cho phép các command và query được xử lý riêng biệt. Điều này có thể giúp tăng khả năng mở rộng của hệ thống.
  • Tăng hiệu suất: CQRS có thể giúp tăng hiệu suất của hệ thống bằng cách cho phép các command và query được xử lý theo cách tối ưu nhất cho từng loại.
  • Tăng khả năng bảo trì: CQRS có thể giúp tăng khả năng bảo trì của hệ thống bằng cách tách biệt các command và query. Điều này có thể giúp các anh dev dễ dàng sửa đổi hoặc nâng cấp hệ thống hơn.
  • Tăng khả năng tái sử dụng: CQRS có thể giúp tăng khả năng tái sử dụng của hệ thống bằng cách tách biệt các command và query. Điều này có thể giúp các dev dễ dàng reuse lại các thành phần trong hệ thống

Những lợi ích ở trên đây mình chỉ tóm tắt thôi.

Để biết chi tiết hơn về lợi ích của CQRS là cái gì. Thì chúng ta đi sâu hơn một chút nhé.

Nếu doanh nghiệp nghèo chỉ có tiền thuê được một server database. Thì chúng ta vẫn sẽ áp dụng CQRS để đơn giản hoá codebase trước.

CQRS

Bây giờ chúng ta sẽ tổ chức cấu trúc thư mục lại áp dụng CQRS nha. Tổ chức cấu trúc thư mục là hoàn toàn linh hoạt đối với từng project và từng team. Nên đối với CQRS sẽ có khá nhiều cách tổ chức cấu trúc thư mục. Mình thì muốn tách ra hoàn toàn thành 2 phần khác nhau.

Các bạn có thể tách ra thành 2 repository (github) hoàn toàn tách biệt luôn.

com.lenhatthanh.blog.command/
|-- controller/
|   |-- ArticleController.java (create, update, delete)
|   `-- ...
|-- service/
|   |-- ArticleService.java
|   `-- ...
|-- repository/
|   |-- ArticleRepository.java
|   `-- ...
`-- model/
    |-- ArticleEntity.java
    `-- ...
com.lenhatthanh.blog.query/
|-- controller/
|   |-- ArticleController.java (all get requests)
|   `-- ...
|-- service/
|   |-- ArticleService.java
|   `-- ...
|-- repository/
|   |-- ArticleRepository.java (ở đây có thể sử dụng query thuần)
|   `-- ...
`-- model/
    |-- Các Model tương ứng với từng use case
    `-- ...

Khi apply CQRS, số lượng file có thể sẽ tăng lên, nhưng đó không phải là vấn đề. Vì lúc này code base đã được tách ra thành 2 phần riêng biệt. Code base lúc này rất dễ bảo trì và mở rộng.

TỐI ƯU HÓA CODE BASE WRITE SIDE

  • Đương nhiên rồi! chúng ta sẽ sử dụng ORM ở write side là quá tuyệt vời (dễ code, dễ bảo trì và cực kì tường minh).
  • Và đối với ứng dụng enterprise, chúng ta có thể dùng Domain Driven Design để có thể tập trung toàn bộ business phức tạp lại một chổ (ở core domain). Để ứng dụng có thể dễ dàng mở rộng về mặt codebase khi business thay đổi hoặc tăng lên phức tạp. Ngoài ra chúng ta có thể kết hợp thêm Clean Architecture để có một cấu trúc code base tốt hơn. Nhưng không phải bạ đâu cũng dùng nha các bạn.
  • Ngoài ra ORM còn giúp chúng ta nhiều thứ hơn như về ngăn chặn các vấn đề security (như SQL injection,…).

TỐI ƯU HÓA CODE BASE READ SIDE

  • Như mình đã nói thì số lượng request và use case ở đây cực kì phức tạp. Nên chúng ta có thể dùng query thuần (không dùng ORM) ở phần read side (trong trường hợp ứng dụng của bạn chỉ có một database ví dụ MySQL). Khi sử dụng query thuần thì code sẽ đở phức tạp đi rất nhiều so với dùng ORM ở read side. Bạn có thể thử dùng ORM và join nhiều bảng cùng với mỗi bảng thì lấy một ít dữ liệu sẽ thấy ngay vấn đề.

Sau khi tối ưu về mặt codebase như trên thì chúng ta sẽ có một thiết kế như sau:

TỐI ƯU HÓA CODE BASE READ SIDE

Nhưng trên thực tế. Nếu đã apply CQRS thì ít ai chỉ tối ưu về mặt codebase mà không tối ưu về mặt database và server. Vì tối ưu về khả năng chịu tải là một vấn đề lớn nếu apply kiến trúc ở trên.

Khi sử dụng CQRS pattern, chúng ta có thể tách riêng hoàn toàn ra 2 server riêng biệt là Write side server và read side server. Và ứng với mỗi side, chúng ta sẽ có database riêng biệt.

SCALE ĐỘC LẬP VỚI NHAU NẾU LƯỢNG REQUEST TĂNG LÊN ĐỘT BIẾN

Bởi vì thông thường lượng request ở Read side chiếm phần lớn, nên bạn sẽ dễ dàng scale server (phần cứng hoặc instance nếu sử dụng cloud services) ở Read side. Ví dụ tăng cấu hình server lên hay tăng số lượng server lên. Hoặc sử dụng database chuyên dụng cho read data như Redis, mongoDB

Còn bên write side thì cũng có thể scale độc lập như vậy.

TỐI ƯU HOÁ PHẦN CỨNG CHO MỖI SERVER

Chúng ta có thể lắp các loại ổ cứng, ram chuyên cho đọc hay ghi tương ứng ở mỗi server read hay write (on-premise). Còn nếu chúng ta sử dụng cloud service có thể dễ dàng lựa chọn các service phù hợp cho mỗi side của ứng dụng.

SAU KHI SCALE XONG THÌ CHÚNG TA SẼ CÓ DESIGN SAU

cqrs-server-optimize

Ở hình trên mình đã dùng Kafka (một message queue) để có thể sync data bất đồng bộ từ write side sang read side.

Và ví dụ bên dưới sẽ cho các bạn thấy mình sẽ dễ dàng scale hệ thống như thế nào. Ở design dưới thì mình scale về database là chính.

cqrs-distributed-database-scaled

  • Mình có design một message queue (mình dùng Kafka) ngay trước khi ghi dữ liệu vào write database. Bởi vì lý do là nếu chạy đồng bộ (sync) thì ngay write database sẽ dễ trở thành một nút thắt cổ chai khi lượng request write tăng đột biến.
  • Ở write database thì mình dùng một Replica database. Và coi như là một backup trong trường hợp server bị chết.
  • Một message queue để đồng bộ dữ liệu từ write database sang read database.
  • Ở read database nếu lượng request quá nhiều và dữ liệu quá lớn. Thì mình có thể design nó thành một hệ thống database distributed (phân tán) để chịu tải tốt hơn và high availability hơn.
  • Ngoài ra chúng ta cũng có thể sử dụng K8S auto scaling instance cho ứng dụng của mình đặc biệt bên read side cho hệ thống ở trên.

Tới đây thì chúng ta đã biết CQRS là cái gì rồi. CQRS hay như thế đấy! Nhưng vẫn sẽ có một vài điểm đánh đổi (trade-off). Chúng ta cùng tìm hiểu tiếp.

TÍNH NHẤT QUÁN VỀ DỮ LIỆU (DATA CONSISTENCY)

Đây chính là một loại đánh đổi (trade-off) khi chúng ta triển khai các hệ thống lớn.

Đây có thể xem là vấn đề lớn nhất khi áp dụng CQRS. Hay những pattern khác mà sử dụng event driven architecture (sử dụng Kafka đó bạn). Bởi vì data được sync bất đồng bộ từ write side lên read side nên dữ liệu sẽ không nhất quán (inconsistency).

Khi dữ liệu được tạo hoặc update bên write side. Thì đôi khi phải mất một khoảng thời gian nhất định thì dữ liệu đó mới sync qua được read side. Nhất là trong những lúc cao điểm, request tăng cao dẫn tới server chịu tải nhiều hơn.

TÍNH NHẤT QUÁN VỀ DỮ LIỆU (DATA CONSISTENCY)

BÂY GIỜ CHÚNG TA SẼ NÓI MỘT CHÚT VỀ TRADE-OFF

Nếu chúng ta muốn dữ liệu consistency (nhất quán). Nghĩa là dữ liệu bên write side update sao thì tất cả các request bên read side luôn trả về dữ liệu mới nhất. Thì ở đây chúng ta có thể sử dụng cơ chế sync (đồng bộ) thay vì async (bất đồng bộ). Ví dụ như sử dụng Rest API để sync dữ liệu luôn. Như vậy chúng ta sẽ có dữ liệu high consistency. Nhưng chúng ta sẽ phải đánh đổi thời gian response ở write side. Và khi lượng request tăng cao có thể dẫn tới server quá tải và không thể handle request. Dẫn tới tính availability sẽ thấp xuống.

Và đương nhiên ngược lại, nếu chúng ta muốn high availability thì phải đánh đổi với consistency.

Tùy vào business của hệ thống mà chúng ta (là những engineer) lựa chọn về việc đánh đổi khi triển khai hệ thống lớn.

Đối với một số hệ thống không cần yêu cầu về tính chất consistency tuyệt đối như báo điện tử (24h, VnExpress), media,… Chúng ta có thể đặt tính availability lên trên consistency và có thể sử dụng design ở hình trên. Lúc này chúng ta sẽ có khái niệm eventual consistency (nghĩa là không hoàn toàn nhất quán).

PHỨC TẠP HOÁ VÀ CHI PHÍ CAO

Câu mình muốn nói là: Không phải lúc nào cũng apply CQRS nếu không muốn tăng độ phức tạp của project.

Các bạn có thể thấy những hình ở trên, để triển khai một hệ thống lớn áp dụng CQRS và event driven architecture (và những pattern khác). Thì mọi thứ sẽ phức tạp hơn rất nhiều từ việc nhân sự, đội ngũ, đến cách tổ chức code. Và đặc biệt là hệ thống server sẽ nhiều hơn.

Hệ thống server nhiều (service nhiều) sẽ đi kèm với độ phức tạp cũng tăng lên rất nhiều. Như khi chúng ta monitor, xử lý, khôi phục hệ thống khi lỗi, … Vâng, và đó cũng là một kiểu trade-off cho chúng ta.

Thiết kệ hệ thống lớn, chúng ta phải đưa ra lựa chọn!

Trong hành trình khám phá CQRS là gì này, chúng ta đã thấy những ưu và nhược điểm của mô hình này. CQRS không phải là một giải pháp đối với tất cả các ứng dụng. Nhưng nó có thể là lựa chọn mạnh mẽ cho những ứng dụng đòi hỏi hiệu suất cao và tính mở rộng.

Nhớ rằng, quá trình triển khai CQRS có thể phức tạp, nhưng nếu được thực hiện đúng cách. Nó có thể đem lại lợi ích lâu dài cho sự phát triển và bảo trì của ứng dụng. Hãy cân nhắc kỹ lưỡng và kiểm soát mỗi quyết định để đảm bảo rằng CQRS phản ánh đúng nhu cầu của dự án của bạn.

Chúc các bạn thành công trong việc xây dựng các hệ thống mạnh mẽ và linh hoạt!

Các bạn có thể tham khảo source code mình có demo một chút về CQRS là cái gì ở link sau: lenhatthanh20/news-website (github.com)

À còn một ý nữa. Khi bạn search những bài viết kiểu CQRS là gì trên google. Thì nó ra khá nhiều các title như Event sourcing, Event Driven Architecture, DDD… Các bạn có thời gian thì tìm hiểu thêm nha. Mình chỉ muốn trình bày only CQRS là cái gì trong bài viết này thôi.

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

Xem thêm:

Xem thêm các vị trí IT Job hấp dẫn trên TopDev

Vietnam Mobile Summit 2024 – Những bước tiến mới trong công nghệ AI và Chiến lược xây dựng sản phẩm

Vietnam Mobile Summit 2024

Ngày 31.05.2024 vừa qua, TopDev đã tổ chức thành công sự kiện Vietnam Mobile Summit với chủ đề “Mobile & Life”. Thu hút đông đảo sự quan tâm của cộng đồng công nghệ, sự kiện đã mang đến những chia sẻ chuyên sâu về các xu hướng công nghệ di động mới nhất, cũng như những giải pháp sáng tạo ứng dụng trí tuệ nhân tạo (AI) và kinh nghiệm phát triển sản phẩm từ các chuyên gia đầu ngành.

Điểm nhấn cho sự kiện lần này đến từ 2 phiên thảo luận từ các chuyên gia công nghệ đến từ nhiều công ty, doanh nghiệp nổi tiếng với chủ đề: “AI FOR FUTURE”“Creating Harmony Between Designers, Developers and Stakeholders”. Ngoài ra, phiên pitching đặc biệt của K-Global@2024 – các startup công nghệ hàng đầu Hàn Quốc, cũng đã để lại ấn tượng mạnh mẽ trước các nhà đầu tư, chuyên gia và khán giả tham gia tại sự kiện Vietnam Mobile Summit 2024.

Khám phá tiềm năng to lớn của AI tại Việt Nam

Trí tuệ nhân tạo (AI) đang trở thành một phần không thể thiếu trong đời sống và kinh tế hiện đại. Với sự phát triển không ngừng, AI đang mở ra những cơ hội mới và đồng thời đặt ra những thách thức cần được giải quyết. Theo anh Đinh Lê Vũ – Global Senior Manager tại Qualcomm, Việt Nam sở hữu nhiều lợi thế để trở thành trung tâm phát triển AI trong khu vực nhờ sở hữu lực lượng dân số trẻ, năng động, nguồn nhân lực dồi dào và khả năng thích ứng nhanh chóng với công nghệ mới. Tuy nhiên, bên cạnh đó cũng tồn tại một số thách thức như thiếu sự đồng bộ trong phát triển, nguồn vốn đầu tư hạn chế và hệ sinh thái khởi nghiệp còn khá non trẻ.

Vietnam Mobile Summit 2024
PANEL DISCUSSION #1: AI FOR FUTURE với sự góp mặt của các diễn giả Vanessa Phan, Nguyễn Việt Phương, Quân Nguyễn, Đinh Lê Vũ, Jaymie Võ

Cũng theo anh Vũ, top 3 lĩnh vực tiềm năng nhất cho việc ứng dụng và phát triển AI tại Việt Nam là ngành bán lẻ, ngân hàng và dịch vụ lưu trú. Theo quan điểm của các chuyên gia, việc xây dựng mô hình AI không chỉ dừng lại ở tốc độ và độ chính xác mà còn phải làm cho nó thấu hiểu nhu cầu của người dùng để nâng cao trải nghiệm khách hàng. Đây chính là điểm mấu chốt giúp các doanh nghiệp thành công khi bắt tay vào đầu tư xây dựng hệ thống AI.

Bên cạnh đó, phiên thảo luận cũng đưa ra một số lời khuyên hữu ích dành cho các bạn fresher mới vào nghề cũng như các chủ doanh nghiệp, những người làm sản phẩm. Với Fresher IT cần trau dồi tiếng Anh và kỹ năng giao tiếp để hòa nhập môi trường làm việc quốc tế. Những người làm sản phẩm thì cần cân bằng giữa kỹ thuật và nhu cầu thị trường để tạo ra sản phẩm AI mang lại giá trị thực tiễn. Còn đối với doanh nghiệp, cần phải xác định rõ mục tiêu sử dụng AI trước khi tìm kiếm giải pháp phù hợp.

Hành trình từ phát triển ý tưởng đến xây dựng sản phẩm

Tại panel “Creating Harmony Between Designers, Developers and Stakeholders”, khán giả đã có cơ hội được lắng nghe các chiến lược giao tiếp và hợp tác hiệu quả, đồng thời khám phá các câu chuyện thành công từ quá trình lên ý tưởng đến thực thi sản phẩm của những diễn giả uy tín đến từ Tanca, VPBank, GEEK Up, ELSA Corp và RegenX.

Vietnam Mobile Summit 2024
PANEL DISCUSSION #2: Creating Harmony Between Designers, Developers and Stakeholders với sự góp mặt của các diễn giả Trần Viết Quân, Tony Lê, Hoàng Nguyễn, Sơn Vũ, Nguyễn Anh Tuấn

Anh Hoàng Nguyễn từ GEEK Up đã chia sẻ về quá trình phát triển sản phẩm từ việc lên ý tưởng đến cách làm việc với khách hàng và tung sản phẩm ra thị trường. Theo anh, đội ngũ Product Analytics của GEEK Up luôn bắt đầu bằng việc trao đổi và tìm hiểu kỹ lưỡng những mong muốn và ý tưởng của đối tác. Sau đó, họ tiến hành thiết kế và thử nghiệm sản phẩm ở quy mô nhỏ để đánh giá hiệu quả trước khi triển khai rộng rãi.

Vietnam Mobile Summit 2024
Anh Hoàng Nguyễn từ GEEK Up chia sẻ về quá trình phát triển sản phẩm từ việc lên ý tưởng đến cách làm việc với khách hàng và tung sản phẩm ra thị trường

Bên cạnh đó, GEEK Up áp dụng mô hình co-partner, kết hợp ưu điểm của cả công ty outsource và inhouse để tối ưu hóa hiệu quả dự án. Sự phối hợp chặt chẽ giữa đội ngũ GEEK Up và các team inhouse của khách hàng giúp dự án tiến triển nhanh chóng và đạt được kết quả tốt nhất. Khi sản phẩm được tung ra thị trường, nếu có bất đồng về tầm nhìn sản phẩm, hai bên sẽ dựa trên các insight khách hàng để thử nghiệm các giả định khác nhau, đảm bảo sản phẩm cuối cùng phù hợp nhất với nhu cầu thị trường.

K-Global@2024: Cầu nối công nghệ Việt – Hàn

Phần pitching của K-global@Vietnam 2024 là một trong những điểm nhấn tại Vietnam Mobile Summit năm nay. Được xem như một cầu nối công nghệ giữa hai quốc gia, chương trình là nơi hội tụ của những chuyên gia CNTT hàng đầu đến từ xứ sở kim chi.

K-global@Vietnam 2024
Gian hàng của K-global@Vietnam 2024 tại Vietnam Mobile Summit 2024

Các startup Hàn Quốc tham gia đã mang đến một bức tranh công nghệ đa sắc màu, phản ánh sự đa dạng và sáng tạo của hệ sinh thái di động. Từ trí tuệ nhân tạo (AI) ứng dụng trong giáo dục và y tế, đến các giải pháp bảo mật tiên tiến; từ ứng dụng doanh nghiệp tối ưu hóa quy trình làm việc, đến những trải nghiệm AR/VR/XR đầy sáng tạo – mỗi bài thuyết trình đều là một lời khẳng định về năng lực và tầm nhìn của các nhà phát triển tại Hàn Quốc.

K-global@Vietnam 2024
Người tham dự tham gia trải nghiệm các sản phẩm công nghệ tại các gian hàng của K-global@Vietnam

Không chỉ là nơi giới thiệu sản phẩm, K-global@Vietnam 2024 còn là một workshop học hỏi lẫn nhau. Các startup Việt Nam học được cách tiếp cận thị trường quốc tế, trong khi các đối tác Hàn Quốc có cơ hội hiểu sâu về hành vi người dùng và môi trường kinh doanh độc đáo của Việt Nam. Chương trình cung cấp nhiều chuyên đề về các xu hướng công nghệ mới nhất, giúp doanh nghiệp Việt Nam cập nhật kiến thức và nâng cao năng lực cạnh tranh.

Tổng kết

Vietnam Mobile Summit 2024 không chỉ là nơi thảo luận về công nghệ mà còn là sân chơi kết nối giữa các chuyên gia, doanh nghiệp và startup hàng đầu. Từ AI đến phát triển sản phẩm, từ thị trường nội địa đến quốc tế, sự kiện đã phác thảo một tương lai đầy hứa hẹn cho ngành di động Việt Nam. Với sự đổi mới không ngừng và tinh thần hợp tác, ngành công nghiệp này chắc chắn sẽ tiếp tục phát triển mạnh mẽ, khẳng định vị thế của Việt Nam trên bản đồ công nghệ toàn cầu.

TOP 35 câu hỏi phỏng vấn Docker và cách trả lời hay nhất (Phần 3)

câu hỏi phỏng vấn Docker

Bài viết được sự cho phép của tác giả Nguyễn Thành Nam

Để giúp bạn chuẩn bị tốt nhất cho các cuộc phỏng vấn liên quan đến Docker, TopDev đã tổng hợp danh sách TOP 35 câu hỏi phỏng vấn Docker và cách trả lời hay nhất. Bỏ túi ngay để có một buổi phỏng vấn thật thành công bạn nhé.

21. Docker volume được lưu ở đâu trong docker?

Volume được tạo và quản lý bởi Docker và không thể truy cập bằng thực thể khác docker. Nó được lưu trữ trong hệ thống file host Docker ở /var/lib/docker/volumes/.

22. Lệnh docker info là gì?

Lệnh lấy thông tin chi tiết về Docker được cài đặt trên hệ thống host. Thông tin có thể giống như số lượng container hoặc image và chúng đang chạy ở trạng thái nào và các thông số kỹ thuật phần cứng như tổng bộ nhớ được cấp phát, tốc độ của bộ xử lý, phiên bản kernel,…

23. Ý nghĩa của các lệnh up, run và start của docker compose?

  • Sử dụng lệnh up để duy trì docker-compose (lý tưởng là mọi lúc), chúng ta có thể khởi động hoặc khởi động lại tất cả các mạng, dịch vụ và driver được liên kết với ứng dụng được chỉ định trong file docker-compos.yml. Bây giờ, nếu chúng ta đang chạy docker-compose ở chế độ “attached” thì tất cả log từ các container sẽ có thể truy cập được đối với chúng ta. Trong trường hợp docker-compose được chạy ở chế độ “detached”, thì khi các container được khởi động, nó sẽ thoát ra và không hiển thị log nào.
  • Sử dụng lệnh run, docker-compose có thể chạy các tác vụ một lần hoặc đột xuất dựa trên các yêu cầu nghiệp vụ. Ở đây, tên dịch vụ phải được cung cấp và docker chỉ bắt đầu dịch vụ cụ thể đó và cả các dịch vụ khác mà dịch vụ đích phụ thuộc (nếu có). Lệnh này hữu ích để kiểm tra container và cũng thực hiện các tác vụ như thêm hoặc xóa dữ liệu vào container,…
  • Sử dụng lệnh start, chỉ những container đó mới có thể được khởi động lại đã được tạo và sau đó dừng lại. Điều này không hữu ích cho việc tạo các container mới của riêng nó.

24. Các yêu cầu cơ bản để Docker chạy trên mọi hệ thống?

Docker có thể chạy trên cả nền tảng Linux và Windows.

  • Đối với nền tảng Windows, ít nhất docker cần có Windows 10 64bit với bộ nhớ RAM 2GB. Đối với các phiên bản thấp hơn, có thể cài đặt docker bằng cách sử dụng toolbox trợ giúp. Docker có thể được tải xuống từ trang web https://docs.docker.com/docker-for-windows/.
  • Đối với nền tảng Linux, Docker có thể chạy trên nhiều phiên bản Linux khác nhau như Ubuntu> = 12.04, Fedora> = 19, RHEL> = 6.5, CentOS> = 6, v.v.

25. Cách đăng nhập vào docker registry?

Sử dụng lệnh docker login để đăng nhập vào kho lưu trữ đám mây của riêng họ có thể được nhập và truy cập.

26. Các instructions phổ biến trong Dockerfile?

  • FROM: dùng cho thiết lập image cơ sở cho instruction sắp tới. File docker được xem là hợp lệ nếu nó bắt đầu bằng FROM.
  • LABEL: dùng cho tổ chức image dựa trên dự án, module hoặc license. Nó còn giúp tự động hoá như một cặp key-value cụ thể trong khi xác định label mà sau này có thể được truy cập và xử lý theo chương trình.
  • RUN: dùng cho thực thi instruction theo sau nó trên top image hiện tại trong lớp mới. Lưu ý: mỗi lần thực thi lệnh RUN, chúng ta thêm các lớp trên image và sử dụng lớp đó cho các bước tiếp theo.
  • CMD: dùng cho cung cấp giá trị mặc định của container thực thi. Trong trường hợp nhiều lệnh CMD, lệnh cuối cùng sẽ được xem xét.

27. Sự khác biệt giữa Daemon Logging và Container Logging?

Trong Docker, logging được hỗ trợ ở hai level là level Daemon và level Container.

  • Daemon: gồm 4 kiểu level
    • Debug có tất cả dữ liệu xuất hiện trong quá trình thực thi của tiến trình daemon.
    • Info quan tâm tất cả thông tin cùng với lỗi trong suốt quá trị thực thi tiến trình daemon.
    • Error gồm các lỗi xảy ra trong quá trình thực thi tiến trình daemon.
    • Fatal chức lỗi fatal trong quá trình thực thi tiến trình daemon.
  • Container:
    • Level container có thể thực hiện logging bằng lệnh: sudo docker run –it <container_name> /bin/bash.
    • Để kiểm tra log của level container ta có thể thực hiện: sudo docker logs <container_id>.

28. Cách thiết lập giao tiếp giữa docker host và linux host?

Điều này có thể được thực hiện bởi mạng bằng cách xác định “ipconfig” trên docker host. Lệnh này đảm bảo rằng một adapter ethernet được tạo miễn là docker có mặt trong host.

29. Cách xoá một container?

Ta có hai bước xoá container:

  1. docker stop <container_id>
  2. docker rm <container_id>

30. Sự khác biệt giữa CMD và ENTRYPOINT?

  • Lệnh CMD cung cấp các giá trị mặc định có thể thực thi cho một container đang thực thi. Trong trường hợp file thực thi phải được bỏ qua thì việc sử dụng lệnh ENTRYPOINT cùng với định dạng mảng JSON phải được kết hợp.
  • ENTRYPOINT chỉ định rằng lệnh bên trong nó sẽ luôn được chạy khi container khởi động. Lệnh này cung cấp một tùy chọn để cấu hình các tham số và các file thực thi. Nếu DockerFile không có lệnh này, thì nó sẽ vẫn được kế thừa từ image cơ sở được đề cập trong lệnh FROM.
  • ENTRYPOINT được sử dụng phổ biến nhất là /bin/sh hoặc /bin/bash cho hầu hết các image cơ sở.

Thực tế, tất cả Dockerfile nên có ít nhất một trong hai lệnh.

31. Có thể dùng JSON thay cho YAML khi phát triển docker-compose trong Docker không?

Có thể. Ta có thể chạy docker-compose trong json, như

docker-compose -f docker-compose.json up

32. Bạn có thể chạy bao nhiêu container trong docker và các yếu tố ảnh hưởng đến giới hạn này là gì?

Không có giới hạn xác định rõ ràng về số lượng container có thể chạy trong docker. Nhưng tất cả phụ thuộc vào những hạn chế – cụ thể hơn là những hạn chế về phần cứng. Kích thước của ứng dụng và tài nguyên CPU có sẵn là 2 yếu tố quan trọng ảnh hưởng đến giới hạn này. Trong trường hợp ứng dụng của bạn không quá lớn và bạn có tài nguyên CPU dồi dào, thì chúng ta có thể chạy một số lượng lớn các container.

33. Vòng đời của container trong Docker?

Các giai đoạn khác nhau của docker container từ khi bắt đầu tạo cho đến khi kết thúc được gọi là vòng đời của docker container.

Các giai đoạn quan trọng nhất là:

  • Created: Đây là trạng thái mà container vừa được tạo mới nhưng chưa bắt đầu.
  • Running: Trong trạng thái này, container sẽ chạy với tất cả các quy trình liên quan của nó.
  • Paused: Trạng thái này xảy ra khi container đang chạy bị tạm dừng.
  • Stopped: Trạng thái này xảy ra khi container đang chạy đã bị dừng.
  • Deleted: Trong trường hợp này, container ở trạng thái chết.

docker container

34. Làm thế nào để sử dụng docker cho nhiều môi trường ứng dụng?

  • Tính năng docker-compose của docker sẽ hỗ trợ bạn tại đây. Trong file docker-compose, chúng ta có thể xác định nhiều dịch vụ, mạng và container cùng với ánh xạ volume một cách rõ ràng và sau đó chúng ta chỉ cần gọi lệnh docker-compose up.
  • Khi có nhiều môi trường tham gia – đó có thể là máy chủ dev, staging, uat hoặc production, chúng ta muốn xác định các quy trình và phụ thuộc dành riêng cho server chủ để chạy ứng dụng. Trong trường hợp này, chúng ta có thể tiếp tục tạo file docker-compose theo môi trường cụ thể có tên là docker-compos. {environment}.yml và sau đó dựa trên môi trường, chúng ta có thể thiết lập và chạy ứng dụng.

35. Làm sao đảm bảo container1 chạy trước container2 trong khi dùng docker compose?

Docker-compose không đợi bất kỳ container nào “sẵn sàng” trước khi đến container kế tiếp. Để thực thi như vậy, ta có thể sử dụng:

  • Bạn có thể sử dụng depend_on đã được thêm vào phiên bản 2 của docker-compose khi được hiển thị trong file docker-compose.yml mẫu bên dưới:
version: "2.4"
services:
 backend:
   build: .
   depends_on:
     - db
 db:
   image: postgres

Bài viết gốc được đăng tải tại blog.thanhnamnguyen.dev

Xem thêm:

Xem thêm việc làm Web Developer mới nhất trên TopDev

TOP 35 câu hỏi phỏng vấn Docker và cách trả lời hay nhất (Phần 2)

câu hỏi phỏng vấn Docker

Bài viết được sự cho phép của tác giả Nguyễn Thành Nam

Để giúp bạn chuẩn bị tốt nhất cho các cuộc phỏng vấn liên quan đến Docker, TopDev đã tổng hợp danh sách TOP 35 câu hỏi phỏng vấn Docker và cách trả lời hay nhất. Bỏ túi ngay để có một buổi phỏng vấn thật thành công bạn nhé.

11. Docker Hub là gì?

  • Là một nền tảng đám mây được cung cấp bởi Docker cho phép lưu trữ công khai image của Docker đồng thời cho phép tìm kiếm và chia sẻ với người khác.
  • Image có thể được đẩy lên Docker Hub bằng câu lệnh docker push.

12. Lệnh để export một docket image như một archive?

Cú pháp đó là:

docker save -o <exported_name>.tar <container-name>

13. Lệnh để import một Docker image đến một Docker host khác?

docker load -i <export_image_name>.tar

14. Có thể xoá container bị tạm dừng khỏi Docker không?

Không thể! Container phải bị dừng trạng thái trước khi ta có thể xoá chúng.

15. Lệnh kiểm tra phiên bản Docker client và server?

Để kiểm tra tất cả không tin phiên bản client và server là:

docker version

Để lấy chỉ phiên bản server, ta có thể chạy:

docker version --format '{{.Server.Version}}'

  20 trường hợp sử dụng lệnh Docker cho developer

  Hiểu cơ chế layer caching khi build docker image để viết Dockerfile tốt hơn

16. Sự khác biệt giữa ảo hoá (virtualization) và containerization?

virtualization containerization
Nó giúp chạy nhiều hệ điều hành trên phần cứng của một server vật lý Nó giúp triển khai nhiều ứng dụng trên cùng hệ điều hành trên một máy ảo hoặc server
Hypervisors cung cấp các máy ảo tổng thể cho hệ điều hành khách Container đảm bảo cung cấp môi trường/không gian người dùng biệt lập để chạy các ứng dụng. Mọi thay đổi được thực hiện trong container không phản ánh trên server hoặc các container khác của cùng server
Các máy ảo này tạo thành một phần trừu tượng của lớp phần cứng hệ thống, điều này có nghĩa là mỗi máy ảo trên host hoạt động giống như một máy vật lý Container tạo thành sự trừu tượng của lớp ứng dụng có nghĩa là mỗi container tạo thành một ứng dụng khác nhau

17. Sự khác biệt giữa lớp COPY và ADD trong Dockerfile?

Cả hai có chức năng giống nhau, nhưng COPY được ưa thích hơn vì mức độ minh bạch cao hơn ADD.

COPY cung cấp các hỗ trợ cơ bản cho sao chép file cục bộ trong khi ADD cung cấp tính năng bổ sung như URL từ xa và hỗ trợ xuất tar.

18. Container có thể tự khởi động lại?

Có, chỉ có thể thực hiện được khi đang sử dụng một số chính sách do docker xác định trong khi sử dụng lệnh run của docker. Sau đây là các chính sách hiện có:

  1. Off: container sẽ không được khởi động lại trong trường hợp nó bị dừng hoặc bị lỗi.
  2. Un-failure: Ở đây, container chỉ khởi động lại khi nó gặp lỗi không liên quan đến người dùng.
  3. Unless-stop: Sử dụng chính sách này, đảm bảo rằng container chỉ có thể khởi động lại khi người dùng thực hiện lệnh để dừng nó.
  4. Always: Bất kể lỗi hay dừng, container luôn được khởi động lại trong loại chính sách này.

Các chính sách này có thể dùng như sau:

docker run -dit — restart [restart-policy-value] [container_name]

19. Sự khác biệt giữa Docker Image và Layer?

Image: được xây dựng từ một loạt các lớp instruction. Một image tương ứng với container và được sử dụng để vận hành nhanh chóng do cơ chế lưu vào bộ nhớ đệm của mỗi bước.

Layer: Mỗi layer tương ứng với một instruction của image của Dockerfile. Nói đơn giản hơn layer còn là image nhưng nó là image của instruction.

Ví dụ:

FROM ubuntu:18.04
COPY . /myapp
RUN make /myapp
CMD python /myapp/app.py

Quan trọng hơn, mỗi layer là một tập khác cảu layer trước đó.

Kết quả xây dựng file docker này là một image. Trong khi instruction hiện tại trong file thêm layer vào image.

20. Mục đích của tham số volume trong lệnh chạy docker là gì?

Cú pháp của lệnh chạy docker sử dụng volumn là: docker run -v host_path:docker_path <container_name>.

Tham số volume được dùng cho đồng bộ hoá một thư mục trong container với bất kỳ thư mục host nào. Ví dụ: docker run -v /data/app:usr/src/app myapp. Lệnh trên gắn thứ mục /data/app trong host vào thư mục usr/src/app. Ta có thể đồng bộ container với file dữ liệu từ host mà không cần khởi động lại.

Điều này đảm bảo rằng ngay cả khi container bị xóa, dữ liệu của container vẫn tồn tại trong vị trí host lưu trữ được ánh xạ theo volume, làm cho nó trở thành cách dễ dàng nhất để lưu trữ dữ liệu container.

Bài viết gốc được đăng tải tại blog.thanhnamnguyen.dev

Xem thêm: 

Tham khảo thêm các vị trí tuyển dụng ngành IT tại Topdev

Ứng dụng của message queue trong xử lý dữ liệu phân tán, tăng tải

Ứng dụng của message queue

Bài viết được sự cho phép của tác giả Tống Xuân Hoài

Vấn đề

Ngày xưa đi học không biết có ai thắc mắc tại sao lại phải học môn cấu trúc dữ liệu và giải thuật không? Môn học cho chúng ta biết một số cấu trúc dữ liệu phổ biến như là danh sách liên kết (linked list) đơn – đôi, mảng, queue, stack… Nhưng có vẻ như nó thật nhàm chán cho những ai đã biết và đang lập trình. Chưa kể hầu hết ngôn ngữ lập trình đều tự triển khai hoặc có thư viện hỗ trợ tất cả cấu trúc này, ấy vậy mà thầy cô vẫn yêu cầu chúng ta tự triển khai lại các cấu trúc này một cách thủ công.

Có lẽ mục đích thật sự đằng sau đó là muốn chúng ta hiểu về tầm quan trọng của cấu trúc dữ liệu. Thật vậy, rất nhiều ý tưởng, giải pháp được phát minh ra dựa trên chúng. Có thể kể đến là Message queue – một cấu trúc góp mặt trong thiết kế hệ thống phần mềm, nhằm tăng khả năng xử lý và giải quyết nhiều vấn đề phức tạp trong hệ thống phân tán.

Vài năm trở lại đây, khái niệm về hệ thống phân tán không còn quá xa lạ. Thay vì xử lý tất ở một nơi duy nhất thì chia nhỏ công việc ra để xử lý. Mỗi nơi xử lý một nhiệm vụ duy nhất, từ đó giúp cho hệ thống phân cấp rõ ràng hơn, năng xuất hơn và chịu lỗi tốt hơn.

Queue là hàng đợi, message queue là một hàng đợi tin nhắn. Một hàng đợi hoạt động theo kiểu vào trước ra trước (First In, First Out). Tưởng tượng như bạn có một cái ống nước đủ rộng để nhét những viên bi vào, thì cho có đổ tất cả các viên bi vào trong phễu ở một đầu, thì đầu kia vẫn chỉ lăn ra từng viên một theo thứ tự trước sau. Không thể nào có hai viên cùng lăn ra một lúc được, đó chính là một hàng đợi.

Trong hệ thống phần mềm, message queue là một cấu trúc quan trọng và được áp dụng rất nhiều bởi hệ thống phân tán. Vì thế, bài viết ngày hôm nay hãy cùng tôi đi qua một vài khái niệm cơ bản về cấu trúc này nhé.

Message queue là gì?

Message queue là một khái niệm trong lĩnh vực phân tán hệ thống và lập trình đa luồng. Nó là một cấu trúc dữ liệu dùng để lưu trữ các thông điệp (message) trong một hệ thống phân tán.

Message queue

Message queue thường được sử dụng để giao tiếp giữa các thành phần của hệ thống thông tin, cho phép chúng truyền thông điệp (message) cho nhau một cách bất đồng bộ. Thay vì gửi trực tiếp thông điệp từ một thành phần đến thành phần khác, các thành phần này gửi thông điệp vào message queue và các thành phần khác có thể lấy thông điệp từ message queue để xử lý.

Message queue

Tại sao lại không gửi thông điệp trực tiếp mà phải thông qua một message queue? Có nhiều lý do, trong đó nổi bất nhất là để quản lý được thông điệp. Hãy tưởng tượng nếu gửi trực tiếp thông điệp đến một điểm đích không khả dụng thì sẽ như thế nào? Thông điệp có thể bị mất và hệ thống cũng chẳng bao giờ xử lý được thông điệp nữa.

  Cấu hình Laravel Queue trên môi trường production

  Messege Queue - Bộ phận không thể thiếu trong các hệ thống lớn và Microservice Architecture

Cách hoạt động của message queue

Về cơ bản, message queue là một hàng đợi tin nhắn. Ngoài ra, để đưa thông điệp được vào hàng đợi và xử lý thông điệp thì cần phải có sự tham gia của nhiều thành phần. Sự kết hợp giữa chúng tạo thành một hệ thống xử lý hàng đợi tin nhắn hoàn chỉnh.

Tùy thuộc vào dịch vụ cung cấp message queue mà chúng có nhiều thành phần khác nhau. Nhưng về cơ bản, phải có ít 3 thành phần tham gia vào quá trình xử lý là Producer, Message queue và Consumer.

  • Producer (nơi gửi thông điệp) gửi thông điệp vào message queue: Producer là thành phần hoặc ứng dụng tạo ra thông điệp và gửi nó vào message queue. Thông điệp có thể là bất cứ loại dữ liệu nào, ví dụ: tin nhắn, tác vụ xử lý, sự kiện, hay yêu cầu.
  • Message queue là nơi lưu trữ thông điệp: Message queue lưu trữ các thông điệp được gửi bởi Producer. Thông điệp có thể được lưu trữ bền vững trong bộ nhớ hoặc trên ổ đĩa tùy thuộc vào cấu hình của message queue.
  • Consumer (nơi nhận thông điệp) lấy thông điệp từ message queue: Consumer là thành phần hoặc ứng dụng muốn nhận và xử lý thông điệp. Consumer yêu cầu lấy thông điệp từ message queue, sau khi nhận được thông điệp, consumer tiến hành xử lý nó theo logic của ứng dụng.

Cách hoạt động của message queue

Quá trình này lặp đi lặp lại mỗi khi Producer gửi thêm thông điệp vào Message queue và Consumer lấy và xử lý các thông điệp. Sự bất đồng bộ giữa Producer và Consumer cho phép hệ thống hoạt động hiệu quả và linh hoạt, đồng thời đảm bảo tính tin cậy và khả năng mở rộng.

Ứng dụng message queue như thế nào?

Message queue có rất nhiều ứng dụng trong các hệ thống phân tán và lập trình đa luồng có thể kể đến như:

  • Hệ thống xử lý dữ liệu theo thời gian thực: Trong các hệ thống xử lý dữ liệu theo thời gian thực, message queue được sử dụng để truyền tải dữ liệu từ các nguồn khác nhau đến các hệ thống xử lý. Các nguồn dữ liệu gửi thông điệp vào message queue và các hệ thống xử lý lấy thông điệp từ queue để xử lý dữ liệu một cách song song và bất đồng bộ.
  • Hệ thống đa luồng và bất đồng bộ: Message queue cho phép các thành phần trong hệ thống hoạt động độc lập và bất đồng bộ. Các thành phần có thể gửi thông điệp vào message queue và tiếp tục công việc của mình mà không cần chờ đợi phản hồi từ các thành phần khác. Điều này giúp tăng hiệu suất và khả năng mở rộng của hệ thống.
  • Hệ thống xử lý sự kiện: Trong các hệ thống xử lý sự kiện, message queue được sử dụng để gửi và nhận các sự kiện từ các nguồn khác nhau.
  • Giao tiếp giữa các dịch vụ: Trong kiến trúc dịch vụ phân tán, message queue được sử dụng để giao tiếp giữa các dịch vụ. Các dịch vụ gửi thông điệp vào message queue để yêu cầu hoặc truyền thông tin cho các dịch vụ khác.
  • Hàng đợi công việc: Message queue cũng được sử dụng trong các hệ thống hàng đợi công việc, nơi các công việc được gửi vào message queue, sau đó chúng được xử lý một cách lần lượt.

Hai cái tên nổi bật cung cấp cấu trúc message queue có thể kể đến RabbitMQ và Apache Kafka. Ngoài ra còn có một vài thư viện hỗ trợ triển khai message queue đơn giản dựa trên các dịch vụ khác như BullMQ, Kue, Agenda.

Một số ví dụ điển hình

Thật khó hình dung những ứng dụng của message queue nếu không có ví dụ cụ thể. Thực tế công việc hàng ngày của tôi ứng dụng cấu trúc này thường xuyên. Có thể kể đến một vài trường hợp phổ biến nhất như sau.

Trong một hệ thống thương mại điện tử, message queue có thể được sử dụng để xử lý đơn hàng. Khi khách hàng đặt hàng, thông tin đơn hàng được gửi vào message queue. Hệ thống xử lý đơn hàng lấy thông điệp từ queue và tiến hành xử lý đơn hàng, bao gồm kiểm tra hàng tồn kho, xác nhận thanh toán và gửi thông báo vận chuyển. Việc sử dụng message queue giúp tách biệt quá trình đặt hàng và xử lý đơn hàng, đồng thời đảm bảo tính tin cậy và khả năng mở rộng của hệ thống.

Trong một hệ thống gửi email hàng loạt, message queue có thể được sử dụng để xử lý và gửi email. Khi người dùng yêu cầu gửi email, thông điệp email được gửi vào message queue. Hệ thống xử lý email lấy thông điệp từ queue và thực hiện quá trình gửi email, bao gồm tạo nội dung, thêm tệp đính kèm và gửi đi. Việc sử dụng message queue giúp xử lý email một cách bất đồng bộ và đảm bảo tính tin cậy trong việc gửi email hàng loạt.

Trong một hệ thống xử lý sự kiện thời gian thực, message queue được sử dụng để truyền tải và xử lý sự kiện. Các sự kiện này liên quan nhiều đến việc tổng hợp, phân tích thông tin của một hệ thống thông tin.

Sử dụng message queue để trao đổi thông tin giữa các dịch vụ trong hệ thống phân tán nhằm tăng khả năng xử lý và chịu tải, đảm bảo không ảnh hưởng đến tốc độ xử lý thông tin luồng chính.

Đây chỉ là một số ví dụ điển hình về việc sử dụng message queue. Thực tế, message queue có thể được áp dụng trong nhiều lĩnh vực và tình huống khác nhau, tùy thuộc vào yêu cầu và mục đích sử dụng của hệ thống.

Bài viết gốc được đăng tải tại 2coffee.dev

Xem thêm:

Tham khảo thêm các vị trí tuyển dụng ngành IT tại Topdev

TOP 35 câu hỏi phỏng vấn Docker và cách trả lời hay nhất (Phần 1)

TOP 35 câu hỏi phỏng vấn Docker và cách trả lời hay nhất

Bài viết được sự cho phép của tác giả Nguyễn Thành Nam

Docker đã trở thành một công cụ không thể thiếu trong việc triển khai và quản lý các ứng dụng container hóa. Với sự phổ biến ngày càng tăng của Docker, việc nắm vững kiến thức và kỹ năng về Docker không chỉ là một lợi thế mà còn là một yêu cầu quan trọng đối với các kỹ sư phần mềm, DevOps và những người làm việc trong lĩnh vực công nghệ thông tin.

Để giúp bạn chuẩn bị tốt nhất cho các cuộc phỏng vấn liên quan đến Docker, TopDev đã tổng hợp danh sách TOP 35 câu hỏi phỏng vấn Docker và cách trả lời hay nhất. Bỏ túi ngay để có một buổi phỏng vấn thật thành công bạn nhé.

I. Giới thiệu Docker

Giới thiệu Docker

Docker là một nền tảng mã nguồn mở rất phổ biến và mạnh mẽ được sử dụng để xây dựng, triển khai và chạy các ứng dụng. Docker cho phép bạn tách ứng dụng/phần mềm khỏi cơ sở hạ tầng bên dưới.

1. Container là gì?

Container là một đơn vị tiêu chuẩn của phần mềm đi kèm với các phần phụ thuộc để các ứng dụng có thể được triển khai nhanh chóng và đáng tin cậy trên các nền tảng tính toán khác nhau.

Docker có thể được hình dung như một con tàu lớn (docker) chở những thùng sản phẩm (container) khổng lồ.

Docker container không yêu cầu cài đặt một hệ điều hành riêng biệt. Docker chỉ dựa vào hoặc sử dụng các tài nguyên của nhân và chức năng của nó để phân bổ chúng cho CPU và bộ nhớ, nó dựa vào chức năng của nhân và sử dụng cách ly tài nguyên cho CPU và bộ nhớ, đồng thời các namespace riêng biệt để tách biệt chế độ xem của ứng dụng đối với OS (hệ điều hành ).

Container là gì?

2. Tại sao học Docker

Phát triển ứng dụng không chỉ đơn thuần là viết code! Chúng liên quan đến rất nhiều việc hậu trường như sử dụng nhiều framework và kiến ​​trúc cho mọi giai đoạn trong vòng đời của nó, điều này làm cho quá trình trở nên phức tạp và đầy thử thách. Sử dụng bản chất của container hóa giúp các nhà phát triển đơn giản hóa và tăng tốc hiệu quả quy trình làm việc của ứng dụng, đồng thời cho phép họ tự do phát triển bằng cách sử dụng lựa chọn công nghệ và môi trường phát triển của riêng họ.

  • Tất cả những khía cạnh này tạo thành phần cốt lõi của DevOps, điều này càng trở nên quan trọng hơn đối với bất kỳ nhà phát triển nào cũng cần biết những điều này để cải thiện năng suất, thúc đẩy sự phát triển nhanh chóng cùng với việc ghi nhớ các yếu tố về khả năng mở rộng ứng dụng và quản lý tài nguyên hiệu quả hơn.
  • Hãy tưởng tượng container như một hộp rất nhẹ được cài đặt sẵn với tất cả các package, phần phụ thuộc, phần mềm theo yêu cầu của ứng dụng của bạn, chỉ cần triển khai production với những thay đổi cấu hình tối thiểu.
  • Rất nhiều tổ chức như PayPal, Spotify, Uber, v.v. sử dụng Docker để đơn giản hóa các hoạt động và đưa cơ sở hạ tầng và bảo mật đến gần hơn để tạo ra các ứng dụng an toàn hơn.
  • Mang tính di động, Container có thể được triển khai trên nhiều nền tảng như máy ảo, nền tảng Kubernetes, v.v. theo yêu cầu của quy mô hoặc nền tảng mong muốn.

II. Câu hỏi phỏng vấn về Docker

1. Giải thích về container trong Docker?

  • Nói một cách đơn giản nhất, container bao gồm các ứng dụng và tất cả các phụ thuộc của chúng.
  • Chúng chia sẻ nhân và tài nguyên hệ thống với các container khác và chạy như các hệ thống biệt lập trong hệ điều hành chủ.
  • Mục đích chính của container là loại bỏ sự phụ thuộc vào cơ sở hạ tầng trong khi triển khai và chạy các ứng dụng. Điều này có nghĩa là bất kỳ ứng dụng được chứa trong container nào cũng có thể chạy trên bất kỳ nền tảng nào bất kể cơ sở hạ tầng đang được sử dụng bên dưới.
  • Về mặt kỹ thuật, chúng chỉ là các phiên bản runtime của docker image.

2. Docker image là gì?

Chúng là các gói thực thi (được đóng gói với code ứng dụng và phần phụ thuộc, gói phần mềm, v.v.) nhằm mục đích tạo container. Docker image có thể được triển khai cho bất kỳ môi trường docker nào và các container có thể được xoay ở đó để chạy ứng dụng.

3. DockerFile là gì?

Nó là một file văn bản có tất cả các lệnh cần được chạy để xây dựng một image nhất định.

DockerFile là gì?

4. Chức năng của hypervisor là gì?

Hypervisor là một phần mềm giúp cho quá trình ảo hóa diễn ra vì nó đôi khi được gọi là Virtual Machine Monitor. Điều này phân chia tài nguyên của hệ thống máy chủ và phân bổ chúng cho từng môi trường khách được cài đặt.

Chức năng của hypervisor

Điều này có nghĩa là nhiều hệ điều hành có thể được cài đặt trên một hệ thống máy chủ duy nhất.

Hypervisor có 2 loại:

  • Native Hypervisor: Loại này còn được gọi là Bare-metal Hypervisor và chạy trực tiếp trên hệ thống máy chủ bên dưới, điều này cũng đảm bảo quyền truy cập trực tiếp vào phần cứng máy chủ, đó là lý do tại sao nó không yêu cầu hệ điều hành cơ bản.
  • Hosted Hypervisor: Loại này sử dụng hệ điều hành máy chủ cơ bản đã được cài đặt hệ điều hành hiện có.

5. Docker compose là gì?

Nó là một file YAML bao gồm tất cả các chi tiết liên quan đến các dịch vụ, mạng và khối lượng khác nhau cần thiết để thiết lập ứng dụng dựa trên Docker. Vì vậy, docker-compose được sử dụng để tạo nhiều container, lưu trữ chúng và thiết lập giao tiếp giữa chúng. Với mục đích giao tiếp giữa các container, các cổng được tiếp xúc bởi từng container.

  20 trường hợp sử dụng lệnh Docker cho developer

  Hiểu cơ chế layer caching khi build docker image để viết Dockerfile tốt hơn

6. Docker namespace là gì?

Namespace về cơ bản là một tính năng của Linux đảm bảo phân vùng tài nguyên hệ điều hành theo cách loại trừ lẫn nhau. Điều này hình thành khái niệm cốt lõi đằng sau quá trình container hóa khi namespace giới thiệu một lớp cách ly giữa các container. Trong docker, namespace đảm bảo rằng các container có thể di động và chúng không ảnh hưởng đến máy chủ bên dưới. Ví dụ về các loại namespace hiện đang được Docker hỗ trợ – PID, Mount, User, Network, IPC.

7. Cách hiển thị trạng thái của tất cả docker container bằng dòng lệnh?

docker ps -a

8. Dữ liệu được lưu trữ trong container sẽ bị mất trong những trường hợp nào?

Dữ liệu của container vẫn ở trong đó cho đế khi bạn xóa container.

Xem thêm việc làm Docker hấp dẫn trên TopDev

9. Docker image registry?

Theo thuật ngữ đơn giản, Docker image registry là một khu vực lưu trữ các docker image. Thay vì chuyển đổi các ứng dụng thành container mỗi lần, một nhà phát triển có thể sử dụng trực tiếp các iamge được lưu trữ trong registry. Docker image registry có thể là công khai hoặc riêng tư và DockerHub là tổ chức đăng ký công khai phổ biến và nổi tiếng nhất hiện có.

10. Các thành phần trong Docker?

Có 3 thành phần Docker là:

  • Docker Client: thành phần này sẽ thực hiện hành động “build” và “run” nhằm mục đích mở ra giao tiếp với docket host.
  • Docker Host: thành phần này gồm daemon chính của docker, các host container và image của chúng. Daemon thiết lập một kết nối đến docker registry.
  • Docker Registry: thành phần này lưu trữ docker image. Nó có thể là công khai hoặc riêng tư. Các registry công khai nổi tiếng là Docker Hub và Docker Cloud.

Các thành phần trong Docker

Bài viết gốc được đăng tải tại blog.thanhnamnguyen.dev

Xem thêm:

Xem thêm việc làm Web Developer mới nhất trên TopDev

Bảo vệ thông tin nhạy cảm trong dự án sử dụng .env

Bảo vệ thông tin nhạy cảm trong dự án sử dụng .env

Bài viết được sự cho phép của tác giả Nguyễn Thành Nam

Trong quá trình phát triển phần mềm và quản lý dự án, việc bảo vệ thông tin bí mật như API key, mật khẩu, và các thông tin quan trọng khác là rất quan trọng. Một cách phổ biến để giải quyết vấn đề này là sử dụng file .env, một cách quản lý biến môi trường được nhiều lập trình viên sử dụng.

Bảo vệ thông tin nhạy cảm trong dự án sử dụng .env

I. File .env là gì

Tệp .env là một tệp cấu hình chứa các biến môi trường cho một ứng dụng hoặc dự án phần mềm. Trong ngữ cảnh này, biến môi trường là các giá trị mà ứng dụng sử dụng để cấu hình chạy, chẳng hạn như API key, mật khẩu cơ sở dữ liệu, và các thông số cấu hình khác…

Tên .env là viết tắt của từ environment (môi trường), và tệp này thường được sử dụng để giữ các thông tin nhạy cảm mà bạn không muốn lưu trữ trực tiếp trong mã nguồn của bạn, đặc biệt là khi chia sẻ mã nguồn trên các hệ thống quản lý phiên bản như Git.

Mỗi dòng trong tệp .env thường chứa một biến môi trường và giá trị của nó, được đặt tên theo định dạng TEN_BIEN=GIATRI.

DATABASE_URL=mysql://user:password@localhost:3306/database
API_KEY=your_api_key_here
DEBUG=true

Các giá trị này sau đó có thể được đọc và sử dụng trong mã nguồn ứng dụng để cấu hình và thực hiện các tác vụ cụ thể. Thông thường, một thư viện như dotenv được sử dụng để tải các biến môi trường từ tệp .env vào quá trình chạy của ứng dụng.

II. Các đặc điểm của file .env

1. Quản lý biến môi trường một cách đơn giản

Một trong những ưu điểm lớn nhất của .env là khả năng đơn giản hóa quản lý biến môi trường. Thay vì trực tiếp nhúng thông tin bí mật vào mã nguồn, chúng ta có thể lưu trữ chúng trong tệp .env và gọi chúng trong mã nguồn khi cần thiết. Điều này giúp lập trình viên dễ dàng thay đổi cấu hình mà không cần sửa đổi mã nguồn.

Các đặc điểm của file .env

2. Thông tin bí mật được an toàn

Thông tin bí mật như API key, mật khẩu và các thông tin nhạy cảm khác thường xuyên cần được bảo vệ khỏi sự truy cập trái phép. .env giúp ngăn chặn việc lộ thông tin này bằng cách giữ chúng trong một tệp không nằm trong lịch sử kiểm soát phiên bản (Git). Điều này đảm bảo rằng những thay đổi thông tin bí mật không được lưu trữ trong các commit của mã nguồn.

3. Quản lý phạm vi dự án hiệu quả

Mỗi dự án có thể có nhiều cấp độ biến môi trường tùy thuộc vào hệ điều hành, người dùng hay phiên làm việc. .env giúp quản lý phạm vi dự án một cách hiệu quả bằng cách giữ thông tin trong phạm vi chỉ của ứng dụng, tránh xung đột với các biến môi trường khác trên hệ thống.

4. Khả năng di chuyển và linh hoạt

Tệp .env có khả năng di chuyển, cho phép bạn đặt nó ở bất kỳ thư mục nào trong dự án. Điều này tăng cường an ninh bằng cách tránh hiển thị thông tin quan trọng khi có sự cố cấu hình máy chủ hoặc mã nguồn. Giống như việc lưu trữ SSH key tại một vị trí ổn định như ~/.ssh

Các đặc điểm của file .env

5. Tích hợp dễ dàng trong quy trình phát triển

Sử dụng .env không chỉ giúp bảo vệ thông tin bí mật mà còn tạo ra một quy trình phát triển mạnh mẽ. Bạn có thể tích hợp .env vào công cụ CI/CD của mình để tự động hóa việc cung cấp các thông tin bí mật phù hợp với môi trường triển khai, tạo ra một quy trình triển khai an toàn và linh hoạt.

6. Tệp bị bỏ qua

Tệp .env có thể được bỏ qua khỏi hệ thống kiểm soát phiên bản, ngăn chặn thông tin bí mật bị commit vào lịch sử của mã nguồn (sử dụng git ignore). Bạn cũng có thể tạo một tệp .sample.env để hướng dẫn người sử dụng về cách thiết lập các biến môi trường mà không cần chia sẻ thông tin bí mật.

Các đặc điểm của file .env

  Bàn về câu lệnh npm run build - tại sao cần phải build?

  6 câu lệnh NPM hữu ích – Web dev mà bỏ qua sẽ vô cùng tiếc

III. Hướng dẫn sử dụng .env

1. Trong node.js

Để minh họa cách sử dụng .env, hãy xem một ví dụ đơn giản với Node.js.

Trong thư mục chính của bạn, chạy cậu lệnh npm init và sau đó npm install dotenv để cài đặt thư viện dotenv.

Tạo một tệp .env chứa các biến môi trường với định dạng TEN_BIEN=GIATRI.

Ở index.js, thêm đoạn mã sau:

require('dotenv').config();
console.log(process.env.TEN_BIEN);

Chạy ứng dụng và giá trị của biến sẽ được xuất ra terminal.

Việc làm JavaScript Hồ Chí Minh dành cho bạn!

2. Trong các dự án sử dụng framework như ReactJS, NextJS, VueJS…

Tiến hành cài đặt như trên, nhớ git ignore file .env trước khi push code, sau đó cấu hình .env ở các hosting hoặc thông qua CI/CD.

Ví dụ: khi bạn làm dự án ở dưới local bạn khai báo các thông tin tại .env

GRAPHCMS_TOKEN=sdadasjdas...
NEXT_PUBLIC_GRAPHCMS_ENDPOINT=dsaddasdasd...

Sau khi toàn tất, bạn kiểm tra trong file .gitignore đã có .env hay chưa. Cuối cùng, khi push code hoàn tất, bạn có thể thêm các biến trong .env lên (ví dụ mình sử dụng Vercel như hình bên dưới).

Bảo vệ thông tin nhạy cảm trong dự án sử dụng .env

IV. Kết luận

Sử dụng tệp .env không chỉ giúp bảo vệ thông tin bí mật của ứng dụng mà còn tăng cường tính di động và linh hoạt của mã nguồn. Điều này làm cho .env trở thành một công cụ quan trọng trong quá trình phát triển và bảo trì dự án. Hãy tích hợp .env vào quy trình phát triển của bạn để đảm bảo an toàn thông tin và sự thuận tiện trong quản lý biến môi trường.

Bài viết gốc được đăng tải tại blog.thanhnamnguyen.dev

Xem thêm:

Xem thêm Việc làm IT hấp dẫn tại TopDev

Đăng Ký Hôm Nay, Phím Xịn Liền Tay

Tháng 6 này, Monthly Reward trở lại với nhiều phần quà hấp dẫn. Khi sử dụng các tính năng như Tạo CV Online hoặc Chuẩn hóa CV trên TopDev, bạn sẽ có cơ hội nhận được các voucher Highlands thú vị. Đặc biệt, cuối chương trình sẽ có một bàn phím Keychron cực chất dành cho người may mắn nhất. Đừng bỏ lỡ, tham gia ngay để trải nghiệm và nhận quà!

Những mẹo nhỏ khi làm việc với Laravel Eloquent

Bỏ túi một vài mẹo nhỏ khi làm việc với Laravel Eloquent

Bài viết được sự cho phép của tác giả Duy Phan

Trong quá trình làm việc với Laravel Eloquent ORM, chắc hẳn các bạn từng thực hiện khá nhiều tác vụ lặp đi lặp lại – mà bạn không hề biết Laravel đã hỗ trợ sẵn. Thông qua vài mẹo và thủ thuật nhỏ trong bài viết này, mình hi vọng sẽ giúp các bạn giảm bớt sự phức tạp khi viết code cũng như bớt nhàm chán khi thực hiện các tác vụ lặp đi lặp lại theo cách thông thường.

laravel

Tăng hoặc giảm giá trị của một thuộc tính

Mình cá là có khá nhiều người đã từng viết những thứ đại loại như thế này:

$page = Page::find($id);

$page->views_count++;
$page->save();

Cách này hoàn toàn đúng nha các bạn, nhưng mình có thể viết lại như sau:

$page = Page::find($id);

$page->increment('views_count');

Đẹp hơn rồi phải không ^^

Các cách viết như sau cũng hoàn toàn hợp lệ:

Page::find($id)->increment('views_count'); //+1

Page::find($id)->increment('views_count', 100); //+100

Product::find($productId)->decrement('stock'); //-1

Khởi tạo nhanh Model và Migration

Thường khi chúng ta cần tạo ra model và migration, chúng ta sẽ thực hiện tuần tự các lệnh sau:

$ php artisan make:migration create_posts_table --create=posts
$ php artisan make:model Post

Chúng ta chỉ cần thực hiện một trong hai câu lệnh đơn giản hơn sau đây:

$ php artisan make:model Post -migration
$ php artisan make:model Post -m

Các phương thức XorY

Eloquent hỗ trợ một số phương thức kết hợp 2 chức năng, đại loại là “Thực hiện X, ngược lại thực hiện Y“.

Khó hiểu quá hả? Vậy chúng ta cùng xem qua một vài ví dụ nhé.

Ví dụ 1: phương thức findOrFail()

Chúng ta có một đoạn code như thế này:

$post = Post::find($id);

if (!$post) {
    abort(404);
}

Thay vì viết phức tạp như vậy, chúng ta có thể viết trực tiếp như sau:

$post = Post::findOrFail($id);

Ví dụ 2: phương thức firstOrCreate()

Phàm nhân sẽ viết như thế này:

$user = User::where('email', $email)->first();

if (!$user) {
    $user = User::create(['email' => $email]);
}

Chúng ta sẽ thử cách khác xịn xò hơn:

$user = User::firstOrCreate(['email' => $email]);

Ví dụ 3: phương thức insertOrIgnore()

Khi chúng ta thực hiện việc insert một danh sách các bản ghi vào cơ sở dữ liệu, chúng ta thường dùng phương thức insert() để giải quyết:

Post::insert([
    ['name' => 'Post 1', 'status' => 'active'],
    ['name' => 'Post 2', 'status' => 'active'],
]);

Khi chúng ta muốn bỏ qua các bản ghi bị lỗi xảy ra trong quá trình insert:

Post::insertOrIgnore([
    ['name' => 'Post 1', 'status' => 'active'],
    ['name' => 'Post 2', 'status' => 'active'],
]);

Phương thức boot()

Chà chà, đây là một nơi kỳ diệu mà Eloquent hỗ trợ chúng ta có thể ghi đè các hành vi mặc định khi thực hiện một số tác vụ nào đó.

Bên dưới là một ví dụ nhỏ về việc thêm một trường uuid vào bảng tại thời điểm tạo mới một User.

class User extends Model
{
    public static function boot()
    {
        parent::boot();

        static::creating(function ($model) {
            $model->uuid = (string)Uuid::generate();
        });
    }
}

Cũng khá dễ hiểu đúng không các bạn ^^

Eloquent cũng cung cấp các phương thức obsever khác hỗ trợ cho quá trình thao tác với model như: updatingdeleting… Bạn có thể tham khảo liên kết sau để biết thêm nhiều thông tin hơn https://laravel.com/docs/7.x/eloquent.

Thiết lập relationship với các điều kiện và thứ tự sắp xếp

Bên dưới là một ví dụ điển hình cho việc thiết lập relationship giữa 2 model User và Post:

class User extends Model
{
    public function posts()
    {
        return $this->hasMany(Post::class);
    }
}

Nhưng nếu như bạn muốn thêm một số điều kiện ràng buộc ở đây, hoặc sắp xếp thứ tự hiển thị của các bài viết thì sao?

Eloquent hỗ trợ thực hiện điều này khá dễ dàng:

public function posts()
{
    return $this->hasMany(Post::class)->where('status', 1)->orderByDesc('published_at');
}

Các thuộc tính của Model

Bạn có thể cấu hình một số tham số của Eloquent dưới dạng thuộc tính của lớp. Dưới đây là một số thuộc tính phổ biến mà đa số lập trình viên đều biết:

class User extends Model
{
    /**
     * Thiết lập tên bảng trong cơ sở dữ liệu của model này
     * @var string
     */
    protected $table = 'users';

    /**
     * Thiết lập các trường có thể được fill khi bạn dùng Mass Assignment
     * @var array
     */
    protected $fillable = [
        'first_name',
        'last_name',
        'uuid',
        'status',
        'gender',
    ];

    /**
     * Ngược lại với $fillable, đây là các trường không thể được fill khi bạn dùng Mass Assignment.
     * Chú ý: Eloquent không cho phép bạn đồng thời định nghĩa cả $fillable và $guarded cho model của mình.
     * @var array
     */
    protected $guarded = [
        'id',
    ];

    /**
     * Định nghĩa các trường được tự động chuyển sang Carbon object - một class xử lí thời gian mà Laravel đang sử dụng
     * @var array
     */
    protected $dates = [
        'published_at',
    ];

    /**
     * Định nghĩa các trường sẽ được thêm vào trực tiếp trong dữ liệu trả về của model thông qua accessors
     * @var array
     */
    protected $appends = [
        'full_name',
    ];

    /**
     * Accessor trả về thông tin từ model khi người dùng gọi tới thuộc tính full_name
     * @return string
     */
    public function getFullNameAttribute()
    {
        return $this->first_name . ' ' . $this->last_name;
    }
}

Nhưng thực ra thì Eloquent hỗ trợ nhiều hơn thế.

/**
* Định nghĩa khóa chính của bảng trong cơ sở dữ liệu
* @var string
*/
protected $primaryKey = 'uuid';

/**
* Đây là các trường lưu lại thông tin thời gian cập nhật dữ liệu của model.
* Bạn có thể cập nhật lại chúng cho phù hợp với cơ sở dữ liệu bạn đang có sẵn.
*/
const CREATED_AT = 'created_at';
const UPDATED_AT = 'updated_at';

/**
* Chỉ định cho model biết có cần thiết lưu thông tin thời gian cập nhật model hay không.
* @var bool
*/
public $timestamps = false;

...

Ở đây mình chỉ nêu một số thuộc tính chúng ta hay sử dụng khi làm việc với model. Bạn có thể tham khảo liên kết sau để biết thêm nhiều thuộc tính khác mà Eloquent hỗ trợ hơn https://github.com/laravel/framework/…/Model.php.

Accessors và Mutators

Trong phần trên mình có nhắc tới Accessor. Vậy thì Accessor là gì?

Trong nhiều trường hợp, chúng ta cần truy cập vào một số thuộc tính của model khi mà chúng không thực sự tồn tại trong cơ sở dữ liệu. Ở ví dụ phía trên, chúng ta cần lấy thông tin full_name của User để hiển thị cho người dùng. Thay vì phải làm một cái gì đó tương tự như thế này:

{{ $user->first_name . ' ' . $user->last_name }}

Thì chúng ta sẽ khai báo phương thức getFullNameAttribute() trong Model như ví dụ phía trên, sau đó ở phía người dùng, chúng ta chỉ cần gọi nó ra như sau:

{{ $user->full_name }}

Để khai báo một accessor, bạn tạo ra một phương thức getFooBarAttribute() trong model của mình, với FooBar đặt theo chuẩn StudlyCase, còn thuộc tính bạn truy vấn ra sẽ dưới dạng snake_case ($user->foo_bar).

Giờ code nhìn sạch sẽ hơn rất nhiều rồi phải không nào ^^

Mutators thì ngược lại với Accessors, chúng được dùng trong quá trình cập nhật thay vì truy xuất dữ liệu như Accessors.

Bạn có thể truy cập liên kết sau để tìm hiểu nhiều hơn về Accessors và Mutatorshttps://laravel.com/docs/7.x/eloquent-mutators#accessors-and-mutators.

Phương thức whereX

Có một cách biến đoạn code sau:

$users = User::where('approved', 1)->get();

trở nên dễ hiểu dễ đọc hơn:

$users = User::whereApproved(1)->get();

Đúng thế, bạn chỉ cần thay đổi tên của bất cứ trường nào trong model (foo_bar) và nối nó với tiền tố “where” dưới dạng StudlyCase (FooBar), Eloquent sẽ tự xử lí và khiến đoạn code chạy “chuẩn không cần chỉnh”.

Mặt khác, hãy chú ý tới một số phương thức đã được định nghĩa sẵn của Eloquent:

User::whereDate('created_at', date('Y-m-d'));

User::whereDay('created_at', date('d'));
User::whereMonth('created_at', date('m'));
User::whereYear('created_at', date('Y'));

Post::whereNull('category_id')->get();
Post::whereNotNull('category_id')->get();

Ah ha, sạch sẽ rõ ràng dễ hiểu hơn rất nhiều rồi.

Thực ra thì có khá nhiều người ghét kiểu viết như thế này (trừ những hàm mặc định của Eloquent), nhưng Eloquent đã hỗ trợ và bạn muốn xài thì cứ xài thôi. Trên thực tế mình lại thích viết rõ ràng các tên trường ra thay vì gọi tên hàm, bởi mình thấy nó làm cho code khó tái sử dụng hơn.

Model có quan hệ belongsTo chứa giá trị mặc định

Hãy tưởng tượng bạn có các bài Post được đăng bởi một Author. Bạn cần xuất tên của Author ra ngoài view.

{{ $post->author->name }}

Nhưng điều gì sẽ xảy ra nếu Author đã bị xóa, hoặc nó chưa được lưu xuống vì một lí do nào đó? Bạn sẽ gặp một lỗi Exception, đại loại là “try to get property of non-object“.

Thực ra bạn có thể tránh điều đó bằng cách sau:

{{ $post->author->name ?? '' }}

Nhưng bạn sẽ phải trả giá bằng cách kiểm tra giá trị như trên ở tất cả những nơi cần chúng. Khá phiền phức đúng không?

Có một cách hay hơn để làm điều này. Chúng ta sẽ thêm đoạn code như sau vào Eloquent model:

public function author()
{
    return $this->belongsTo(Author::class)->withDefault();
}

Đoạn code này sẽ trả về một lớp Author rỗng nếu không có Author nào đi kèm với bài Post. Hơn nữa chúng ta hoàn toàn có thể thiết lập các giá trị mặc định cho Author:

public function author()
{
    return $this->belongsTo(Author::class)->withDefault([
        'name' => 'Guest',
    ]);
}

Thiết lập một vài Global Scope

Một ngày đẹp trời, bạn muốn các Category được sắp xếp theo “name” bất cứ khi nào truy vấn dạng danh sách. Ủa không lẽ giờ ngồi tìm rồi sửa lại hết hay sao ta?

Có một cách để thực hiện điều này tốt hơn, ít “cơ bắp” hơn – chỉ định một Global Scope. Chúng ta cùng quay trở lại phương thức boot() đã đề cập trước đó:

use Illuminate\Database\Eloquent\Builder;

protected static function boot()
{
    parent::boot();

    static::addGlobalScope('orderByName', function (Builder $builder) {
        $builder->orderBy('name', 'asc');
    });
}

Bạn nên tham khảo liên kết sau đây để tìm hiểu rõ hơn về phần Global Scope này https://laravel.com/docs/7.x/eloquent#global-scopes.

Chỉ định các Raw Query

Trong một số trường hợp, khi mà các phương thức xây dựng sẵn của Eloquent không đủ để chúng ta thực hiện truy vấn, chúng ta hoàn toàn có thể thêm vào các raw query.

$orders = Order::whereRaw('price > IF(state = "Texas", ?, 100)', [200])->get();

$products = Product::groupBy('category_id')->havingRaw('COUNT(*) > 1')->get();

$users = User::orderByRaw('(updated_at - created_at) desc')->get();

Replicate – tạo một bản sao của model

Đây là cách ngắn gọn và đơn giản nhất để tạo ra một bản sao cho model:

$post = Post::find($id);

$newPost = $post->replicate();
$newPost->save();

Chunk – xử lí dữ liệu lớn

Khi xử lí hàng ngàn kết quả từ Eloquent, sử dụng chunk sẽ giúp tiết kiệm tối đa bộ nhớ hệ thống. Thực ra phương thức này thuộc về xử lí Collection, chứ không hẳn là ở Model.

Thay vì viết như thế này:

$users = User::all();

foreach ($users => $user) {
    // ...
}

Chúng ta cần chuyển sang dạng này:

User::chunk(50, function ($users) {
    foreach ($users => $user) {
        // ...
    }
});

Tạo thêm các cấu trúc liên quan trong lúc khởi tạo một model

Phần phía trên đã đề cập, và hầu như ai trong chúng ta cũng biết câu lệnh này:

$ php artisan make:model Company

Thực ra chúng ta còn có thêm một số tùy chọn khá hữu ích liên quan tới Model:

$ php artisan make:model Company -m -c -r
  • -m: tạo kèm một migration tương ứng
  • -c: tạo kèm một controller.
  • -r: chỉ định controller được tạo ra là resource.

Kết quả trả về của hàm update()

Có bao giờ bạn tự hỏi những đoạn code tương tự như thế này trả về giá trị gì chưa?

$result = Product::whereNull('category_id')->update(['category_id' => 5]);

Câu lệnh này đã thực hiện việc cập nhật category_id cho toàn bộ các Product thỏa điều kiện, nhưng giá trị của $result ở đây là gì?

Câu trả lời chính là: số lượng các mục bị ảnh hưởng. Điều này có nghĩa là nếu bạn muốn kiểm tra xem có bao nhiêu mục đã được cập nhật, thì đây là chính xác những gì bạn cần, không cần gọi thêm thứ gì khác.

Truy vấn điều kiện nâng cao

Nếu bạn có một câu SQL đại loại như thế này:

... WHERE (gender = 'Male' and age >= 20) OR (gender = 'Female' and age >= 18)

Chuyển đoạn SQL này sang Eloquent như thế nào đây? Có lẽ nhiều người từng làm như thế này:

$query->whereRaw('(gender = ? and age >= ?) OR (gender = ? and age >= ?)', ['Male', 20, 'Female', 18]);

Viết như vầy thì “cơ bắp” quá các bạn, cũng khó bảo trì sau này nữa. Trừ trường hợp bất khả kháng, nếu không thì chúng ta nên cố gắng chuyển câu truy vấn sang Eloquent hết sức có thể.

Chúng ta có thể gom nhóm các điều kiện đi kèm với nhau trong dấu ngoặc bằng một hàm Closure như sau:

$query
    ->where(function ($q) {
        $q->where('gender', 'Male')->where('age', '>=', 20);
    })
    ->orWhere(function ($q) {
        $q->where('gender', 'Female')->where('age', '>=', 18);
    });

Phương thức orWhere với nhiều tham số

Đôi khi chúng ta cần truy vấn dữ liệu với nhiều điều kiện OR. Đây là cách thông thường mà mọi người hay sử dụng:

$query
    ->where('category_id', $categoryId)
    ->orWhere('name', $name)
    ->orWhere('description', $description)
    ->get();

Ổn và không có vấn đề gì cả. Nhưng chúng ta có thể rút gọn nó như sau:

$query
    ->where('category_id', $categoryId)
    ->orWhere(['name' => $name, 'description' => $description])
    ->get();

Trên đây là những kinh nghiệm và mẹo nhỏ mà mình tìm hiểu được khi làm việc với Laravel. Nếu bạn biết một vài mẹo nào đó và muốn chia sẻ, hãy để lại bình luận bên dưới nhé.

Cám ơn các bạn đã theo dõi. Hẹn gặp lại trong các bài viết tiếp theo.

Bài viết gốc được đăng tải tại duypt.dev

Xem thêm:

Tham khảo thêm các vị trí tuyển dụng ngành IT tại Topdev