Sự khác nhau giữa code dễ và code đơn giản

530

Chào các bạn,

Bấy lâu nay, mình và có thể nhiều bạn khác đang có sự nhầm lẫn to lớn giữa hai từ “dễ dàng” và “đơn giản”. Mặc dù nghe qua, chúng có vẻ giống nhau, có vẻ như là từ đồng nghĩa, có vẻ có thể sử dụng thay thế cho nhau được, nhưng thực chất không phải vậy, “dễ dàng” và “đơn giản” là hai từ mang sắc thái ý nghĩa rất khác nhau. Và việc nhầm lẫn giữa “dễ dàng” và “đơn giản” có thể khiến bạn có những suy nghĩ không đúng đắn cả về cuộc sống lẫn … code.

Vì vậy, bài viết này mình sẽ đi phân tích sự khác nhau giữa “dễ dàng” và “đơn giản” để chúng ta cũng hiểu rõ ý nghĩa của mỗi từ mà nó hướng tới.

I. Dễ dàng vs Đơn giản

Giả sử mình có câu “Dậy sớm rất đơn giản”.

– Đúng, dậy sớm rất đơn giản, chỉ cần hẹn báo thức và dậy đúng giờ đó, không lằng nhằng nhiều bước, đứa trẻ 5 tuổi cũng làm được.
– Nhưng nó không dễ dàng, bởi bạn có cưỡng lại được sự buồn ngủ, hay cưỡng lại được cái chăn ấm kia. Và thử nghĩ xem, đã bao nhiêu lần bạn đặt mục tiêu dậy sớm và không làm được :D.

Ví dụ ngắn gọn trên có lẽ đã giúp bạn hiểu được sự khác nhau giữa dễ dàng và đơn giản, nhưng hãy cùng phân tích kỹ hơn nhé:

  • Dễ dàng hướng tới việc mô tả một hành động mà không đòi hỏi nhiều công sức, động lực, kiến thức mà vẫn có thể thực hiện.
  • Đơn giản hướng tới việc mô tả một hành động có mà càng ít bước thực hiện, hoặc các bước thực hiện càng rõ ràng càng tốt (xin phép chỉ giới hạn trong phạm vi hành động đơn giản, mà bỏ qua các sự vật, hiện tượng đơn giản).
  • Trái nghĩa với đơn giảnphức tạp, trái nghĩa với dễ dàngkhó khăn.
  • Ranh giới giữa dễ dàng và đơn giản có thể rất mong manh, và bị phụ thuộc nhiều ở góc độ nhìn nhận của các đối tượng khác nhau (mang tính tương đối). Như ví dụ “dậy sớm rất đơn giản” ở trên, chúng ta đều đồng ý là nó đơn giản, nhưng còn dễ dàng thì sao? Với một người lười chảy thây, có thói quen ngủ nướng, hoặc người làm việc nhiều về đêm, thì dậy sớm thật sự khó khăn, nhưng với một người sống trong quân đội lâu năm (hoặc trong tù :D) thì nó quá dễ dàng. Vì thế, để đánh giá một điều là đơn giản (hay dễ dàng) thì cần phải đặt bản thân ở góc độ của đối tượng sẽ nhìn nhận điều đó.

II. Code dễ dàng VS Code đơn giản

Dễ dàng và đơn giản khác nhau thế nào thì mình đã phân tích ở trên, vậy code dễ dàng và code đơn giản thì khác nhau thế nào:

  • Code dễ dàng: Là những đoạn code mà để tạo ra nó thì không cần nhiều công sức hay kiến thức về code.
  • Code đơn giản: Là những đoạn code sáng sủa, ít bước xử lý, hoặc có các bước xử lý rất rõ ràng.

Trong lập trình, chúng ta thường hướng tới code đơn giản nhiều hơn là code dễ dàng, và một sự thật rằng “Để tạo ra các đoạn code đơn giản thường không dễ dàng”.

Nguyên tắc KISS.

KISS (không phải là HÔN HÍT) là viết tắt của Keep it simple, Stupid, tạm dịch là Giữ nó đơn giản thôi, đồ ngu – là một nguyên tắc giúp chúng ta hướng tới sự đơn giản, và cho rằng một điều gì đó đơn giản thì sẽ dễ dàng sử dụng hơn là phức tạp (lưu ý là dễ dàng sử dụng, chứ không phải dễ dàng tạo ra nhé).

Để hình dung rõ hơn về code dễ dàng và code đơn giản, chúng ta sẽ cùng làm một ví dụ nhỏ sau:

Xét bài toán

Cho mảng $numbers chứa các số nguyên, hãy viết chương trình in ra màn hình các số nguyên tố có trong mảng $numbers.

Mình sẽ giải bài toán trên theo 2 cách, một cách ưu tiên code dễ, cách còn lại ưu tiên code đơn giản, sau đó chúng ta sẽ cùng rút ra nhận xét về 2 cách này.

Cách 1: Ưu tiên code dễ dàng

// Ban đầu đề bài cho cái mảng này
$numbers = [1, 2, 4, 5, 7, 39, 12, 0];

// Tạo cái mảng để chứa các số nguyên tố
$soNguyenTo = [];

// Bắt đầu đi tìm các số nguyên tố có trong mảng
foreach ($numbers as $n) {
    // Số nguyên tố là số tự nhiên lớn hơn 1
    // và chỉ chia hết cho 1 và chính nó
    // hay nói cách khác, số nguyên tố luôn chỉ có 2 ước
    $soUoc = 1;
    for ($i = 2; $i <= $n; $i++) {
        if ($n % $i == 0) {
            $soUoc = $soUoc + 1;
        }
    }
    
    // Kiểm tra số ước
    // Nếu bằng 2, thì thêm vào mảng các số nguyên tố
    if ($soUoc == 2) {
        $soNguyenTo[] = $n;
    }
}

