#257 - The Part of PostgreSQL We Hate the Most
Ở kỳ trước, nhóm biên tập có đặt ra câu hỏi “Theo bạn trong 3-4 năm nữa, một buổi phỏng vấn Software Engineer sẽ diễn ra như thế nào? Nó sẽ khác gì với cách chúng ta đang phỏng vấn hiện tại?” và nhận được một câu trả lời từ một bạn đọc. Các bạn có thể tham khảo ở mục Góc bạn đọc bên dưới.
Hãy reply email này (hoặc gửi câu trả lời đến newsletter@grokking.org) để chia sẻ ý kiến của mình nhé! Ban biên tập sẽ chọn ra những câu trả lời hay nhất để trao tặng phần quà là một quyển Dijkstra tập 2 (bản in).
Mong nhận được nhiều góp ý từ các bạn.
P/S: Các bạn nhớ gửi kèm theo thông tin liên hệ để Ban biên tập có thể tiện gửi quà nhé.
📻News
(by lpv)
Go Developer Survey 2023 Q1 Results
Một khảo sát được thực hiện trên gần 6000 lập trình viên về Golang. Kết quả này sẽ giúp Go team có thể tập trung hơn vào những phần quan trọng.
DataDog và sự cố 5 triệu $
Cùng tìm hiểu về sự cố xảy ra gần đây trên DataDog.
📰Những bài viết hay
The Part of PostgreSQL We Hate the Most
(by lpv)
Trong nhiều năm gần đây, PostgreSQL đang trở thành một DBMS được sử dụng khá rộng rãi. Tuy nhiên bên cạnh những ưu điểm của mình, PostgreSQL cũng có những nhược điểm kèm theo đó. Trong bài viết này, tác giả giải thích về MVCC (Multi Version Concurrency Control) trong Database hoạt động như thế nào, và so sánh cụ thể cách cài đặt giữa PostgreSQL và các DBMS khác.
Mục tiêu của MVCC trong DBMS là cho phép nhiều truy vấn đọc và ghi vào cơ sở dữ liệu đồng thời mà không can thiệp lẫn nhau khi có thể. Ý tưởng cơ bản của MVCC là DBMS không bao giờ ghi đè lên các hàng (row) hiện có. Thay vào đó, đối với mỗi hàng (logic), DBMS duy trì nhiều phiên bản (vật lý). Khi ứng dụng thực hiện một truy vấn, DBMS sẽ xác định phiên bản nào cần truy xuất để đáp ứng yêu cầu theo một số thứ tự phiên bản (ví dụ: timestamp). Lợi ích của phương pháp này là nhiều truy vấn có thể đọc các phiên bản cũ hơn của các hàng mà không bị chặn bởi một truy vấn khác đang cập nhật nó. Ngoài ra loại bỏ nhu cầu lock record, ngăn người đọc truy cập dữ liệu trong khi người viết sửa đổi cùng một item.
Một số vấn đề xảy ra đối với PostgreSQL MVCC được tác giải liệt kê và giải thích cụ thể như: Version Copying, Table Bloat, Secondary Index Maintenance, Vacuum Management. Mời các bạn cùng đọc và tìm hiểu chi tiết.
Example of PostgreSQL index maintenance operations with a non-HOT update
How to measure your technical debt
(by steven.do87)
Nợ kỹ thuật (technical debt) được hiểu như sự đánh đổi giữa việc rút ngắn thời gian phát triển và cho ra đời một chức năng mới một sản phẩm phần mềm mới với việc đảm bảo một hệ thống hoạt động ổn định và đáng tin cậy, và đây là một thành phần không thể thiếu trong quy trình phát triển phần mềm.
Ngày nay, các chỉ số technical debt ngày càng được các đơn vị và doanh nghiệp phát triển phần mềm quan tâm và càng phổ biến, chúng được thiết kế nhằm giúp cho các doanh nghiệp có thể hiểu và đánh giá được dữ liệu liên quan đến rủi ro về mặt kỹ thuật đối với các hệ thống phần mềm trước khi các vấn đề nghiêm trọng thực sự xuất hiện.
Technical debt có thể được phân làm 04 loại bao gồm: code debt (quan trọng nhất), quản lý tài liệu (documentation), bảo mật (security), và các công cụ hoặc công nghệ được sử dụng bởi đội ngũ phát triển (Engineering tooling).
Thông qua bài viết, tác giả Alex Omeyer tại stepsize đã gợi ý 08 chỉ số giúp đo lường và đánh giá được các mức độ rủi ro về technical debt như sau:
+ Tỷ lệ New Bugs vs Closed Bugs
+ Debt Index: tỷ lệ issues đã resolved trên tổng số issues
+ Code Quality: chất lượng mã nguồn
+ Cycle Time: thời gian xử lý vấn đề
+ Code Churn: số liệu đếm số lần một line code bị xoá, thay thế hoặc viết lại.
+ Code Coverage: độ bao phủ khi thực thi của mã nguồn.
+ Code Ownership: mức độ hiểu được mã nguồn
+ Technical Debt Ratio (TDR): tỷ lệ nợ kỹ thuật
Để có thể hiểu thêm về các chỉ số đo lường trên, các bạn có thể tham khảo thông tin chi tiết tại bài viết gốc.
Modern Approaches to Complex IT Development: Sorting Out Team Communications
(by steven.do87)
Trong bối cảnh ngành CNTT đang có những thay đổi nhanh chóng, các đội phát triển ngày càng đối mặt với các vấn đề khó khăn trong quá trình phát triển các dự án phần mềm, điển hình như vấn đề về ngân sách, thời gian cũng như giao tiếp trao đổi thông tin thiếu hiệu quả trong khi vẫn phải cố gắng bắt kịp tiến độ và các yêu cầu nghiệp vụ thay đổi liên tục.
Thông qua kinh nghiệm làm việc và tham gia các dự án phần mềm, và quá trình áp dụng các công cụ, công nghệ mới cho đến quá trình chuyển đổi cho doanh nghiệp, tác giả đã nhận định ra 03 vấn đề mà các nhóm phát triển phần mềm ngày nay thường xuyên gặp phải.
Trong số đó vấn đề thường xuyên vấp phải đầu tiên đó là việc giao tiếp và cộng tác thiếu hiệu quả giữa các bộ phận và thành viên trong mỗi bộ phận, và vấn đề này bắt nguồn từ sự thiếu minh bạch hoặc truyền đạt thông tin sai lệch do cơ cấu tổ chức chưa tối ưu.
Yếu tố tiếp theo tác giả xem xét đến đó là sự phức tạp ngày càng tăng của các quy trình phát triển phần mềm cũng như hạ tầng CNTT.
Cuối cùng đó là việc các mục tiêu và yêu cầu dự án không được cập nhật liên tục dẫn đến nhầm lẫn, thiếu sót và phát sinh thêm nhiều vấn đề gây ảnh hưởng đến tiến độ và kết quả của dự án.
Đây là bài viết khởi đầu cho loạt bài của tác giả Alex Lashkov về việc đề xuất một phương pháp tiếp cận mới phù hợp hơn với quy trình phát triển phần mềm phức tạp ngày nay.
Using CockroachDB to Reduce Feature Store Costs by 75%
(by steven.do87)
Trong quá trình xây dựng các nền tảng máy học Machine Learning, các kỹ sư tại DoorDash đã nhận định rằng việc sử dụng kết hợp nhiều cơ sở dữ liệu khác nhau có thể giúp đơn giản hóa quá trình vận hành cũng như đem lại hiệu quả đáng kể.
Với nỗ lực tìm kiếm một phương án hiệu quả hơn nhằm đáp ứng nhu cầu thực thi các tác vụ Machine Learning, các kỹ sư tại DoorDash đã quyết định thử nghiệm sử dụng một cơ sở dữ liệu khác để bổ sung cho Redis hiện tại đang đóng vai trò là lưu trữ các online feature phía backend và họ đã quyết định sử dụng CockroachDB làm kho lưu trữ các feature.
Sau khi thử nghiệm và đánh giá hiệu quả giúp giảm trung bình được 75% mức chi phí trên mỗi đơn vị lưu trữ nếu tổ chức lưu trữ trên các nền tảng Cloud, và vẫn đảm bảo được độ trễ tối thiểu.
Bài viết mô tả quá trình các kỹ sư DoorDash tiến hành thử nghiệm và các bài học đã được rút ra về cách thức vận hành các cluster Redis trên quy mô lớn và khi áp dụng Cockroach để hỗ trợ cho nền tảng serving online của DoorDash.
👨💻Góc lập trình
(by ndaadn and phucnh)
Đề ra tuần này: Remove All Occurrences of a Substring
Cho 2 chuỗi "s" và "part", hãy thực hiện biến đổi chuỗi "s" cho tới khi sự xuất hiện của tất cả các chuỗi con trùng với "part" được loại bỏ.
Phép biến đổi được thực hiện như sau:
Tìm chuỗi con trái nhất trong "s" trùng với "part" và loại bỏ khỏi "s"
Lặp lại bước trên cho tới khi không còn sự xuất hiện của chuỗi con "part" trong "s"
Điều kiện của đầu vào:
1 <= s.length <= 1000
1 <= part.length <= 1000
"s" và "part" chỉ chứa 26 ký tự chữ thường trong tiếng Anh
Ví dụ:
Input: s = "daabcbaabcbc", part = "abc"
Output: "dab"
Giải thích:
s = "daabcbaabcbc", loại bỏ "abc" từ vị trí thứ 2, ta thu được s = "dabaabcbc".
s = "dabaabcbc", loại bỏ "abc" từ vị trí thứ 4, ta thu được s = "dababc".
s = "dababc", loại bỏ "abc" từ vị trí thứ 3, ta thu được s = "dab".
Lời giải tuần trước: Jump Game
Hướng tiếp cận 1: giải thuật quay lui
Bắt đầu từ vị trí xuất phát tại ô thứ 0, ta thực hiện như sau:
lần lượt nhảy đến những ô cho phép
tại mỗi ô đích ta lặp lại bước 1
Nếu ở một lần nhảy bất kỳ, ta tới được vị trí cuối cùng n - 1, với n là độ dài của mảng đầu vào, ta trả lại kết quả là true.
Giải thuật quay lui sẽ có độ phức tạp thời gian là O(2^n).
Hướng tiếp cận 2: quy hoạch động
Nếu ta biết tại vị trí A ta có thể nhảy tới ô cuối cùng, và tại vị trí B ta có thể nhảy tới vị trí A, ta có kết luận từ vị trí B ta có thể nhảy tới ô cuối cùng.
Dựa trên nhận xét này, ta chỉ cần duyệt mảng đầu vào và đánh dấu những ô có thể nhảy được tới vị trí cuối cùng bằng giải thuật như sau:
class Solution {
public boolean canJump(int[] nums) {
int n = nums.length;
boolean[] memo = new boolean[n];
// from n - 1 index, always can jump to n - 1
memo[n - 1] = true;
for (int i = n - 2; i >= 0; i--) {
for (int s = 1; s <= nums[i]; s++) {
if (i + s >= n - 1 || memo[i + s]) {
// can jump to n - 1 from index i
memo[i] = true;
break;
}
}
}
return memo[0];
}
}
Độ phức tạp thời gian của giải thuật là O(n^2)
Hướng tiếp cận 3: tối ưu giải thuật quy hoạch động
Tương tự như giải thuật ở hướng tiếp cận quy hoạch động, nhưng thay vì sử dụng mảng memo để đánh dấu những vị trí có thể nhảy tới ô cuối cùng, ta thực ra chỉ cần biết vị trí bên trái nhất mà ta có thể nhảy tới vị trí cuối cùng, ta gọi đây là "leftmostReachToEndIndex".
Nếu ở vị trí hiện tại, ta có thể nhảy tới "leftmostReachToEndIndex", ta cũng có thể nhảy tới vị trí cuối cùng.
Giải thuật được thực hiện như sau:
class Solution {
public boolean canJump(int[] nums) {
// from n - 1 index, always can jump to n - 1
int leftmostReachToEndIndex = nums.length - 1;
for (int i = nums.length - 1; i >= 0; i--) {
// if from i, we can jump to leftmostReachToEndIndex, we can reach to end from i
// thus, update leftmostReachToEndIndex = i
if (i + nums[i] >= leftmostReachToEndIndex) {
leftmostReachToEndIndex = i;
}
}
return leftmostReachToEndIndex == 0;
}
}
Độ phức tạp thời gian của giải thuật là O(n), độ phức tạp về không gian là O(1).
💭Góc bạn đọc
Bạn đọc T.L chia sẻ câu trả lời cho câu hỏi “Theo bạn trong 3-4 năm nữa, một buổi phỏng vấn Software Engineer sẽ diễn ra như thế nào? Nó sẽ khác gì với cách chúng ta đang phỏng vấn hiện tại?”
Theo mình thấy nhiều công ty hay có quy trình phỏng vấn như sau:
Screening test
Bài assignment take home
Phỏng vấn trực tiếp thì hay hỏi về thuật toán, kiến thức về các loại ngôn ngữ lập trình, …
Theo mình, với sự phát triển của các công cụ AI, Copilot như hiện tại thì các bài screening test dạng trắc nghiệm có khả năng sẽ bỏ. Hồi xưa mấy bài screening test tốt vì có thể hỏi một số câu mang tính nhận định, hoặc có giới hạn thời gian thì còn được, giờ thì câu hỏi nhận định cũng bị bot trả lời rồi nên cũng không còn hiệu quả nữa.
Phỏng vấn trực tiếp thì chắc sẽ là hình thức tốt nhất vì lúc đó ứng viên sẽ phản ứng dựa trên kiến thức thật của mình nên việc dựa vào bot nhiều cũng không hiệu quả. Tuy nhiên, mình thì thấy phỏng vấn tương lai chắc sẽ thiên về tình huống và xử lý vấn đề nhiều hơn, vì các thuật toán bây giờ ít quan trọng. Chỉ cần mô tả yêu cầu kèm theo input/output đúng là có khi các ứng dụng Copilot đã sinh ra code kèm test case cho mình luôn rồi.
Ngoài ra, bạn đọc Thịnh có gửi đến thắc mắc, mong các bạn có thể chia sẻ góp ý cho bạn ấy. Như thường lệ, các câu trả lời hay sẽ nhận được một phần quà là một quyển Dijkstra tập 2 bản in.
Công việc của Software Engineer liệu có phải chỉ có code không ạ? Em đang làm Software Engineer ở một công ty công nghệ cũng lớn, nhưng công việc hàng ngày của em thì lại xoay quanh cấu hình Kafka Connect, cấu hình github repo, nâng cấp các phiên bản phần mềm các team khác đang dùng, … và rất ít code. Nên em không biết là như vậy thì có gọi là software engineer không, và em có đang đi đúng hướng không?
Quotes
“We can only see a short distance ahead, but we can see plenty there that needs to be done.”
Alan Turing