// In các số nguyên tố ra màn hình
foreach ($soNguyenTo as $n) {
    echo $n . PHP_EOL;
}

/*
Output

2
5
7
*/

Cách 2: Ưu tiên code đơn giản

/*
 * Đừng quan tâm tới 3 hàm dưới đây viết như thế nào,
 * hãy chỉ quan tâm tới input và output của nó thôi
 */

// Hàm lọc các số nguyên tố có trong $mang
// input: một biến $mang là mảng chứa các số nguyên
// output: trả về một mảng các số nguyên tố có trong biến $mang 
function locCacSoNguyenTo($mang) {
    $mangSoNguyenTo = [];

    foreach ($mang as $phanTu) {
        if (laSoNguyenTo($phanTu) == true) {
            $mangSoNguyenTo[] = $phanTu;
        }
    }

    return $mangSoNguyenTo;
}

// Hàm kiểm tra một số $n có phải số nguyên tố hay không
// input: một số $n bất kỳ
// output: trả về true/false. true thì $n là số nguyên tố và ngược lại
function laSoNguyenTo($n) {
    $soUoc = 1;
    for ($i = 2; $i <= $n; $i++) {
        if ($n % $i == 0) {
            $soUoc = $soUoc + 1;
        }
    }

    if ($soUoc == 2) {
        return true;
    }

    return false;
}

// Hàm in các phần tử có trong mảng
// input: một mảng bất kỳ
// output: in ra các phần tử trong mảng
function inPhanTuTrongMang($mang) {
    foreach ($mang as $phanTu) {
        echo $phanTu . PHP_EOL;
    }
}

/*
 * Đoạn này thì hãy quan tâm chi tiết
 */

// Cái mảng đề bài cho này
$numbers = [1, 2, 4, 5, 7, 39, 12, 0];

// Lọc các số nguyên tố có trong mảng ra này
$mangSoNguyenTo = locCacSoNguyenTo($numbers);

// In ra màn hình các số nguyên tố này
inPhanTuTrongMang($mangSoNguyenTo);

/*
Output

2
5
7
*/

Nhận xét

  • Về kết quả, cả 2 cách trên đều cho ra kết quả giống nhau, và đều chính xác so với đề bài.
  • Cách 1 không sử dụng nhiều kiến thức về code, chỉ bao gồm: kiến thức về cách sử dụng biến, cách sử dụng lệnh rẽ nhánhvòng lặp.
  • Cách 2 thì sử dụng nhiều kiến thức hơn, bao gồm các kiến thức của cách 1, và kiến thức về cách sử dụng function.

Mới chỉ là một bài toán đơn giản, mà hàm lượng kiến thức giữa 2 cách code đã khác nhau rất nhiều (biết sử dụng function và không biết sử dụng function là rất khác nhau). Nếu trong các dự án thực tế, thì sự khác biệt giữa code dễ và code đơn giản còn chênh lệch nhau nhiều nữa.

>> Đọc thêm: Design pattern là gì mà lập trình viên giỏi phải biết

  • Cách 1 code chạy một lèo từ trên xuống dưới, vẫn chia thành các bước nhưng không rõ ràng, nếu không comment có lẽ bạn sẽ không biết các bước được thực hiện như thế nào.
  • Cách 2 code được chia thành 2 bước rõ ràng, bước 1 tìm các số nguyên tố, bước 2 in ra màn hình, mỗi bước được đóng gói thành một function, nếu không có comment, có lẽ bạn sẽ vẫn hiểu code trong cách 2 được chạy như thế nào.
  • Cách 1 code nhanh hơn, do người code chỉ việc viết một chương trình chạy từ trên xuống dưới.
  • Cách 2 code lâu hơn, do người code phải mất công phân tích để tách thành các function.

Trên là một bài toán đơn giản và cũng phổ biến, nên không tốn nhiều thời gian để phân tích xem cần phải tách thành các function nào, còn với các bài toán mới, các bài toán phức tạp trong thực tế thì việc thiết kế code gồm những function nào là cả một vấn đề lớn, và thường được thực hiện bởi những người có kinh nghiệm.

  • Cách 1 không có khả năng tái sử dụng code đã viết.
  • Cách 2 có thể tái sử dụng code, do code được đóng gói thành các function.
  • Cách 1 code khó hiểu hơn, hãy tưởng tượng 3 tháng sau nhìn lại code trong cách 1 thì mất bao lâu để bạn hiểu nó đang thực hiện cái gì. Code khó hiểu hơn, đồng nghĩa với việc khó bảo trì hơn.
  • Cách 2 code dễ hiểu hơn, chắc chắn là vậy, và cũng dễ bảo trì hơn.

Một thực tế rằng, các lập trình viên sẽ dành thời gian để sửa code nhiều hơn là viết code, mà để sửa code thì bạn phải hiểu code hiện tại đang chạy như thế nào, vì thế việc viết code dễ hiểu quan trọng hơn rất nhiều so với việc viết code sao cho nhanh.

  • Để có các dòng code đơn giản, thì không dễ dàng và ngược lại.
Bộ sưu tập áo thun cho dân IT, đủ các ngôn ngữ lập trình và hệ điều hành.
Click vào ảnh để xem.
QC Được tài trợ

III. Tổng kết

Một bài viết ngắn gọn giúp các bạn phân biệt thế nào là code dễ và code đơn giản, và … à mà thôi. Keep it simple, stupid.