Home Blog Page 144

Xây dựng crawler siêu đơn giản với Java

Xây dựng crawler siêu đơn giản với Java

Bài viết được sự cho phép của BBT Tạp chí Lập trình

Giới thiệu

Crawler là một công cụ giúp thu thập dữ liệu, thông tin từ các trang web khác nhau. Một trong những ví dụ về crawler mà chúng ta gặp hằng ngày là Google. Google là một hệ thống có nhiều máy chủ có thể crawling rất nhiều trang web trên Internet, từ đó chúng ta có thể tìm kiếm nội dung những trang web mà chúng ta cần dựa vào từ khoá cụ thể. Hoặc là những trang web so sánh giá cả từ nhiều nguồn khác nhau (websosanh.vn), trang tin báo tổng hợp (baomoi.com) và nhiều ví dụ khác mà mình không thể liệt kê hết ở đây.

Chúng ta có thể tự viết một crawler đơn giản nhằm thu gom một số dữ liệu cơ bản nào đó. Khi hướng dẫn học viên học module 2 (Advance Programming with Java) tại CodeGym, mình thường giao bài tập xây dựng công cụ crawler này. Ví dụ thu thập giá bất động sản trên các trang rao vặt hoặc giá sản phẩm trên các trang thương mại điện tử. Qua bài viết này, mình sẽ hướng dẫn lại các bạn làm bài tập này với ngôn ngữ lập trình Java.

Tuyển dụng Java lương cao mới nhất

Một số yêu cầu cơ bản để thực hiện bài tập này:

  • Nắm vững cú pháp ngôn ngữ lập trình Java
  • Sử dụng được ngôn ngữ đánh dấu HTML
  • Sử dụng được biểu thức chính quy (regular expression) — còn được gọi là regex
  • Một ít hiểu biết về HTTP (Giao thức được sử dụng để truy cập các trang web qua Internet)
  • Hiểu cơ bản phương pháp lập trình hướng đối tượng
  • Hiểu cơ bản về design pattern

Ghi chú: Trên thực tế, có nhiều thư viện hỗ trợ chúng ta làm crawler hiệu quả hơn cách làm trong bài này. Với mục đích học là chính, mình sẽ không sử dụng các thư viện đấy mà sẽ tự xây dựng lấy, các bạn nhé!

Thiết kế chương trình

Chúng ta sẽ xây dựng một công cụ có thể thu thập được tin tức bất động sản đang rao (bao gồm bán và cho thuê) tại các website sau:

  • https://batdongsan.com.vn/
  • https://batdongsan24h.com.vn/
  • https://nhadat24h.net/
  • https://diendanbatdongsan.vn/

Mô tả dữ liệu

Khai báo class có tên là ClassifiedAd để mô tả thông tin thu thập được từ các trang web. Bao gồm: tiêu đề, loại tin rao, diện tích, giá, mô tả chi tiết, hình ảnh (link).

Sau khi khảo sát nội dung các trang web, chúng ta thấy rằng:

  • Các tin có thể hiển thị giá tổng (tính trên toàn bộ diện tích) hoặc giá theo mét vuông. Vì vậy cần khai báo những class sau để mô tả loại giá được hiển thị: enum TypePriceclass Price.
  • Đơn vị tiền có thể là “triệu đồng” hoặc “tỷ đồng”. Vì vậy cần thuộc tính unit tương ứng trong class Price. Giá trị được liệt kê trong enum Unit để xác định đơn vị tiền tệ.
  • Các tin rao được phân loại thành: bán căn hộ, bán nhà đất, bán biệt thự, cho thuê,… enum TypeAd được khai báo cho mục đích này.
enum TypePrice {
    PRICE_PER_M2,   // loại giá dựa trên m2
    TOTAL_PRICE     // giá toàn bộ
}
enum Unit {
    MILLION_VND,
    BILLION_VND,
}
class Price {
    private Float price;
    private TypePrice typePrice;
		private Unit unit;
}
enum TypeAd {
		...,
    SELL,
    RENTAL,
    OTHERS
}
class ClassifiedAd {
    private String title;       // tiêu đề
    private TypeAd typeAd;      // loại tin
    private Price price;        // giá
    private Float acreage;      // diện tích
    private String description; // mô tả
}
  10 Java Web Framework tốt nhất
  10 lý do cho thấy tại sao bạn nên theo học ngôn ngữ lập trình Java

Thiết kế tổng quan

Qua khảo sát các trang web mà cần thu thập tin, chúng ta có thể xác định thứ tự các bước để thu thập tin như sau:

  1. Truy cập trang chủ, liệt kê danh sách những danh mục tin (ví dụ: chung cư, nhà đất, biệt thự,…)
  2. Truy cập các danh mục tin để liệt kê các tin đang rao
  3. Truy cập trang chi tiết của từng tin để lấy các thông tin chi tiết

Chúng ta sẽ áp dụng pattern Template Method để chuyển các bước trên thành một dãy các bước xử lý chung cho mỗi trang web.

public abstract class Crawler {
// bước 1
    abstract Iterable<Subpage> inspectHomepage();
		
// bước 2
    abstract Iterable<DetailPage> inspectSubpage(Subpage subpage);
		
// bước 3
    abstract ClassifiedAd inspectDetailPage(DetailPage detailPage);
// Đây là thao tác chung cho tất cả các trang web mà chúng ta muốn thu thập tin
    Iterable<ClassifiedAd> inspect() {
        List<ClassifiedAd> classifiedAds = new ArrayList<>();
        Iterable<Subpage> subpages = inspectHomepage();
        for (Subpage subpage: subpages) {
            Iterable<DetailPage> detailPages = inspectSubpage(subpage);
            for (DetailPage detailPage: detailPages) {
                ClassifiedAd classifiedAd = inspectDetailPage(detailPage);
                classifiedAds.add(classifiedAd);
            }
        }
        return classifiedAds;
    }
}

Với mỗi trang web cụ thể, chúng ta có một cách thu thập khác nhau (vì giao diện mỗi trang khác nhau). Trong tương lai, chúng ta có thể bổ sung những trang web khác hoặc thay đổi cách thức thu thập. Vì thế chúng ta sẽ xây dựng các class phục vụ việc crawle cho từng trang web cụ thể theo thiết kế như sau:

Sơ đồ lớp (class diagram) chương trình Crawler

Ở thiết kế trên, chúng ta áp dụng kiến thức về abstract class trong lập trình hướng đối tượng nhằm đảm bảo có thể dễ dàng mở rộng các trang web muốn thu thập. Khi cần bổ sung trang mới, chúng ta có thể implement thêm Crawler mà không phải sửa đổi ở khung thiết kế và luồng thực thi của chương trình. Cuối cùng là class MySimpleCrawler chứa đoạn mã khởi động chương trình.

Bây giờ, chúng ta viết mã kiểm tra xem ý tưởng thiết kế trên có thể thực hiện được chưa nhé! Tính năng ban đầu sẽ là khởi động chương trình và lấy những tin rao ở các trang batdongsan.com.vn.

Ghi chú: Ở công cụ siêu đơn giản này, chúng ta chưa tính đến việc làm thế nào để tối ưu thời gian chạy, lấy nhiều tin ở các trang tiếp theo, lên lịch chạy để luôn cập nhật được tin mới nhất, hoặc thậm chí là cấu hình thời gian ngắt quãng giữa các lần thu thập (để tránh trường hợp một số trang không cho phép tạo request liên tục trong khoảng thời gian nhất định nào đó).

Start coding!

1. Xác định các nội dung cần thu thập

Để lấy được nội dung trang web, chúng ta có thể sử dụng một tính năng tạo HTTP request đơn giản mà Java cung cấp là class URL.

Để tạo một request đến trang web cần lấy nội dung, chúng ta sử dụng hàm dưới đây:

private static String getContentFrom(String link) throws IOException {
        // Gởi HTTP request và nhận về kết quả là chuỗi các thẻ HTML
        URL url = new URL(link);
        Scanner scanner = new Scanner(new InputStreamReader(url.openStream()));
        scanner.useDelimiter("\\\\Z");
        String content = scanner.next();
        scanner.close();
        // xoá các ký tự ngắt dòng (xuống dòng)
        content = content.replaceAll("\\\\R", "");
        return content;
    }
</pre

Khi request thành công, các trang web thường trả về các thẻ HTML. Nếu nơi nhận là trình duyệt thì các thẻ HTML này sẽ được dựng hình (render) thành giao diện của trang web. Còn công cụ crawler của chúng ta chỉ xem đấy là các chuỗi ký tự. Việc chúng ta cần làm là tìm những vị trí chứa thông tin cần thiết bên trong chuỗi ấy. Biểu thức chính quy (regex) có thể được áp dụng trong trường hợp này.

Như vậy, chúng ta cần làm hai bước sau để lấy được thông tin trong trang web:

  • Bước 1: Xác định vị trí thông tin cần lấy trong chuỗi HTML để tìm được quy tắc đánh dấu
  • Bước 2: Dựa vào quy tắc đánh dấu trên, chúng ta xác định biểu thức chính quy phù hợp để lọc được chuỗi thông tin cần thiết

Để đơn giản hoá Bước 1 — Tìm vị trí các thông tin cần thiết trong chuỗi HTML trả về, chúng ta có thể sử dụng chức năng Inspect (trong bộ Developer Tools) của trình duyệt Google Chrome hoặc Firefox để tra đến vị trí mã nguồn thông qua giao diện trực quan.

Dưới đây là phần minh hoạ các bước trên cho việc liệt kê danh sách những danh mục tin ở trang chủ của trang web batdongsan.com.vn (Như đã trình bày Bước 1 trong mục Thiết kế tổng quan).

1.1. Hướng dẫn bước 1

  • Truy cập trang web batdongsan.com.vn trên trình duyệt
  • Mở chức năng Inspect với phím tắt Option + CMD + I (hệ điều hành MacOS) hoặc Ctrl + Shift + P (hệ điều hành Windows)
  • Di chuyển chuột đến mục Nhà đất bán > Bán căn hộ chung cư trên thanh định hướng (menu) > Bấm chuột phải > Chọn Inspect.

Rê chuột đến mục Nhà đất bán > Bán căn hộ chung cư trên thanh định hướng (menu), click chuột phải, chọn Inspect.

  • Qua nội dung hiển thị trên tab Element, chúng ta có thể thấy mã HTML của những thẻ đánh dấu mục Bán căn hộ chung cư như bên dưới:

Qua nội dung hiển thị trên tab Element, chúng ta có thể thấy mã HTML của những thẻ đánh dấu mục Bán căn hộ chung cư như trên.

Như vậy, chúng ta xác định được mã đánh dấu các đường link của các danh mục tin trên trang web này là thẻ <a> nằm trong thẻ <li> có class là lv1.

1.2. Hướng dẫn bước 2

Qua bước 1, chúng ta xác định được rằng, để lấy được đường link của danh mục con Bán căn hộ chung cư thì phải lấy thuộc tính href của thẻ <a> nằm trong <li class="lv1">.

Vậy regex có thể dùng ở đây là:

 "<li class='lv1'><a href='(.*?)' class='haslink '>"

Giá trị của thông tin mà chúng ta muốn tìm là đường link nằm giữa <li class='lv1'><a href=' và ' class='haslink '> được đại diện bằng các kí tự (.*?).

Bạn có thể kiểm tra kết quả tìm kiếm dựa trên regex trên bằng một chương trình demo nhỏ với những dòng mã sau:

public class DemoUsingURL {
    private static String getContentFrom(String link) throws IOException {
        ...
    }
    public static void main(String[] args) throws IOException {
        String content = getContentFrom("<https://batdongsan.com.vn>");
        // Regex
        Pattern p = Pattern.compile("<li class='lv1'><a href='(.*?)' class='haslink '>");
        Matcher m = p.matcher(content);
        while (m.find()) {
            System.out.println(m.group(1));
        }
    }
}

Kết quả của đoạn code trên như sau:

/ban-can-ho-chung-cu
/ban-nha-rieng
/ban-nha-biet-thu-lien-ke
/ban-nha-mat-pho
/ban-dat-nen-du-an
...
...
/phong-thuy-van-phong
/tin-tuc-phong-thuy-theo-tuoi
/nha-moi-gioi
/doanh-nghiep

Đây là những đường link con, có thể kết hợp với chuỗi https://batdongsan.com.vn để tạo ra đường link dẫn tới nội dung các danh mục tin được rao.

Ở kết quả trên, chúng ta thấy có một số đường link không phù hợp. Vì đó là những đường link mà chúng ta không muốn thu thập nội dung. Ví dụ: /phong-thuy-van-phong/tin-tuc-phong-thuy-theo-tuoi/nha-moi-gioi,… Chúng ta sẽ tìm cách loại bỏ những kết quả không mong đợi này.

Xem xét lại mã HTML của trang web, chúng ta sẽ phát hiện ra các thẻ <li class='lv1'> chứa các thông tin cần thiết này nằm trong 2 nội dung sau:

Nhà đất bán

<li class='lv0'><a href="/nha-dat-ban" class="haslink ">Nhà đất bán</a>
...nội dung các danh mục con của mục Nhà đất bán ở đây
</li>

Nhà đất cho thuê

<li class='lv0'><a href="/nha-dat-cho-thue" class="haslink ">Nhà đất cho thuê</a>
...nội dung các danh mục con của mục Nhà đất cho thuê ở đây
</li>

Đoạn code trên cần sửa lại như dưới đây để loại ra những link không cần thiết:

public class DemoUsingURL {
    private static String getContentFrom(String link) throws IOException {
        ...
    }
    private static List<String> getLinksFromMenu(String content, String menuPattern) {
        // Regex
        List<String> links = new ArrayList<>();
        Pattern p = Pattern.compile(menuPattern);
        Matcher m = p.matcher(content);
        while (m.find()) {
            Pattern p2 = Pattern.compile("<li class='lv1'><a href='(.*?)' class='haslink '>");
            Matcher m2 = p2.matcher(m.group(1));
            while (m2.find()) links.add(m2.group(1));
        }
        return links;
    }
    public static void main(String[] args) throws IOException {
        String content = getContentFrom("<https://batdongsan.com.vn>");
        String sellMenuPattern = "<li class='lv0'><a href='/nha-dat-ban' class='haslink '>Nhà đất bán</a><ul>(.*?)</ul>";
        List<String> sellLinks = getLinksFromMenu(content, sellMenuPattern);
        String rentalMenuPattern = "<li class='lv0'><a href='/nha-dat-cho-thue' class='haslink '>Nhà đất cho thuê</a><ul>(.*?)</ul>";
        List<String> rentalLinks = getLinksFromMenu(content, rentalMenuPattern);
        System.out.println(sellLinks);
        System.out.println(rentalLinks);
    }
}

Ở đoạn code trên, mình tách phần lấy nội dung từ đường dẫn trang web thành hàm getContentFrom, và một hàm tách link từ nội dung có tên là getLinksFromMenu. Hàm main sử dụng hai hàm được khai báo ở trên để lấy các đường link nằm trong mục Nhà đất bán và Nhà đất cho thuê.

1.3. Thực hành

Bây giờ, các bạn có thể tự thực hành với hướng dẫn hai bước trên để xác định những thông tin còn lại.

Nếu cần có kết quả ngay thì bạn có thể tham khảo mã nguồn mình cung cấp ở cuối bài viết này! 🙂

1.4. Tổng hợp các regex tìm được

Dưới đây các regex đã tìm được với trang batdongsan.com.vn để các bạn tham khảo:

  1. Link các danh mục tin
  2. Link đến nội dung chi tiết
  3. Thông tin cụ thể (như tiêu đề, giá, diện tích,…) trong tin chi tiết

1.4.1. Link các danh mục tin

Tìm các link bên trong mục “Nhà đất bán” và “Nhà đất cho thuê”:

Pattern p1 = Pattern.compile("<li class='lv0'><a href='/nha-dat-ban' class='haslink '>Nhà đất bán</a><ul>(.*?)</ul>");
Pattern p2 = Pattern.compile("<li class='lv0'><a href='/nha-dat-cho-thue' class='haslink '>Nhà đất cho thuê</a><ul>(.*?)</ul>");

Sau đó, tìm các link danh mục thuộc “Nhà đất bán” và “Nhà đất cho thuê” để loại các link không cần thiết:

Pattern pLink = Pattern.compile("<li class='lv1'><a href='(.*?)' class='haslink '>");

1.4.2. Link đến nội dung chi tiết

 Pattern p = Pattern.compile("<div class='p-title'><h3><a href='(.*?)' title");

1.4.3. Thông tin cụ thể trong tin chi tiết

<span id="48e5" class="ir gx ap ce in b ei is it r iu" data-selectable-paragraph="">String title = "<h1 itemprop=\\"name\\">(.*?)</h1>";
String price = "<span class=\\"gia-title mar-right-15\\"><b>Giá:</b><strong>(.*?)</strong>";</span><span id="e97c" class="ir gx ap ce in b ei iv iw ix iy iz it r iu" data-selectable-paragraph="">Pattern p = Pattern.compile(title + ".*" + price);</span>

2. Viết mã crawler cho từng trang web cụ thể

Xác định được các regex pattern để lấy những thông tin cần thiết ở trên là chúng ta đã đi được 50% chặng đường. Việc còn lại là kết hợp các regex trên để viết mã crawler cụ thể cho từng trang web theo thiết kế được trình bày trong mục Thiết kế tổng quan.

Các class dành cho trang cụ thể sẽ implement những phương thức abstract đã định nghĩa trong Crawler:

    // bước 1
    abstract Iterable<Subpage> inspectHomepage();
		
    // bước 2
    abstract Iterable<DetailPage> inspectSubpage(Subpage subpage);
		
    // bước 3
    abstract ClassifiedAd inspectDetailPage(DetailPage detailPage);

inspectHomepage() sẽ sử dụng các regex như minh hoạ trong mục Hướng dẫn bước 1.

inspectSubpage trả về danh sách link các trang chi tiết.

inspectDetailPage trả về thông tin cụ thể từ trang chi tiết.

Cải tiến

Như đã trình bày ở trên, đây là một công cụ “siêu đơn giản”. Vì thế sẽ thiếu nhiều tính năng để crawler thực sự hữu ích trên thực tế như tối ưu thời gian chạy, lên lịch chạy để luôn cập nhật được tin mới nhất, lưu vào kho dữ liệu phù hợp phục vụ tra cứu hoặc tính toán/so sánh…

Mình sẽ đưa ra một số gợi ý để các bạn có thể tiếp tục tìm hiểu và cải tiến công cụ này nhé!

  1. Sử dụng Thread để tối ưu thời gian chạy, giảm thời gian đợi giữa các lần request nội dung từng trang web. Vì mỗi trang được xử lý độc lập, việc đợi kết quả của request này sẽ không ảnh hưởng đến kết quả của các request còn lại.
  2. Sử dụng Crob Job để lên lịch chạy hằng ngày hoặc một khung thời gian cố định (ví dụ: 10 phút 1 lần). Hiện tại, các thao tác phải được kích hoạt thủ công. Việc này sẽ không giúp hệ thống có được dữ liệu mới nhất.
  3. Sử dụng một hệ CSDL cụ thể để gom dữ liệu thu thập được. Hệ CSDL sẽ giúp chúng ta có thể xử lý và đưa ra một số thông tin hữu ích. Ví dụ: so sánh giá thị trường với từng khu vực cụ thể, hoặc tìm giá tốt nhất được rao trên các trang theo nhu cầu của người dùng.

Author: Đặng Huy Hòa

Bài viết gốc được đăng tải tại Tạp chí lập trình

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

Xem thêm các việc làm Developer hấp dẫn tại TopDev

CSS Specificity là gì vậy?

CSS Specificity là gì vậy?

Bài viết được sự cho phép của tác giả Phúc Lương

Mở bài

Chào các bạn, hôm nay mình sẽ tiếp tục series về CSS cơ bản. Bài viết lần này như tiêu đề đã ghi rõ, mình sẽ giới thiệu và phân tích về Specificity trong CSS. Đây là phần kiến thức quan trọng bậc nhất (không nhất thì nhì :D) nhưng lại không quá phức tạp, mình sẽ cố gắng trình bày những thứ đơn giản mà chúng ta hay sử dụng hàng ngày thôi. Nếu các bạn thấy có thiếu sót hay phản hồi gì thì vui lòng cho mình biết ở comment bên dưới nhé.

  5 điều phiền toái nhất của CSS
  11 công cụ hữu ích để kiểm tra và tối ưu hóa các file CSS

Đặt vấn đề

Trong một buổi phỏng vấn khi còn là mid-level developer, mình từng được đặt một câu hỏi cơ bản mang tính lý thuyết cao nhưng mình không trả lời được, mình xin viết lại ra đây (không chính xác hoàn toàn nhưng bản chất câu hỏi không đổi)

<html>
  <head>
    <style>
      body h1 { color: green; }
      html h1 { color: purple; }
    </style>
  </head>

  <body>
    <h1>text</h1>
  </body>
</html>

Theo bạn thì thẻ h1 sẽ có màu green hay purple?

Câu trả lời là màu purple, các bạn có thể tự mình chứng thực kết quả. Phần giải thích cho bài toán này mình để ở cuối bài viết.

Mình đã không trả lời được câu hỏi này, nhưng thời điểm đó mình cho rằng người phỏng vấn chỉ đang đưa ra câu hỏi mang tính đánh đố thôi, chứ thực tế ai lại viết CSS như vậy. Và sau này mình mới nhận ra, đó không phải là một câu hỏi mang tính đánh đố, mà nó là một phần trong một mảng kiến thức vô cùng quan trọng của CSS, đó là CSS Specificity mà bất kì frontend developer nào cũng cần phải hiểu và nắm vững. Nếu bạn không hiểu hoặc không biết về nó, thì bạn hãy tự vấn mình rằng có phải bạn đang viết CSS theo cảm tính, hoặc theo thói quen hàng ngày hay không.

Ok vậy hãy cùng mình tìm hiểu xem CSS Specificity là gì nhé.

CSS Specificity là gì?

Hãy lấy một ví dụ đơn giản sau để mô tả cho định nghĩa bên dưới:

<div class="parent">
  <span class="child" id="sample">Sample text</span>
</div>
/* thẻ span sẽ có màu gì đây? */
.parent .child {
  color: red;
}

.child {
  color: green;
}

#sample {
  color: blue;
}

Ôi trời, một thẻ span thôi nhưng lại có đến 3 selector cố gắng “tranh nhau” thay đổi màu sắc của nó, giống như một cuộc chiến vậy. Nhưng tin vui là cuộc chiến này sẽ luôn luôn có người chiến thắng, nhờ vào trọng tài là browser. Tuy nhiên browser làm thế nào để xác định người chiến thắng? Câu trả lời là nhờ vào một tập các quy tắc, và browser cứ dựa theo tập quy tắc này để xác định ai là người chiến thắng. CSS Specificity chính là một phần chính yếu trong “tập quy tắc” đấy nhé.

Mình sẽ định nghĩa đơn giản như sau:

Specificity là một trọng số mà browser dựa vào đó để xác định xem một element sẽ có css style là gì. Trọng số chỉ đơn giản như việc 2 > 1 thì 2 chiến thắng, hay 3 > 2 thì 3 chiến thắng, vậy thôi. Một điều cũng quan trọng không kém: Specificity là trọng số của CSS selectors nhé. Nói nôm na hơn, browser sẽ cố gắng xác định xem selector nào là cụ thể nhất (most specific) và style theo selector đó.

“Tập quy tắc” này có phức tạp không? Xác định trọng số Specificity có phức tạp không? Browser dùng tới nó thì chắc hẳn là nó phức tạp lắm? Câu trả lời là nó không hề phức tạp và developer vẫn có thể học thuộc nó một cách dễ dàng. Nói cách khác, 80% các quy tắc là rất đơn giản và dễ hiểu, có thể học thuộc được, còn 20% quy tắc còn lại sẽ khá rối rắm mà ít khi chúng ta sử dụng trong thực tế, nên chúng ta không cần phải nhớ nó, cứ để browser làm việc của nó là được.

Tại sao developer lại nên học thuộc tập quy tắc này (80% các quy tắc thường sử dụng thôi)? Điều này mình không hề chém gió đâu, nếu bạn là một frontend developer chuyên xử lý layout và CSS, thì đây là một kiến thức mà bạn nên nằm lòng, chứ không phải chỉ là để đọc chơi cho biết. Tuy nhiên mình cũng không phải muốn các bạn thuộc nó một cách máy móc, mà nên hiểu nó. Và khi hiểu rồi thì sẽ tự thuộc thôi, hoặc khi quên thì chỉ cần đọc lại tí xíu là nhớ.

Cách xác định trọng số Specificity và cách so sánh

Cách xác định trọng số của CSS selectors chỉ đơn giản là chơi trò chơi đếm số và điền vào 3 ô trống bên dưới thôi.

CSS Specificity là gì vậy?
https://css-tricks.com/specifics-on-css-specificity/

Ở ô đầu tiên (ID), mình sẽ đếm xem selector có bao nhiêu id. Ví dụ #parent { } là 1, #parent #child { } là 2. Đếm xong rồi thì điền vào ô trống thôi.

CSS Specificity là gì vậy?

Ở ô thứ 2, mình sẽ đếm xem có tổng cộng bao nhiêu class (ví dụ .list), psuedo-class (ví dụ :hover) và attribute (ví dụ [type=radio]).

CSS Specificity là gì vậy?

Ở ô thứ 3, mình sẽ đếm xem có tổng cộng bao nhiêu type selector (ví dụ h1), pseudo-element (ví dụ ::before)

CSS Specificity là gì vậy?

Chúng ta cơ bản đã xong bước xác định trọng số rồi, giờ thì so sánh chúng thôi. Cách so sánh cực kì đơn giản, như toán lớp 1 vậy:

  • 1,1,0 lớn hơn 1,0,0 (110 > 100)
  • 0,1,0 lớn hơn 0,0,1 (10 > 1)
  • 1,3,0 lớn hơn 1,0,3 (130 > 103)
  • 0,0,1 bằng với 0,0,1 (1 === 1)

Ồ, nếu bằng nhau thì thế nào? Nếu bằng nhau thì thằng nào được khai báo sau cùng sẽ thắng. Điều này mình sẽ lặp lại ở phần tiếp theo. Giờ thì cùng nhau thực hành đếm trọng số qua các ví dụ sau nhé:

  • #parent: 1,0,0
  • #parent #child: 2,0,0
  • [id="parent"]: 0,1,0
  • li: 0,0,1
  • ul > li: 0,0,2
  • ul ol + li: 0,0,3
  • h1 + *[rel=up]: 0,1,1
  • ul ol li.red: 0,1,3
  • li.red.level: 0,2,1
  • li.name::before: 0,1,2
  • #parent:not(ul): 1,0,1
  • .foo:is(.bar, #bar): 1,1,0

Một số quy tắc khác

Có một số quy tắc khác ít nhiều ảnh hưởng đến trọng số Specificity mà bạn không thể bỏ qua:

  • Universal selector * sẽ được bỏ qua khi xác định trọng số. Ví dụ selector * sẽ có trọng số là 0,0,0. Hay *.foo sẽ có trọng số là 0,1,0. Điều này có nghĩa là *.foo và .foo là hoàn toàn giống nhau.
  • Combinators như +>~|| hay space cũng sẽ được bỏ qua khi xác định trọng số. Ví dụ .parent .child và .parent > .child có cùng trọng số là 0,2,0.
  • :not() không được xem là pseudo-class nên cũng được bỏ qua khi tính trọng số. Tuy nhiên trọng số vẫn sẽ được tính với param truyền vào nó. Ví dụ: div:not(.parent) p sẽ có trọng số là 0,1,2.
  • :is() cũng tương tự với :not(), tuy nhiên vì chúng ta có thể truyền vào một danh sách selector, nên trọng số sẽ được tính với matched selector nào có trọng số cao nhất. Ví dụ: div:is(.parent, #foo) sẽ có trọng số có thể vừa là 0,1,1, vừa có thể là 1,0,1, vừa có thể là 1,1,1, tùy theo việc nó match với bao nhiêu trường hợp. Cũng phức tạp ghê phải không nào.
  • “Inline styles” sẽ luôn luôn có trọng số cao nhất, đánh bật tất cả các đối thủ (ngoại trừ trùm cuối !important). Ví dụ bạn viết:
    <span class="text" style="color: red">text</span>
    

    thì dù bạn cố gắng viết CSS (external CSS) để thay đổi color của nó đều vô ích (tất nhiên như mình đã nói, bạn vẫn có thể nếu dùng đến !important)

    .text {
      color: green; /* không được đâu nhé, nó thua inline style */
    }
    
    .text {
      color: blue !important; /* khi đã dùng tới trùm cuối thì đừng hỏi nữa */
    }
    
  • Trùm cuối của chúng ta !important có thể đánh bại mọi đối thủ, ngay cả inline style vốn đã vô cùng mạnh mẽ. Bạn xem ví dụ ngay phía bên trên là rõ. Tuy nhiên nếu 2 anh trùm cuối cùng đánh nhau thì thế nào? Câu trả lời ở quy tắc ngay bên dưới. Ví dụ:
    .text {
      color: green !important; /* ê blue, đấu với tao không */
    }
    
    .text {
      color: blue !important; /* tao sợ mày à green, chơi luôn */
    }
    
  • Khi 2 hoặc nhiều selector có cùng trọng số, thì selector nào được khai báo cuối cùng sẽ thắng. Trong cuộc đối đầu ở quy tắc bên trên, blue là người chiến thắng. Tất nhiên nếu ta đổi vị trí 2 selector này cho nhau, thì green lại là người chiến thắng. Đây là một lỗi thường thấy khi chúng ta không am hiểu về Specificity (thường là các bạn junior), vô tình thay đổi vị trí hoặc chỉnh sửa CSS vô tội vạ làm thay đổi trọng số, dẫn đến lỗi style không mong muốn.

Độ gần/xa (proximity) có ảnh hưởng không?

Thật sự mình không biết nên dịch từ “proximity” thế nào cho đúng, nhưng ý nghĩa của nó có hiểu qua ví dụ ở đầu bài viết.

<html>
  <head>
    <style>
      body h1 { color: green; }
      html h1 { color: purple; }
    </style>
  </head>

  <body>
    <h1>text</h1>
  </body>
</html>

“Proximity” ám chỉ việc thẻ h1 gần với body hơn là html, vậy liệu selector body h1 có trọng số lớn hơn html h1 không? Câu trả lời là KHÔNG.

Trong trường hợp này, vì cả 2 đều có cùng trọng số là 0,0,2, chúng ta sẽ sử dụng quy tắc “thằng nào được khai báo cuối cùng sẽ thắng”. Vậy kết quả sẽ là html h1 chiến thắng, màu của thẻ h1 sẽ là purple.

Lưu ý & suy ngẫm

  1. Một selector với trọng số lớn liệu có tốt không? Ví dụ:
    /* Trọng số là 2,3,4 */
    #main article.sports table#stats tr:nth-child(even) td:last-child {
      ...
    }
        

    Với trọng số là 2,3,4, bạn sẽ rất khó để override nó, và sẽ làm cho code của bạn rối rắm và khó để maintain hay extend.

  2. Bất kì khi nào bạn rơi vào tình huống không hiểu vì sao element của mình lại có style không như mong muốn, thì Specificity sẽ giúp bạn. Tuy nhiên thay vì ngồi đếm trọng số bằng tay, giờ đây với công cụ devtools mạnh mẽ của các browser thì việc xác định lỗi style là vô cùng đơn giản. Tuy nhiên các công cụ này cũng xây dựng trên nguyên lý CSS Specificity mà thôi chứ không có gì khác biệt đâu.
  3. Specificity chỉ có ý nghĩa nếu một element có nhiều selector cùng trỏ (target) đến nó. Nói nôm na là nếu cuộc chiến mà chỉ có 1 người tham gia thì hiển nhiên người đó thắng rồi.
  4. Trong CSS có việc kế thừa style từ các element cha. Tuy nhiên việc kế thừa này sẽ luôn xếp sau những selector trỏ (target) đích danh đến element nhé. Bạn để ý khi sử dụng devtools là thấy thôi.
  5. Việc có nên sử dụng inline styles không vẫn là một vấn đề gây tranh cãi. Một số linter sẽ warning nếu bạn viết inline styles, nhưng bạn vẫn có thể tắt warning đó đi nếu muốn. Một trong những lý do là vì trọng số của nó quá cao sẽ dễ gây ra các lỗi không mong muốn, hoặc sẽ rất khó để override và buộc phải dùng đến !important. Một lý do khác nữa là với nhiều “chuyên gia” thì CSS nên đặt trong các file .css để dễ quản lý, chứ nếu nằm trong style (html) thì rối loạn lên hết?
  6. Mặc dù trùm cuối !important vô cùng mạnh mẽ, việc dùng đến !important không phải là một giải pháp tốt và cần hạn chế sử dụng, giống như inline styles mà mình vừa đề cập đến. Trước khi buộc phải dùng đến !important, bạn hãy suy xét cẩn thận xem chúng ta có thể sử dụng CSS Specificity để đạt được mục đích hay không.

BEM & ITCSS

Ở đây mình không phải muốn giải thích hay giới thiệu chi tiết về 2 “phương pháp” này, mà chỉ muốn chỉ ra một vài điểm liên quan với Specificity thôi. Ngoài BEM và ITCSS ra còn có nhiều phương pháp khác nữa, nhưng cơ bản đều xây dựng trên Specificity cả.

BEM: mình mặc định bạn đã biết đến BEM, thì một vài tôn chỉ của nó có thể kể đến như:

  • Tránh sử dụng id (#foo): lý do thì như mình đã chia sẻ, id có trọng số lớn và khá khó để override, nên việc cố gắng override nó sẽ dễ đẩy CSS của bạn đến một tương lai không mấy sáng sủa.
  • Tránh nested selector, cố gắng làm phẳng selector: cũng cùng lý do, nested selector cũng làm tăng trọng số của selector. Ví dụ BEM sẽ khuyến khích:
    /* BEM thích điều này, trọng số chỉ là 0,1,0
    nhưng vẫn rất specific và khó bị conflict */
    .block {}
    .block__elem1 {}
    .block__elem2 {}
    .block__elem3 {}
    
    /* Trọng số sẽ là 0,2,0, cũng không quá tệ, nhưng BEM không khuyến khích,
    và nó cũng rất dễ bị conflict. */
    .block {}
    .block .elem1 {}
    .block .elem2 {}
    .block .elem3 {}
        

ITCSS: cũng là một phương pháp ứng dụng triệt để các quy tắc của CSS Specificity, giúp CSS của bạn có thể dễ dàng scale, extend và maintain (SEM). ITCSS có rất nhiều thứ để nói nhưng nằm ngoài phạm vi bài viết nên mình xin dừng ở đây, nếu các bạn quan tâm thì để lại comment để mình làm một bài viết riêng về nó nhé.

CSS Specificity calculator

Chỉ cần search google là bạn sẽ thấy một vài tool sẽ giúp bạn xác định trọng số của selector:

https://polypane.app/css-specificity-calculator/
https://www.codecaptain.io/tools/css-specificity-calculator
https://isellsoap.github.io/specificity-visualizer/

Tuy nhiên các bạn cũng không nên hoàn toàn tin tưởng vì các tool này chỉ đếm trọng số trong những trường hợp đơn giản, còn những trường hợp phức tạp hơn thì vẫn có thể sai nhé.

Mình chốt lại bài viết bằng một tấm hình vui nhưng khá nổi tiếng nhé.

CSS Specificity là gì vậy?
https://specifishity.com/

Lời kết

CSS cơ bản thật ra cũng không nhiều, bạn chỉ cần biết vừa đủ là có thể tung hoành giang hồ được rồi. Vì nó không nhiều và cũng không khó, nên các bạn hãy dành thời gian học và nắm vững nó nhé. Trước giờ mình đi phỏng vấn với vị trí frontend, mình thấy khá hiếm công ty nào phỏng vấn về CSS, có lẽ họ mặc nhiên rằng frontend developer thì phải biết CSS, hoặc bản thân họ không thích CSS nên không muốn đặt câu hỏi. Nhưng nếu vô tình được hỏi, thì hãy “chém tơi bời” interviewer nhé 😀

Như mọi lần, nếu các bạn thấy bài viết có gì thiếu sót hay sai chỗ nào thì vui lòng để lại comment cho mình biết để sửa đổi. Nếu các bạn thấy bài viết hay và hữu ích thì upvote hoặc comment để mình có động lực viết tiếp các bài tiếp theo nhé.

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

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

Xem thêm các tuyển dụng CSS hấp dẫn tại TopDev

Viết một chatbot đơn giản với Python3

Viết một chatbot đơn giản với Python3

Bài viết được sự cho phép của tác giả Nguyễn Việt Hưng

Chatbot là gì?

Trước khi thò tay vào hì hục code, ta cần hiểu chatbot là gì đã?

Chatbot là một chương trình thực hiện cuộc hội thoại qua phương pháp gửi nhận văn bản hoặc các object như hình ảnh, file, … Chú ý Chatbot không nhất thiết là phải thông minh, là phải dùng trí tuệ nhân tạo, etc …

Có bao giờ sắp đến giao thừa hay một dịp mà bạn muốn nhắn tin cho nhiều người vào 12h đêm mà bạn không thể dậy được, hoặc bạn quá lười để làm một việc lặp đi lặp lại? Câu trả lời là viết một chatbot và hẹn giờ cho nó.

  Trải nghiệm lần đầu viết thư viện Python từ ngôn ngữ biên dịch

Viết chatbot

Trong bài viết này mình sử dụng 2 thư viện có sẵn trên mạng là fbchatschedule do đó bạn cần tạo virtualenv trước tiên, sau đó dùng pip để cài 2 lib trên rồi tạo một file code python tùy ý, ở đây mình dùng chatbot.py.

Đầu tiên, import những lib mình cần

import logging
import os
import time
from threading import Thread
from fbchat import Client
from fbchat.models import Message, ThreadType
import schedule

Sau đó tạo một class Bot kế thừa Client:

class Bot(Client):

Tạo 1 function trong class Bot để thực hiện gửi tin nhắn, dưới đây là code của mình:

class Bot(Client):
    def do_something(self):
        #Đổi tên function cho phù hợp
        logging.basicConfig(level=logging.INFO)
        lst_id = [...] # List chứa fb id của những người bạn muốn gửi
        for user_id in lst_id:
            self.send(Message(text="Chúc mừng năm mới"),
                      thread_id=user_id, thread_type=ThreadType.USER)
            self.sendLocalImage('/home/dosontung007/Pictures/wallpaper.png', message=Message(text='Chúc mừng năm mới'),
                                thread_id=user_id, thread_type=ThreadType.USER)
            logging.info('Sent success to %s' % str(user_id))

Và để nhận được tin nhắn từ những người gửi cho mình cho mình , ta viết function onMessage trong class Bot và xử lí các tin nhắn đó:

def onMessage(self, message_object, author_id, thread_id, thread_type, **kwargs):
    lst_msg = list('Chúc mừng năm mới')
    if author_id != self.uid and message_object.text in lst_msg:
        self.send(Message(text='Năm mới chúc .....'),
                  thread_id=author_id,
                  thread_type=thread_type)

Tham khảo thêm tại https://fbchat.readthedocs.io/en/master/

  Tại sao phải chọn giữa R hay Python trong khi bạn có thể chọn cả 2?

Job thực hiện việc gửi tin nhắn trong này đó là:

Bot(os.environ['USERNAME_'], os.environ['PASSWORD']).do_something()

Class Bot kế thừa Client, khi tạo một Bot object, ta cần truyền 2 tham số là username và password của Facebook của bạn. Do đó bạn cần set value cho 2 var USERNAME_ và PASSWORD bằng câu lệnh export var=value trong bash trước khi chạy chương trình (vì ta không muốn ghi trực tiếp password vào file code – lộ mật khẩu nếu up lên GitHub). Lưu ý USERNAME_ chứ không phải USERNAME.

Bây giờ còn một công việc duy nhất là hẹn giờ cho job làm việc thôi!

def job():
    Bot(os.environ['USERNAME_'], os.environ['PASSWORD']).do_something()


def send_msg():
    schedule.every().day.at('00:00').do(job_that_executes_once))

    while True:
        schedule.run_pending()
        time.sleep(1)

Thay đổi 00:00 bằng thời gian mà bạn muốn hẹn giờ.

Để nhận được message, ta sử dụng function listen từ Client , về cơ bản listen khi chạy sẽ truyền các arguments vào onMessage mỗi lần Facebook bạn có event mới (VD: có người nhắn cho bạn, bạn nhắn cho người khác hoặc tin nhắn trong nhóm, …):

def reply_msg():
    Bot(os.environ['USERNAME_'], os.environ['PASSWORD']).listen()

Ở function main, mình sử dụng lib threading để chạy song song 2 job là reply_msg và send_msg :

def main():
    Thread(target=send_msg).start()
    Thread(target=reply_msg).start()

Cuối cùng cũng xong .Sau tất cả, đây là một con chatbot hoàn chỉnh :

import logging
import os
import time
from threading import Thread

from fbchat import Client
from fbchat.models import Message, ThreadType
import schedule


class Bot(Client):
    def onMessage(self, message_object, author_id, thread_id, thread_type, **kwargs):
        lst_msg = list('Chúc mừng năm mới')
        if author_id != self.uid and message_object.text in lst_msg:
            self.send(Message(text='Năm mới chúc .....'),
                      thread_id=author_id,
                      thread_type=ThreadType.USER)


    def do_something(self):
        logging.basicConfig(level=logging.INFO)
        user_ids = ['100012610305665']
        for user_id in user_ids:
            self.send(Message(text="Chúc mừng năm mới"),
                      thread_id=user_id, thread_type=ThreadType.USER)
            self.sendLocalImage('/home/dosontung007/Pictures/wallpaper.png', message=Message(text='Chúc mừng năm mới'),
                                thread_id=user_id, thread_type=ThreadType.USER)
            logging.info('Sent success to %s' % "100012610305665")


def job_that_executes_once():
    Bot(os.environ['USERNAME_'], os.environ['PASSWORD']).something()
    return schedule.CancelJob


def reply_msg():
    Bot(os.environ['USERNAME_'], os.environ['PASSWORD']).listen()


def send_msg():
    schedule.every().day.at('00:00').do(job_that_executes_once))
    while True:
        schedule.run_pending()
        time.sleep(1)


def main():
    thread1 = Thread(target=send_msg)
    thread2 = Thread(target=reply_msg)

    thread1.start()
    thread2.start()

    thread1.join()
    thread2.join()


if __name__ == '__main__':
    main()

Bây giờ export username, password rồi chạy thôi. Và đây là thành quả:

Viết một chatbot đơn giản với Python3

Nếu bạn muốn chạy luôn mà không cần hẹn giờ thì chỉ cần xoá function job_that_executes_once và thay function send_msg bằng:

def send_msg():
    Bot(os.environ['USERNAME_'],os.environ['PASSWORD']).do_something()

HẾT.

Bài viết gốc được đăng tải tại pp.pymi.vn

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

Xem thêm tuyển dụng python nhiều vị trí hấp dẫn tại TopDev

Top 5 API thú vị dành cho các New Developers

Top 5 API cho các New Developers

Bài gốc được viết bởi tác giả Elle Townsend

Khi đang cố gắng để cải thiện kỹ năng Front-end và JavaScript của mình, tôi đã nảy ra ý tưởng học thêm về các API. Dưới đây tôi sẽ chia sẻ với mọi người một số API thú vị mà tôi hay sử dụng.

API là gì?

API – Application Programming Interface là phương thức trung gian kết nối các ứng dụng và thư viện khác nhau. Nó cung cấp khả năng truy xuất đến một tập hợp các hàm hay dùng, từ đó có thể trao đổi dữ liệu giữa các ứng dụng. Bên cạnh đó, các phương thức này sử dụng mã nguồn mở, dùng được với mọi client hỗ trợ XML, JSON và được đánh giá là một trong những kiểu kiến trúc hỗ trợ tốt nhất với các thiết bị có lượng băng thông bị giới hạn như smartphone, tablet…

Xem thêm Top 20 API trong AI và Machine Learning bạn nên biết

topdev

Một số API được sử dụng nhiều:

1. REST Countries

REST Countries là nguồn tài nguyên hữu ích để tạo các dự án mới. Nó lưu trữ tài liệu của nhiều lĩnh vực khác nhau từ đơn vị tiền tệ, thủ đô quốc gia đến các ngôn ngữ trên khắp thế giới. Cá nhân tôi từng tạo API calls trong Vue.js với Axios.

2. The PokéAPI

Tôi rất thích nền tảng này, The PokéAPI cũng là phương thức đầu tiên tôi sử dụng và đã thực hiện một số dự án bằng API này. PokéAPI chứa nguồn dữ liệu lớn đặc biệt phù hợp với những người mới bắt đầu, không giới hạn về tỉ lệ và có mọi thứ bạn cần để tạo một PokéDex của riêng mình.

  20 trường hợp sử dụng lệnh Docker cho developer
  Software Developer và 5 bài học kinh nghiệm quan trọng

3. Translation APIs

Có rất nhiều API để dịch văn bản sang các ngôn ngữ khác nhau bao gồm cả Yandex Translator và Google translate. Đặc biệt, với những nhân vật trong các tác phẩm kinh điển như Elvish – Chúa tể của những chiếc nhẫn, Yoda – Chiến tranh giữa các vì sao hay Groot – Vệ binh dải ngân hà họ đều không nói ngôn ngữ của loài người, các translation APIs còn cho phép chúng ta dịch được cả tiếng của họ trong phim nữa.

4. Affirmations API

Affirmations API được Tilde Ann Thurium tạo trên Github cho phép bạn truy cập thư viện những affirmation dễ nhìn nhất. Truy cập https://www.affirmations.dev/ và bạn sẽ được recommend những ý tưởng affirmation sáng tạo nhất và áp dụng cho dự án của mình.

Xem thêm Software Developer và 5 bài học kinh nghiệm quan trọng

5. Spotify

Nếu vẫn không có API nào thật sự thu hút bạn thì hãy thử cân nhắc đến khía cạnh âm nhạc xem. Spotify có một nền tảng với các nguồn dữ liệu mở về thông tin ca sĩ, nhạc sĩ, bài hát, album, tạo và hiển thị danh sách phát và kể cả tạo một giao diện Spotify cho riêng cá nhân bạn luôn.

Kết luận

Hy vọng rằng một số API trên đây sẽ có thể cho bạn thêm thông tin cần thiết và hữu ích với các dự án tiếp theo của bạn.

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

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

Xem thêm các việc làm Developer hấp dẫn tại TopDev

Làm quen với kiến trúc Serverless

Làm quen với kiến trúc Serverless

Bài viết được sự cho phép của tác giả Lưu Bình An

Mười mấy năm về trước, ngày còn đang học đại học, mỗi lần đến ngày đăng ký môn học là mình được nghe điệp khúc hát mãi “server quá tải, số lượng sinh viên tranh nhau vào các lớp có nhiều gái xinh quá đông, quá nguy hiểm, mấy em vui lòng canh 12 giờ đêm, khi ko còn ai lên đăng ký môn học, chúng tôi mới đáp ứng kịp”

  Sập server, làm gì đây?
  Chuỗi chuyên đề độc quyền về Serverless từ Amazon Web Services

Ngày đó Server của trường nằm ở Nguyễn Văn Tráng, phòng server nhỏ như hang thỏ, mà chỉ xài đúng mấy ngày đầu học kỳ, nên thầy trưởng khoa ko thể nào xin ngân sách được để mà nâng cấp 10 mấy con server cho các em sinh viên xài thỏa thích.

Bài toán Server đó giờ được giải quyết ra sao? Serverless

Trước tiên cần khẳng định Serverless không phải là bạn không cần server. Một shop thú nuôi đơn giản, vài ngàn người mua hoa một tháng, làm bằng wordpress bạn sẽ không thấy được lợi ích từ việc sử dụng kiến trúc mới này, không những vậy còn là việc ném một cục tiền cho mấy thằng bán dịch vụ như Amazon

Trang bán thú nuôi, kiến trúc cũ sẽ là thế này

Làm quen với kiến trúc Serverless

Tất cả những logic sẽ nằm ở ứng dụng phía server: từ authentication, page navigation, searching, transaction (code backend đó)

Yêu cầu cần có ngân sách, kế hoạch cụ thể, lắp đặt các hệ thống máy chủ, tìm một chỗ để máy, đảm bảo luôn có điện, luôn mát lạnh, đi dây, chọn nhà cung cấp mạng không bị cá mập cắn…

Nói chung bạn tự làm mọi thứ, hoặc bỏ tiền ra thuê một thằng làm mọi thứ, mà nó còn hay đòi hỏi thêm thắt này kia nọ, vô cùng tốn thời gian, nhân lực, tiền bạc, cơ sở hạ tầng.

Infrastructure as a service – IaaS, các dịch vụ cho thuê mặt bằng ra đời. Đáp ứng nhu cầu tiết kiệm chi phí ở thời điểm đầu, nhưng vẫn có thể bành trướng khi cần.

Bạn hình dung nó như việc mở một quán ăn, phải tìm mặt bằng, tìm người giữ xe, chỗ để xe cho khách, thu hút khách vào ăn, thanh toán, sửa chữa điện, nước… Những thằng IaaS là các trung tâm thương mại, nó lo hết mọi thứ khác, bạn chỉ việc bỏ tiền ra và thuê lại mặt bằng và kinh doanh.

Serverless là gì

Nó như một khái niệm kinh tế học, không có một cách định nghĩa chính xác Serverless là gì! Có thể hiểu theo 2 cách sau

Serverless được dùng để ám chỉ những ứng dụng sử dụng phần lớn (hoặc toàn bộ) dịch vụ “nhà hàng xóm” (third-party), được host trên cloud, cho các vấn đề ở phía server là logic và state (ví dụ trạng thái đăng nhập, một dạng của dịch vụ chăm sóc khách hàng thân thiết). Những ứng dụng để sử dụng (không phải những trang profile công ty, show hiệu ứng bay lượn portfolio, ví dụ như Facebook, ứng dụng đăng ký môn học, hoặc ứng dụng điện thoại bị chửi bới quá trời FaceApp, tức là mô hình này không chỉ áp dụng riêng cho web). Những dịch vụ thường được outsource cho nhà hàng xóm là gì: database có ParseFirebase, authentication có Auth0, AWS Cognito. Mấy nhà này nằm trong khu “Backend as a Service” – BaaS, khi gắn vào hậu tố as a Service bạn có thể biết là nó nằm ở nhà hàng xóm.

Serverless cũng có nghĩa là ứng dụng đó logic server vẫn có, developer vẫn phải viết logic này, tuy nhiên, không giống kiến trúc truyền thống, nó chạy theo cơ chế “tiền trao-cháo múc” (event-trigger), không quan tâm anh bạn có ở chung nhà mình không (stateless compute container). Khái niệm này được @marak trên Twitter gọi là Function as a Service – FaaS, bạn có nhu cầu cắt tóc, gội đầu, uống cafe, đánh giày thì bạn ra tiệm hết, không dùng đồ nhà có sẵn nữa. Hiện tại, AWS Lambda là một trong những platform nổi tiếng nhất khi nói đến FaaS

Giờ nói tới FaaS, nó đang là trend, nó thay đổi cách chúng ta trước đây vẫn nghĩ về kiến trúc dưới server.

Tất cả những ông lớn đều có các sản phẩm BaaS và FaaS, Amazon ServerlessGoogle Cloud Functions for Firebase.

Làm quen với kiến trúc Serverless

Một kiến trúc Serverless nó như thế này

Làm quen với kiến trúc Serverless

  1. Phần authen trước đây được gửi nhà hàng xóm làm (cơ quan nhà nước chuyên cung cấp CMND)
  2. Dữ liệu được đưa một về nhà kho quản lý, kiểu như Tiki bây giờ quá mệt quản lý kho hàng, các cửa hàng nhỏ lẻ tự quản lý kho, Tiki bán được thì chạy tới kho của bên thứ 3 lấy.
  3. Với 2 thay đổi ở trên, điều này có nghĩa là một vài logic đã được nằm ở phía client, thí dụ, user session, bạn sẽ thấy rõ nhất ở các Single Page App chúng ta build, phần logic giao diện cho user đã và chưa đăng nhập nằm ở client – nhà user, những route nào user có thể vào nằm ở code client
  4. Một vài hiển thị, ràng buộc tất nhiên vẫn được server nắm. Thí dụ “search”. Chúng ta có thêm một nhà gọi là “API Gateway”, dịch vụ giao nhận, tất cả các yêu cầu từ client đưa về đây, các anh em HTTP sẽ đi lấy dữ liệu từ kho về cho chúng ta.
  5. Với tính năng đặt hàng, nó do một nhà** khác cung cấp. Những logic khác nhau, được tách và deploy thành những cục* khác nhau như vậy cách tiếp cận của FaaS cũng là cách tiếp cận rất phổ biến trong “Microservices”

Nó sẽ có những lợi ích i chang như Microservices, tất nhiên là có trả giá, có nhiều thứ để kiểm soát và theo dõi hơn, vấn đề bảo mật cũng không phải đơn giản như xưa, nằm ở nhiều nơi quá mà, bài toán đi đi lại tránh kẹt xe giữa các hệ thống khác nhau, biết đâu đi lạc vào chổ nào đó mất CMND luôn !!

Function as a Service

Nãy giờ nói FaaS nhiều quá rồi, giờ “đào sâu” nghiên cứu nó chút. Trích dẫn từ trang Amazon Lambda

AWS Lambda lets you run code without provisioning or managing servers. (1) … With Lambda, you can run code for virtually any type of application or backend service (2) – all with zero administration. Just upload your code and Lambda takes care of everything required to run (3) and scale (4) your code with high availability. You can set up your code to automatically trigger from other AWS services (5) or call it directly from any web or mobile app (6).

Diễn giải đoạn dài ngoằn kia

(1) FaaS là chạy backend code mà không cần quan tâm việc quản lý và bảo trì hệ thống server.

(2) FaaS không yêu cầu một framework hay thư viện cụ thể nào. Các function trên Lambda có thể được viết bằng Javascript, Python, Go, Java, Clojure, Scala, .NET.

(3) Deploy sẽ rất khác với hệ thống truyền thống. Tới *nhà** của FaaS chúng ta đưa đoạn code cho chủ nhà, còn lại chủ nhà làm gì thì làm.

(4) Scale sẽ tự động được chủ nhà làm. Nếu hệ thống cần đáp ứng 1000 request đồng thời, chủ nhà sẽ lo, bạn chỉ cần bơm tiền. Quan trọng nhất, bên cung cấp dịch vụ sẽ quản lý hết toàn bộ resource, xin giấy phép, nói chung là toàn bộ – bạn không cần làm gì với cluster, VM cả.

(5) Cung cấp cơ chế trigger ứng với các event bạn muốn.

(6) Mấy bên cung cấp dịch vụ, cho phép các function này trigger theo những sự kiện HTTP request, như ví dụ là search, và purchase, hoặc gọi trực tiếp lên các API được cung cấp bởi bên cung cấp

Case Study

PhotoVogue trang Vogue của Ý, chạy từ năm 2011, sau một năm chạy, photographer bu vô như kiến, server ở nhà riêng quá tải không chịu nổi.

Giám đốc kỹ thuật quyết định chuyển đổi toàn bộ hệ thống server ở nhà riêng sang AWS trong 3 tháng.

Chạy theo trend này, còn có những cái tên rất phổ biến là Uber, Pokemon Go, Airbnb, Clash of Clans và rất nhiều ứng dụng khác khi số lượng user và real-time data lớn

Những vấn đề mà team PhotoVogue đã gặp

  • Có hơn 130,000 photographer trên khắp thế giới sử dụng hệ thống để đưa ảnh lên, ước tính có khoảng 400,000 ảnh, với dung lượng tối đa mỗi hình là 50MB (bọn này chơi sang nhỉ)
  • Số lượng truy cập ngày càng tăng
  • Trải nghiệm sử dụng của user không tốt, thao tác xử lý quá chậm, up ảnh quá rùa

Với AWS, nó đã giải quyết các vấn đề sau cho PhotoVogue

  • Khả năng scale, dễ maintenance, quản lý chi phí rõ ràng
  • Lưu trữ hình trên Amazon S3
  • Khi up lên Amazon S3, bật trigger sử dụng AWS Lambda function, convert các file này qua gif, jpeg, png, tiff
  • Amazon API Gateway được sử dụng để làm tầng caching của REST API, Amazon CloudFront cho CDN

Làm quen với kiến trúc Serverless

Còn vấn đề nào nữa không, mình hy vọng bạn nào chuyên gia vào chỉ giáo

Tài liệu tham khảo

📜 What is Serverless Architecture? What are its Pros and Cons?

📜 Serverless Architectures

📜 Serverless Architecture: A Comprehensive Guide

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

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

Xem thêm các việc làm Developer hấp dẫn tại TopDev

Một số nguyên tắc thiết kế UI/UX website

thiết kế UX/UI

Bài viết được sự cho phép của tác giả Đoàn Văn Tuyển

Lâu rồi mình mới quay lại viết, chủ đề mình đã muốn viết từ rất lâu rồi: UI/UX. Mình tự nhận không phải là chuyên gia về UX, nhưng mình có thời gian đọc, tìm hiểu thử nghiệm nên cũng có một số kiến thức để chia sẻ với các bạn. Những gì mình viết ở đây chủ yếu là kiến thức liên quan phần visualization (UX thực tế là một khía cạnh rộng lớn hơn). Như mình suy nghĩ thì UX/UI có một số nguyên tắc cần ghi nhớ: First thing first (ưu tiên cho điều quan trọng nhất), Don’t make me think và Consistent (2 cái đầu trùng với tên 2 quyển sách mình khá thích).

1. First thing first

FTF nghĩa là mình luôn luôn ưu tiên cho những thứ quan trọng nhất. Nghĩa là mình sẽ ưu tiên nhóm khách hàng quan trọng, nhóm tính năng quan trọng, thông tin quan trọng với khách hàng…. Cụ thể những thứ mình nghĩ thì như sau:

1.1 Mobile First:
Hiện tại đa số các website vẫn sử dụng thiết kế cho mobile dạng Responsive (nghĩa là Desktop First — Mobile là ưu tiên sau). Giờ là thời buổi mobile, 80% khách hàng sử dụng mobile. Vậy việc thiết kế riêng cho Mobile là điều cực kỳ quan trọng. Cụ thể phần mobile thì phần cuối mình sẽ có một số ví dụ cụ thể hơn, còn ở đây mình cũng nêu một số ví thứ cần để ý:
Màn hình mobile khá nhỏ nên không thể hiển thị full thông tin như desktop => thế nên cần lựa chọn thông tin nào sẽ hiển thị trên mobile
Màn hình Mobile dạng dọc, chiều ngang khá hạn chế, thế nên các bảng biểu cần đều chỉnh thông tin lọt vào màn hình 320–400 pixel (so với 1366 đến 1920 của PC) hoặc tối thiểu cũng có thể scroll để nhìn được.

1.2 Để ý đến khung nhìn đầu tiên:

Một số nguyên tắc thiết kế UI/UX website

Ví dụ về việc khung nhìn đầu tiên không tốt, những thứ ít quan trọng được show lên ở khung nhìn đầu tiên. Ngoài ra phần khoảng trắng cũng không hợp lý.

Khung nhìn đầu tiên là khung nhìn của người dùng mà người dùng không cần Scroll ngang hoặc scroll xuống. Mình nên đặt những thông tin quan trọng nhất vào khung nhìn này. Thay vì việc đặt một banner quá to (và có thể ít thay đổi) thì nên thu nhỏ lại và đưa thông tin quan trọng lên. Việc này đôi khi cũng không được để ý trên mobile, một số màn hình khi vào chỉ nhìn được giao diện của tab hoặc nhứng thông số filter, trên mobile có thể ẩn bớt một số thành phần ít quan trọng để vùng nhìn đầu tiên có thể thể hiện được nhiều thông tin quan trọng. Vùng nhìn đầu tiên còn đặt biệt quan trọng với màn hình chính / màn hình dashboard.

1.3 Chức năng quan trọng:

Một số nguyên tắc thiết kế UI/UX website

Những menu quan trọng được đưa ra trang chủ, link quan trọng hiện ra luôn thay vì ẩn trong menu.

Một trong những vấn đề cần để ý nữa là chức năng quan trọng cần được dễ dàng điều hướng tới. Ngoài việc menu sắp xếp để sao người dùng dễ dàng tìm được những menu quan trọng nhất. Menu nếu cần có thể để hiển thị thay cho việc giấu đi, chức năng muốn người dùng click nhất thì hiển thị rõ lên. “Call to action” cần làm nổi bật và hiển thị ở vùng nhìn đầu tiên. Menu trên mobile có thể thể hiện luôn thay vì giấu đi trên mobile như đa số các website. Một trong những sai lầm kinh điển phần này là người dùng sử dụng quá nhiều icon mà quên đi text. Đôi khi bản thân icon không thể hiện chính xác thông tin (cùng 1 icon mỗi người có thể có hình dung khác nhau), thế nên khi dùng icon thì mình nên thể hiện cả text để người dùng có thể hiểu được chứ năng.

1.4 Thông tin quan trọng:

Một số nguyên tắc thiết kế UI/UX website

Thông tin quan trọng được đưa lên trên và nhấn mạnh, căn phải số để dễ dàng so sánh

Thông tin quan trọng trên màn hình cần làm nổi bật. Một số những chỗ mình thường là như sau:

  • Trong bảng biểu: Cột tổng xếp lên đầu thay cho cuối, sắp xếp dữ liệu theo thứ tự giảm dần (số to lên trước)
  • Các thông tin muốn nhấn mạnh như giảm giá, giá tiền, status, cảnh báo, CTA… cần highlight để thể hiện rõ (nếu nhiều thứ cần chú ý thì sử dụng nhiều level như in đậm, in hoa, tăng font-size, màu sắc…)
  • Chia nhỏ đoạn văn thành những đoạn ngắn hơn, highlight những thông tin quan trọng.
  • Đưa chữ vào ảnh cũng là một thủ thuật tạo sự chú ý.

  6 câu lệnh linux hay dùng trong phân tích log

2. Don’t make me think

Đây là một trong những quyển sách gối đầu giường cho những người muốn biết về UX. Như tiêu đề bạn đã hình dung ra thứ mình muốn nói trong nguyên tắc này. Phần này có một số ý mình muốn nói:

2.1 Hướng dẫn cho khách hàng mới:
Khách hàng mới thường là nhóm khách hàng bơ vơ nhất, vào một hệ thống hoàn toán mới thường không biết làm gì tiếp theo. Thông thường bạn nên có làm những thứ như sau:

  • Gửi email chào mừng và chia sẻ những nguồn lực hỗ trợ cho họ: Hotline, support mail, link đến Q&A (nếu có), tài liệu liên quan nên đọc….
  • Nên có Tour hướng dẫn trên giao diện hoặc hướng dẫn hiển thị ngay trang dashboard.
  • Các chức năng phức tạp nên sử dụng thiết kế kiểu Wizard để dẫn dắt người dùng.
  • Cá nhân mình nghĩ không nên có tài liệu hướng dẫn đồ sộ, không ai có thời gian đọc chỗ đó. Có chăng chỉ là tài liệu để khi gặp vấn đề thì tra cứu (chứ ko phải để đọc hết).

2.2 Hướng dẫn khi gặp lỗi:
Mỗi khi khách hàng làm gì đó sai (ví dụ nhập thông tin không đúng định dạng) luôn hiển thị thông tin cảnh báo với 2 nội dung: lỗi gặp phải là gì & cách khắc phục thế nào. Đây là một trong những lỗi rất hay gặp khi làm giao diện. Khách hàng rơi vào tình trạng này thường rất hoang mang và không biết làm gì tiếp theo. Một trong những thứ cần để ý nữa là khi khách hàng submit form và bị lỗi, bạn phải khôi phục lại form y hệt thông tin trước khi khách hàng submit. Đặc biệt với form nhiều thông tin thì điều này khiến khách hàng rất ức chế.
Một trong những chú ý nhỏ là mình nên sử dụng hiệu ứng để thể hiện có điều gì đó đã diễn ra. Thay vì âm thầm hiển thị lỗi thì hãy để một số hiệu ứng như: loading, slide down…. để gây chú ý cho người dùng.

Nhiều vị trí tuyển dụng UI UX đang chờ bạn ứng tuyển trên TopDev

3. Consistent

Trong khi 2 nguyên tắc trên liên quan nhiều đến UX, thì nguyên tắc cuối lại liên quan đến UI nhiều hơn. Một trong những nguyên tắc theo mình là quan trọng nhất của UI là sự đồng nhất về thiết kế. Font chữ, khoảng cách, kích thước, màu sắc, vị trí đặt các button… tất cả đều cần sự đồng nhất. Nếu thiết kế dạng Mobile First bạn nên sử dụng thiết kế đã được chuẩn hoá của google (Material design system) hoặc Apple’s Flat Design. Hai Design System này có đầy đủ hướng dẫn cực kỳ chi tiết đến mức bạn chỉ cần đọc và áp dụng là đáp ứng được 90% nhu cầu trang mobile web của bạn. Dù Design System đề cập đến rất nhiều yếu tố nhưng mình xin nói về một số thành phần mình cho rằng quan trọng.

3.1 Typography:
Từ này dịch ra tiếng việt mình không rõ là gì nên để tiếng anh. Typography là nói đến các yếu tố liên quan đến chữ bao gồm: font chữ, in đậm in nghiêng gạch chân, font-size, màu chữ, cách dòng, chia cột chữ, khoảng cách giữa các paragraph….. Thực tế mình đôi khi mình không để ý nhưng tất cả những yếu tố trên khi đặt vào trang web muốn đẹp đều có những tỷ lệ nhất định và quan trọng nhất phải đồng nhất trên các trang. Những content cùng ý nghĩa phải có typography đồng nhất. Các button, status, form input, select đều cần có sử sự tương đồng này. Điều này ảnh hưởng rất lớn đến sự “đẹp” của website.

3.2 Khoảng cách và sự alignment:

Một số nguyên tắc thiết kế UI/UX website

Ví dụ về khoảng cách giữa các khối

Việc chia cột, khoảng cách các dòng, khoảng cách giữa các khối…. tất cả những thiết kế này cần có sự tương đồng giữa các trang. Khoảng cách trong form, khoảng cách tớ hai lề… tất cả những yếu tố này cũng cần có sự tương đồng. Một gợi ý nhỏ mình hay thực hiện ở phần này như sau:

  • Với màn hình điện thoại thì nên để khoảng cách giữa khối chính và hai lề nhỏ (để tăng không gian hiển thị)
  • Hạn chế dùng bo viền, sử dụng hai khối màu khác nhau để phân chia.
  • Khoảng cách giữa khối dạng cột thì nhỏ hơn khoảng cách giữa hai dòng.
  • Khoảng cách giữa hai yếu tố liên quan gần hơn so với khoảng cách giữa hai yếu tố ít liên quan.

3.3 Khoảng trắng (đặc biệt trên mobile).

Ví dụ về việc tận dụng không gian trên Mobile.

Khi thiết kế thì một trong những yếu tố quan trọng là khoảng trắng, đặc biệt quan trọng trên Mobile. Vì màn hình Mobile nhỏ, thế nên bạn chắc không muốn scroll chục màn hình để xem thông tin, do vậy thiết kế trên mobile thường tìm cách làm đầu màn hình. Khoảng trắng trên giao diện nên hạn chế chỉ cần đủ để đáp ứng tính thẩm mỹ.

3.4 Nguyên tắc trình bày các loại dữ liệu khác nhau
Một trong những nguyên tắc có thể có nhiều bạn ít để ý là nguyên tắc trình bày văn bản, đặt biệt là những văn bản trong bảng biểu, mình luôn cố gắng tuân thủ các nguyên tắc này, điều này giúp cho thông tin được hiển thị mạch lạc hơn rất nhiều.

  • Số luôn căng lề phải, sử dụng dấu phẩy/chấm để phân chia số phần ngàn. Nếu có thêm số sau số thập phân thì số lượng chữ số sau số thập phân hiển thị phải luôn bằng nhau ở tất cả các dòng trong cùng 1 cột
  • Sử dụng ký tự (-) thay cho những dòng trắng hoặc số giá trị 0
  • Đặt khoảng trắng chính xác khi bỏ các dấu câu như: (.,:;’)
  • Viết hoa đầu dòng, tiêu đề.
  • … Ngoài ra còn có rất nhiều nguyên tắc để đảm bảo sự đồng nhất, để nhìn, dễ đọc nữa, mỗi team nên có một danh sách cho việc này.

Tóm lại UI/UX là chủ đề dài tập, những gì mình nói ở đây mới chỉ là một phần nhỏ của vấn đề. Mình hy vọng ai đó đọc được bài viết này nếu thấy hay hãy chia sẻ lại cho bạn bè và những người bạn cho rằng cần thiết.

— — — — — — — — — — — — — — — — — — — — — — — — — — — — — — —

Bài viết của mình sử dụng khá nhiều kiến thức mình học được từ buổi trao đổi với Tùng Jacob bên TGDD và những slide của bạn ấy. Mọi người có thể xem thêm thông tin tại những link sau:

https://speakerdeck.com/tungjacob/vi-sao-nen-lua-hoa-website-ban-hang-make-a-website-your-mom-can-use
https://docs.google.com/file/d/0B_tCvYq4ZMQKQWJHTnlNZXVwdjg/edit?filetype=mspresentation
https://speakerdeck.com/tungjacob/ui-workshop-for-team-it-thegiodidong-dot-com
https://docs.google.com/presentation/d/1SCrMeZ83z2P37MkmGn6C6oLGERkN6y7vv-bezo_VBUo/edit
https://drive.google.com/file/d/0B_tCvYq4ZMQKYlNHY29BRWIyaUU/view

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

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

Truy cập ngay việc làm IT đãi ngộ tốt trên TopDev

Tìm hiểu đơn vị EM và REM

Tìm hiểu đơn vị EM và REM

Bài viết được sự cho phép của tác giả Trần Anh Tuấn

Chắc hẳn không ít các bạn khi code web thường hay cân nhắc việc sử dụng đơn vị như thế nào cho hợp lý mà lại hiệu quả. Nào là code trên desktop rồi khi responsive xuống mobile thì bị vỡ layout, cỡ chữ do đơn vị cố định rồi phải chỉnh css từng thành phần…

Ngoài những đơn vị như px, %, vw, vh, pt… thì trong số đó có 2 đơn vị em và rem luôn làm nhiều bạn nhầm lẫn, chưa nắm rõ nên sử dụng trong việc code khá là khó khăn, trắc trở.

  Dùng Px, Em hay Rem để viết media query
  Làm việc từ xa (remote) - Chính sách nhân sự mới của doanh nghiệp trong mùa dịch

Để giải quyết vấn đề đó nên hôm nay mình xin chia sẻ bài đầu tiên về 2 đơn vị em và rem này nhằm giúp các bạn có thể hiểu rõ và áp dụng chúng vào việc code giao diện ra sao nhé. Trước khi vào demo thì mình xin nhắc lại chút về khái niệm của 2 đơn vị em và rem này nha.

# Khái niệm về đơn vị em và rem

rem: là đơn vị tham chiếu tỷ lệ so với phần tử gốc của website ở đây là thẻ <html> dựa vào giá trị của thuộc tính font-size

em: là đơn vị tham chiếu tỷ lệ so với phần tử cha trực tiếp chứa nó hoặc chính nó dựa vào giá trị của thuộc tính là font-size

Tìm hiểu đơn vị EM và REM
Sơ đồ minh họa sự khác nhau giữa đơn vị em và rem

# Áp dụng thực tế

Mình chắn hẳn nhiều bạn đọc xong và thậm chí coi sơ đồ mà vẫn chưa hiểu lắm. Trước đây mình cũng thế. Và cách tốt nhất để hiểu và nắm rõ chúng đó là bắt tay vào code. Nên ở đây mình có làm 1 demo nho nhỏ để cho các bạn dễ hình dung hơn nè.

Đầu tiên là html như thế này:

<html>
<head><title>Em vs Rem</title></head>
<body>
<div class="box">
  <div class="em">EM</div>
  <div class="rem">REM</div>
</div>
</body>
</html>

Tiếp đến là css:

Ta được kết quả như sau. Bạn vẫn chưa hiểu ? Mình có giải thích chi tiết ở bên dưới cho các bạn

# Giải thích chi tiết

Đầu tiên mình tạo html layout gồm có 1 div có class box bọc ngoài và có 2 div bên trong tương ứng với class em rem  sau đó mình set cho thẻ <html> có thuộc tính font-size là 15px và lần lượt 2 ô là màu đỏ xanh cho các bạn dễ phân biệt.

Cho nên lúc này 1em = 1rem = 15px. Như các bạn nhìn vào demo ở trên thì 2 ô đều bằng nhau là 10(em-rem) x 15px = 150px của mỗi ô.

À có chỗ này sẽ có bạn hỏi là đơn vị em phụ thuộc vào phần tử cha chứa nó chứ có phải thẻ <html> đâu sao mà 1em = 15px ?

Mình xin giải thích là vì do lúc này chính nó(class em) và  phần tử cha chứa nó là thẻ div có class box mình chưa set thuộc tính font-size nên nó sẽ phụ thuộc phần tử lớn hơn ở ngoài đó là thẻ <body> nhưng thẻ <body> cũng chưa set thuộc tính font-size nên nó cứ thế lấy ra ngoài cùng cho tới thẻ <html>. Nên ở trên 1em = 1rem = 15px là theo thẻ <html> đấy.

Tuy nhiên bây giờ mình sẽ set cái thuộc tính font-size của thẻ div có class box là 20px thì chắn chắn sẽ có thay đổi. Các bạn nhìn dưới đây nha.

Ô màu đỏ có đơn vị em sẽ to hơn ban đầu vì như mình đã nói ở trên là đơn vị em phụ thuộc vào giá trị thuộc tính font-size của chính nó hoặc phần tử cha trực tiếp chứa nó. Cho nên lúc này ô màu đỏ sẽ có kích thước là 10em x 20px = 200px.

Còn ô màu xanh(rem) do phụ thuộc vào thẻ <html> nên khi mình thay đổi giá trị font-size của thẻ <html> sang 25px thì ô màu xanh cũng sẽ thay đổi kích thước. Và lúc này giá trị của nó sẽ là 10rem x 25px = 250px. Nhìn vào demo bạn sẽ thấy nó to hơn ban đầu và to hơn ô màu đỏ luôn.

# Lời kết

Có 1 chi tiết nhỏ mình quên nói đó là nếu mình không set giá trị của thuộc tính font-size cho thẻ <html> thì font-size mặc định của thẻ <html> là 16px nha.

Hi vọng với giải thích và ví dụ demo của mình sẽ giúp các bạn dễ dàng hiểu hơn về 2 đơn vị em và rem này. Ở bài sau mình sẽ chia sẻ về cách sử dụng 2 đơn vị này vào dự án nhé. Nếu các bạn có ý kiến gì hay hoặc góp ý thì bình luận để giúp mình cải thiện hơn nha. Cám ơn các bạn đã đọc và chúc các bạn một ngày làm việc tốt lành.

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

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

Xem thêm các việc làm Developer hấp dẫn tại TopDev

HTTP status code là gì? Danh sách đầy đủ HTTP status code

http status code

Dù có là 1 lập trình viên web hay không, chắc hẳn bạn cũng đã bắt gặp HTTP status code (mã trạng thái HTTP) ít nhất 1 hay nhiều lần rồi đúng không nào?

200, 404, 500… đều là những HTTP status code phổ biến. Thậm chí các truyện vui hay ảnh chế meme về 404 cũng khá nổi tiếng và đầy rẫy trên mạng Internet mà hầu hết bất kỳ ai cũng có thể hiểu được.

HTTP status code là gì - error 404

Vậy thì có bao giờ bạn thắc mắc HTTP status code là gì và ý nghĩa các con số của chúng hay chưa? Hôm nay chúng ta sẽ nói tổng quát 1 chút về HTTP status code và ý nghĩa nằm ẩn sau các con số đó nhé!

HTTP Status Code – Mã trạng thái HTTP là gì?

Khi được nhận và phiên dịch 1 yêu cầu HTTP từ phía client, HTTP status code sẽ được máy chủ cung cấp để đáp ứng yêu cầu đó của họ. Nó bao gồm code từ IETF Request for Comments (RFC), các thông số kỹ thuật khác và 1 số code bổ sung được sử dụng trong 1 số ứng dụng phổ biến của giao thức HTTP.

Chữ số đầu tiên của HTTP status code chỉ định 1 trong 5 loại phản hồi quy chuẩn. Các cụm tin nhắn được hiển thị chỉ mang tính tượng trưng, nhưng cũng có thể cung cấp bất kỳ thông tin bổ sung nào để chúng ta có thể đọc được. Trừ khi có những chỉ định khác, HTTP status code được xem như 1 phần của quy chuẩn HTTP/1.1 (RFC 7231).

Cơ Quan Cấp Số Được Ấn Định Trên Internet (tức IANA hay The Internet Assigned Numbers Authority) chính là nơi duy trì sổ đăng ký chính thức của các HTTP status code.

>>> Xem thêm: HttpOnly Flag và Secure Flag là gì?

Hạng mục các HTTP status code

Tất cả các HTTP status code phản hồi được chia ra thành 5 hạng mục riêng biệt và là các số nguyên có 3 chữ số. Chữ số đầu được dùng để xác định loại phản hồi, trong khi 2 chữ số cuối thì không có bất kỳ vai trò phân loại nào. HTTP status code sẽ cho ta biết liệu 1 yêu cầu HTTP cụ thể đã được hoàn thành thành công hay chưa.

Các ứng dụng hiểu HTTP status code không cần phải biết hết tất cả code, tức là dù code không xác định cũng có cụm từ để chỉ lý do không xác định. Cụm từ này không cho phía client nhiều thông tin nhưng các ứng dụng HTTP đó phải hiểu được nó thuộc 1 trong 5  hạng mục riêng biệt. 5 hạng mục đó bao gồm:

1xx (100 – 199): Information responses / Phản hồi thông tin – Yêu cầu đã được chấp nhận và quá trình xử lý yêu cầu của bạn đang được tiếp tục.

2xx (200 – 299): Successful responses / Phản hồi thành công – Yêu cầu của bạn đã được máy chủ tiếp nhận, hiểu và xử lý thành công.

3xx (300 – 399): Redirects / Điều hướng – Phía client cần thực hiện hành động bổ sung để hoàn tất yêu cầu.

4xx (400 – 499): Client errors / Lỗi phía client – Yêu cầu không thể hoàn tất hoặc yêu cầu chứa cú pháp không chính xác. 4xx sẽ hiện ra khi có lỗi từ phía client do không đưa ra yêu cầu hợp lệ.

5xx (500 – 599): Server errors / Lỗi phía máy chủ – Máy chủ không thể hoàn thành yêu cầu được cho là hợp lệ. Khi 5xx xảy ra, bạn chỉ có thể đợi để bên hệ thống máy chủ xử lý xong.

Danh sách đầy đủ các HTTP status code (code + cụm từ chỉ lý do):

1. Information responses / Phản hồi thông tin:

100 Continue: Phản hồi tạm thời này cho biết rằng mọi thứ tới hiện tại vẫn ổn và phía client nên tiếp tục yêu cầu hay bỏ qua phản hồi nếu yêu cầu đã hoàn tất.

101 Switching Protocol: Code này được gửi để phản hồi header yêu cầu Upgrade từ phía client và cho biết giao thức máy chủ đang chuyển sang.

102 Processing (WebDAV): Code này cho biết rằng máy chủ đã nhận và đang xử lý yêu cầu, nhưng phản hồi vẫn chưa có hiệu lực.

103 Early Hints: Được sử dụng để trả về một số tiêu đề phản hồi trước message HTTP cuối cùng.

2. Successful responses / Phản hồi thành công:

200 OK: Yêu cầu đã thành công. Ý nghĩa của thành công còn phụ thuộc vào phương thức HTTP là gì:

GET: Tài nguyên đã được tìm nạp và được truyền trong nội dung thông điệp.
HEAD: Các header thực thể nằm trong nội dung thông điệp.
PUT hoặc POST: Tài nguyên mô tả kết quả của hành động được truyền trong nội dung thông điệp.
TRACE: Nội dung thông điệp chứa thông báo yêu cầu khi máy chủ nhận được.

201 Created: Yêu cầu đã thành công và kết quả là một tài nguyên mới đã được tạo. Đây thường là phản hồi được gửi sau các yêu cầu POST hoặc một số yêu cầu PUT.

202 Accepted: Yêu cầu đã được nhận nhưng chưa được thực hiện. Yêu cầu này là non-committal, vì không có cách nào trong HTTP để gửi sau đó một phản hồi không đồng bộ cho biết kết quả của yêu cầu. Nó dành cho các trường hợp trong đó 1 quá trình / máy chủ khác xử lý yêu cầu hoặc để xử lý hàng loạt.

203 Non-Authoritative Information: Code phản hồi này có nghĩa là siêu thông tin được trả về không hoàn toàn giống với thông tin có sẵn từ máy chủ gốc, nhưng được thu thập từ phần copy local hay của bên phía thứ 3. Code này chủ yếu được sử dụng để phản chiếu hoặc sao lưu tài nguyên khác. Ngoại trừ trường hợp cụ thể đó, thông thường phản hồi “200 OK” được ưu tiên cho trạng thái này.

204 No Content: Không có nội dung để gửi cho yêu cầu này, nhưng các header có thể hữu dụng. User-agent có thể cập nhật các header đã lưu trong bộ nhớ cache cho tài nguyên này bằng các header mới.

205 Reset Content: Cho user-agent biết để reset document đã gửi yêu cầu này.

206 Partial Content: Code phản hồi này được dùng khi Range header được gửi từ client để yêu cầu chỉ 1 phần của nguồn tài nguyên.

207 Multi-Status (WebDAV): Truyền tải thông tin về nhiều nguồn tài nguyên, đối với các trường hợp mà nhiều status code có thể đều thích hợp.

208 Already Reported (WebDAV): Được sử dụng trong 1 phần tử phản hồi <dav:propstat> để tránh liệt kê nhiều lần các thành viên nội tại của nhiều liên kết vào cùng 1 tập hợp.

226 IM Used (HTTP Delta encoding): Máy chủ đã hoàn thành yêu cầu GET cho nguồn tài nguyên và phản hồi là sự trình bày kết quả của 1 hoặc nhiều thao tác instance được áp dụng cho instance hiện tại.

Xem ngay những tin đăng tuyển lập trình viên HTML mới nhất trên TopDev

3. Redirects / Điều hướng:

300 Multiple Choice: Yêu cầu có thể có nhiều hơn 1 phản hồi khả dụng. User-agent hay user nên chọn 1 trong số đó. (Không có cách chuẩn hóa nào để chọn 1 trong các phản hồi, nhưng HTML liên kết đến các khả năng được khuyến nghị để user có thể chọn.)

301 Moved Permanently: URL của tài nguyên được yêu cầu đã được thay đổi vĩnh viễn. URL mới được đưa ra trong phần phản hồi.

302 Found: Code phản hồi này có nghĩa là URI của tài nguyên được yêu cầu đã được thay đổi tạm thời. Những thay đổi khác trong URI có thể được thực hiện trong tương lai. Do đó, chính URI này sẽ được client sử dụng trong các yêu cầu trong tương lai.

303 See Other: Máy chủ gửi phản hồi này để điều hướng client lấy nguồn tài nguyên tại 1 URI khác với 1 yêu cầu GET.

304 Not Modified: Code này được sử dụng cho mục đích caching. Nó cho client biết rằng phản hồi chưa được điều chỉnh, nên client có thể tiếp tục sử dụng cùng phiên bản phản hồi trong bộ nhớ cache.

305 Use Proxy: Được xác định trong phiên bản trước của HTTP specification để chỉ ra rằng phản hồi được yêu cầu phải được truy cập bằng proxy. Nó được yêu cầu do quan ngại về phần bảo mật liên quan đến cấu hình trong băng tần của proxy.

306 unused: Mã phản hồi này không còn được sử dụng nữa, nó được bảo lưu và chỉ được sử dụng trong phiên bản trước của HTTP/1.1 specification.

307 Temporary Redirect: Máy chủ gửi phản hồi này để điều hướng client tới lấy tài nguyên được yêu cầu tại 1 URI khác với cùng 1 phương thức đã được sử dụng trong yêu cầu trước đó. Code này có cùng ý nghĩa như code phản hồi HTTP 302 Found, ngoại trừ việc user-agent không được thay đổi phương thức HTTP sử dụng: nếu POST được dùng trong yêu cầu đầu tiên, POST phải được sử dụng trong yêu cầu thứ hai.

308 Permanent Redirect: Điều này có nghĩa là tài nguyên hiện được đặt cố định tại 1 URI khác, được chỉ định bởi header Location: HTTP Response. Code này có cùng ý nghĩa như code phản hồi HTTP 301 Moved Permanently, ngoại trừ việc user-agent không được thay đổi phương thức HTTP sử dụng: nếu POST được dùng trong yêu cầu đầu tiên, POST phải được sử dụng trong yêu cầu thứ hai.

4. Client errors / Lỗi phía client:

400 Bad Request: Máy chủ không thể hiểu yêu cầu do cú pháp không hợp lệ.

401 Unauthorized: Cho dù quy chuẩn HTTP chỉ định “unauthorized” (không có thẩm quyền), nhưng nó có nghĩa phản hồi này là “unauthenticated” (chưa được xác thực). Có nghĩa là, client phải các tự xác thực chính mình để nhận được phản hồi đã yêu cầu.

402 Payment Required: Code phản hồi này được dành cho những lần sử dụng trong tương lai. Mục đích ban đầu của việc tạo mã này là sử dụng nó cho các hệ thống thanh toán kỹ thuật số, tuy nhiên status code này rất hiếm khi được sử dụng và không tồn tại quy ước tiêu chuẩn nào.

403 Forbidden: Client không có quyền truy cập vào phần nội dung, nghĩa là nó không được phép, vì vậy máy chủ từ chối cung cấp tài nguyên được yêu cầu. Không giống như 401, danh tính của client đã được máy chủ nhận biết.

404 Not Found:
HTTP status code - error 404

405 Method Not Allowed: Phương thức yêu cầu được máy chủ nhận biết nhưng đã bị vô hiệu hóa và không thể sử dụng được. Ví dụ: 1 API có thể cấm XÓA 1 nguồn tài nguyên. 2 phương thức bắt buộc, GET và HEAD, không bao giờ được vô hiệu hóa và không được trả về code lỗi này.

406 Not Acceptable: Phản hồi này được gửi khi máy chủ web, sau khi thực hiện server-driven content negotiation, không tìm thấy bất kỳ nội dung nào phù hợp với các tiêu chí do user-agent đưa ra.

407 Proxy Authentication Required: Code này tương tự như 401 nhưng việc xác thực là cần thiết để được thực hiện bởi proxy.

408 Request Timeout: Phản hồi này được gửi trên 1 kết nối idle bởi 1 số máy chủ, ngay cả khi không có bất kỳ yêu cầu nào trước đó của client. Có nghĩa là máy chủ muốn tắt kết nối không sử dụng này. Phản hồi này được sử dụng nhiều hơn vì 1 số trình duyệt như Chrome, Firefox 27+ hoặc IE9, sử dụng cơ chế  tiền kết nối HTTP để tăng tốc độ lướt web. Cũng lưu ý rằng 1 số máy chủ chỉ tắt kết nối luôn mà không hề gửi thông báo này.

409 Conflict: Phản hồi này được gửi khi 1 yêu cầu xung đột với trạng thái hiện tại của máy chủ.

410 Gone: Phản hồi này được gửi khi nội dung được yêu cầu đã bị xóa vĩnh viễn khỏi máy chủ, không có địa chỉ chuyển tiếp. Client phải xóa bộ nhớ cache và liên kết của mình tới nguồn tài nguyên. HTTP spectication dự định status code này được sử dụng cho “các dịch vụ khuyến mại, có thời hạn”. Các API không nên bắt buộc phải chỉ ra các tài nguyên đã bị xóa bằng status code này.

411 Length Required: Máy chủ đã từ chối yêu cầu vì trường header Content-Lenghth không được xác định và máy chủ thì yêu cầu chuyện đó.

412 Precondition Failed: Client đã chỉ ra các điều kiện tiên quyết trong các header của nó mà máy chủ không đáp ứng được.

413 Payload Too Large: Thực thể yêu cầu lớn hơn giới hạn do máy chủ xác định, máy chủ có thể đóng kết nối hoặc trả về trường header Retry-After.

414 URI Too Long: URI được yêu cầu bởi client dài hơn mức máy chủ muốn thông dịch.

415 Unsupported Media Type: Định dạng phương tiện của dữ liệu được yêu cầu không được máy chủ hỗ trợ, do đó máy chủ đang từ chối yêu cầu.

416 Range Not Satisfiable: Client yêu cầu một phần của tập tin nhưng máy chủ không thể cung cấp nó. Trước đây được gọi là “Requested Range Not Satisfiable”.

417 Expectation Failed: Máy chủ không thể đáp ứng các yêu cầu của trường Expect trong header.

5. Server errors / Lỗi phía máy chủ:

500 Internal Server Error: Một thông báo chung, được đưa ra khi máy chủ gặp phải một trường hợp bất ngờ, message cụ thể không phù hợp.

501 Not Implemented: Máy chủ không công nhận các phương thức yêu cầu hoặc không có khả năng xử lý nó.

502 Bad Gateway: Máy chủ đã hoạt động như một gateway hoặc proxy và nhận được một phản hồi không hợp lệ từ máy chủ nguồn.

503 Service Unavailable: Máy chủ hiện tại không có sẵn (hiện đang quá tải hoặc bị down để bảo trì). Đây chỉ là trạng thái tạm thời.

504 Gateway Timeout: Máy chủ đã hoạt động như một gateway hoặc proxy và không nhận được một phản hồi từ máy chủ nguồn.

505 HTTP Version Not Supported: Máy chủ không hỗ trợ phiên bản “giao thức HTTP”.

Danh sách được tổng hợp và tham khảo từ WikipediaMozilla.

Truy cập ngay các công việc IT đãi ngộ tốt trên TopDev

Vì sao IT Fresher không thể bỏ lỡ Vòng Loại cuối cùng của TopDev Challenge?

TopDev Challenge lần đầu tiên khởi động vào tháng 10/2020 kết hợp cùng nền tảng Hackerrank hứa hẹn một sân chơi chuyên nghiệp, công bằng, trực quan không cảm tính hay thiên vị dành riêng cho lập trình viên sẵn sàng đương đầu thử thách!

Nếu đây từng là nơi “luyện code” nay đã trở thành một đấu trường cạnh tranh năng lực cùng những món quà hấp dẫn “dân công nghệ” không tài nào bỏ qua!

Hiện tại cuộc thi đã đi đến được Round 2 – Vòng Loại cuối cùng của TopDev Challenge 2020 trước khi bước vào Final Round và tìm ra người thắng chung cuộc! 

HackerRank là một nền tảng hiện đang được nhắc đến rất nhiều trong cộng đồng lập trình viên. Nếu bạn đã từng nghe thoáng qua cái tên này hoặc nếu bạn đã biết đến HackerRank nhưng vẫn chưa có “đủ động lực” để thử sức với một nền tảng mà sẽ giúp năng cao kỹ năng lập trình của mình thì hãy cùng TopDev tìm hiểu 4 lý do vì sao bạn nên tạo một tài khoản HackerRank ngay bây giờ nhé!


HackerRank là nơi bạn có thể học và rèn luyện kỹ năng lập trình, đặc biệt về thuật toán, Machine learning & AI, với độ khó từ mức cơ bản cho đến cực kỳ “hack não”.

Trên HackerRank, người tham gia được yêu cầu đưa ra lời giải cho các challenge (những bài toán/câu đố do HackerRank cung cấp). Kết quả và tốc độ giải đề của bạn sẽ những yếu tố để đánh giá và xếp hạng các lập trình viên tham gia trên toàn thế giới!

Hiện tại nhiều công ty công nghệ trên thế giới đang sử dụng HackerRank như một công cụ để đánh giá ứng viên trong quy trình tuyển dụng IT. Riêng Việt Nam cũng sẽ không ngoại lệ, làn sóng sử dụng HackerRank như một bài test ứng viên IT sẽ trở nên phổ biến trong thời gian tới!

Một nơi để bạn khẳng định bản thân và giành lấy những phần quà hấp dẫn thông qua các cuộc thi! Nếu bạn là người “mới vào nghề” (fresher hoặc sinh viên CNTT), việc luyện tập & tham gia một cuộc thi trên HackerRank sẽ là một cơ hội giúp bạn khẳng định bản thân trước nhà tuyển dụng và trong cộng đồng lập trình, đồng thời rinh về những phần quà giá trị!

  HackerRank là gì? Lời khuyên khi tham gia HackerRank

  Ra mắt Nền tảng kết hợp tuyển dụng và đánh giá ứng viên IT chuẩn quốc tế đầu tiên tại Việt Nam TopDev x HackerRank

Không những thế, ciệc lộ diện danh tính các ‘Problem Setter’ có giúp bạn đoán được phần nào chủ đề bài thi:

TopDev Challenge là một “sân chơi chuẩn quốc tế” dành riêng cho IT freshers Việt Nam. Cuộc thi vừa là một nơi “luyện code”, đồng thời cũng là nơi “đọ code” giữa các fresher để bạn có thể khẳng định bản thân trước nhà tuyển dụng nói riêng và trong cộng đồng lập trình viên Việt Nam nói chung. Người chiến thắng còn có cơ hội nhận được những phần thưởng lên đến hàng chục triệu đồng, ngại gì mà không thử sức?!

Tìm hiểu & đăng ký tham gia cuộc thi ngay nào coders ơi!     

Xây dựng REST API cơ bản trong Golang

Xây dựng REST API cơ bản trong Golang

Bài viết được sự cho phép của tác giả Võ Xuân Phong

Để tiếp cận với Golang một cách nhanh chóng hơn, chúng ta sẽ xây dựng một REST API cơ bản với Golang nhé.

Cấu trúc project

Chúng ta hãy tạo cấu trúc thư mục như hình bên dưới, project này có tên GolangRestApi các bạn có thể clone về với đường link sau: Github

  Chiến trường sinh tử phiên bản lập trình : Python vs Ruby vs Golang
  Channel trong Golang là gì? So sánh Callback function và mutex lock với channel

Sau khi clone về các bạn nhớ đổi tên project thành GolangRestApi và vào GOPATH rồi copy vào thư mục src, cách cài đặt và setup dự án Golang các bạn có thể tham khảo chi tiết tại bài viết này của mình:

https://anhlamweb.com/bai-viet-64/hoc-golang-tu-con-so-0-phan-1-cai-dat-golang-tren-linux-va-windows.html

Xây dựng REST API cơ bản trong Golang

Code Rest Api Golang

entities/user.go

Khai báo cấu trúc của một thực thể User. User sẽ có hàm ToString để xuất thông tin chi tiết của User đó ra.

package entities

import (
"fmt"
)

type User struct {
Id string `json:"id"`
Name string `json:"name"`
Password string `json:"password"`
}

func (user User) ToString() string {
return fmt.Sprintf("id: %s\nName: %s\nPassword: %s\n", user.Id, user.Name, user.Password)
}

models/userModel.go

Định nghĩa các hàm cơ bản như CreateUser, UpdateUser, FindUser, DeleteUser và GetAllUser. listUser dùng để chưa thông tin của các User, thay vì để khai báo listUser như vậy chúng ta có thể connect tới  database và thực hiện các thao tác như trên, nhưng để dễ hiểu và rõ ràng hơn thì ở bài viết này chúng ta sẽ thực hiện theo cách đơn giản này trước.

package models

import (
"GolangRestApi/entities"
"errors"
)

var (
listUser = make([]*entities.User, 0)
)

func CreateUser(user *entities.User) bool {
if user.Id != "" && user.Name != "" && user.Password != "" {
if userF, _ := FindUser(user.Id); userF == nil {
listUser = append(listUser, user)
return true
}
}
return false
}

func UpdateUser(eUser *entities.User) bool {
for index, user := range listUser {
if user.Id == eUser.Id {
listUser[index] = eUser
return true
}
}
return false
}

func FindUser(id string) (*entities.User, error) {
for _, user := range listUser {
if user.Id == id {
return user, nil
}
}
return nil, errors.New("User does not exist")
}

func DeleteUser(id string) bool {
for index, user := range listUser {
if user.Id == id {
copy(listUser[index:], listUser[index+1:])
listUser[len(listUser)-1] = &entities.User{}
listUser = listUser[:len(listUser)-1]
return true
}
}
return false
}

func GetAllUser() []*entities.User {
return listUser
}

apis/userapi/userApi.go

Ở file này là các hàm xử lý các http request và chịu trách nhiệm trả về kết quả cho người dùng bằng http response.

package userapi

import (
"GolangRestApi/entities"
"GolangRestApi/models"
"encoding/json"
"net/http"
)

func FindUser(response http.ResponseWriter, request *http.Request) {
ids, ok := request.URL.Query()["id"]
if !ok || len(ids) < 1 {
responseWithError(response, http.StatusBadRequest, "Url Param id is missing")
return
}
user, err := models.FindUser(ids[0])
if err != nil {
responseWithError(response, http.StatusBadRequest, err.Error())
return
}
responseWithJSON(response, http.StatusOK, user)
}

func GetAll(response http.ResponseWriter, request *http.Request) {
users := models.GetAllUser()
responseWithJSON(response, http.StatusOK, users)
}

func CreateUser(response http.ResponseWriter, request *http.Request) {
var user entities.User
err := json.NewDecoder(request.Body).Decode(&user)
if err != nil {
responseWithError(response, http.StatusBadRequest, err.Error())
} else {
result := models.CreateUser(&user)
if !result {
responseWithError(response, http.StatusBadRequest, "Could not create user")
return
}
responseWithJSON(response, http.StatusOK, user)
}
}

func UpdateUser(response http.ResponseWriter, request *http.Request) {
var user entities.User
err := json.NewDecoder(request.Body).Decode(&user)
if err != nil {
responseWithError(response, http.StatusBadRequest, err.Error())
} else {
result := models.UpdateUser(&user)
if !result {
responseWithError(response, http.StatusBadRequest, "Could not update user")
return
}
responseWithJSON(response, http.StatusOK, "Update user successfully")
}
}

func Delete(response http.ResponseWriter, request *http.Request) {
ids, ok := request.URL.Query()["id"]
if !ok || len(ids) < 1 {
responseWithError(response, http.StatusBadRequest, "Url Param id is missing")
return
}
result := models.DeleteUser(ids[0])
if !result {
responseWithError(response, http.StatusBadRequest, "Could not delete user")
return
}
responseWithJSON(response, http.StatusOK, "Delete user successfully")
}

func responseWithError(response http.ResponseWriter, statusCode int, msg string) {
responseWithJSON(response, statusCode, map[string]string{
"error": msg,
})
}

func responseWithJSON(response http.ResponseWriter, statusCode int, data interface{}) {
result, _ := json.Marshal(data)
response.Header().Set("Content-Type", "application/json")
response.WriteHeader(statusCode)
response.Write(result)
}

Main.go

Để xây dựng một REST Api Server thì ở đây chúng ta sử dụng mux và tạo một router để nó thực hiện việc handle request như sau.

Server sẽ lắng nghe ở port 5000.

package main

import (
"GolangRestApi/apis/userapi"
"net/http"

"github.com/gorilla/mux"
)

func main() {
router := mux.NewRouter()

router.HandleFunc("/api/v1/user/find", userapi.FindUser).Methods("GET")
router.HandleFunc("/api/v1/user/getall", userapi.GetAll).Methods("GET")
router.HandleFunc("/api/v1/user/create", userapi.CreateUser).Methods("POST")
router.HandleFunc("/api/v1/user/update", userapi.UpdateUser).Methods("PUT")
router.HandleFunc("/api/v1/user/delete", userapi.Delete).Methods("DELETE")

err := http.ListenAndServe(":5000", router)
if err != nil {
panic(err)
}
}

Chạy chương trình bằng lệnh

go run main.go

Kiểm Tra Kết Quả

Để kiểm tra kết quả chúng ta sẽ sử dụng Postman nhé, bạn có thể vào thư mục assets và import file GolangRestApi.postman_collection.json vào để test cho nhanh.

Tạo mới User.

Xây dựng REST API cơ bản trong Golang

Lấy danh sách các User

Xây dựng REST API cơ bản trong Golang

Tìm kiếm một User

Xây dựng REST API cơ bản trong Golang

Cập nhật User

Xây dựng REST API cơ bản trong Golang

Sau khi update user chúng ta hãy kiểm tra lại thông tin vừa được update.

Xây dựng REST API cơ bản trong Golang

Xóa một User

Xây dựng REST API cơ bản trong Golang

Sau khi delete user chúng ta hãy kiểm tra lại danh sách, như hình bên dưới sau khi delete user đi thì danh sách là rỗng.

Xây dựng REST API cơ bản trong Golang

Tổng kết:

Chúng ta đã tập làm quen với Golang và Rest Api trong Golang, ở bài tiếp theo chúng ta sẽ tìm hiểu tiếp về xác thực Rest Api sử dụng Json Web Token nhé.

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

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

Xem thêm các việc làm Developer hấp dẫn tại TopDev

Viết chương trình Xoá các File trùng lặp bằng Python

Viết chương trình Xoá các File trùng lặp bằng Python

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

Bạn quá lo âu vì có nhiều file bị trùng lặp trên ổ đĩa khiến chiếm dung lượng bộ nhớ? Nhưng khi tìm kiếm và xoá chúng theo cách thủ công lại quá tẻ nhạt. Tiếp tục Seri python, hôm nay, mình sẽ tiếp tục hướng dẫn các bạn cách xoá các File trùng lặp và giải phóng dung lượng ổ đĩa bằng python.

Giải pháp

Thay vì tìm kiếm khắp ổ đĩa để xoá các File trùng lặp, bạn có thể tự động hóa quy trình này bằng cách sử dụng script, bằng cách viết một chương trình để tìm kiếm đệ quy trong ổ đĩa và loại bỏ tất cả các File trùng lặp được tìm thấy.

Nguyên lý hoạt động

Nếu chúng ta đọc toàn bộ File và sau đó so sánh nó với các File còn lại bằng đệ quy thì sẽ mất rất nhiều thời gian, vậy chúng ta phải làm thế nào mới được?

Câu trả lời là hashing (băm), với hashing chúng ta có thể tạo ra một chuỗi các chữ cái và số nhất định đóng vai trò là danh tính của một File nhất định và nếu chúng ta tìm thấy bất kỳ File nào khác có cùng danh tính, chúng ta sẽ xóa nó.

Viết chương trình Xoá các File trùng lặp bằng Python

Có rất nhiều thuật toán hashing khác nhau như:

  • md5
  • sha1
  • sha224, sha256, sha384 và sha512
  Tại sao phải chọn giữa R hay Python trong khi bạn có thể chọn cả 2?

Code xoá các File trùng lặp bằng Python

Hashing trong Python khá đơn giản, chúng ta sẽ sử dụng thư viện hashlib được mặc định với thư viện chuẩn của Python.

Dưới đây là một ví dụ về cách chúng ta hashing nội dung bằng cách sử dụng hashlib, chúng ta sẽ băm một chuỗi trong Python bằng cách sử dụng thuật toán băm md5.

Ví dụ

>>> import hashlib
>>> example_text = "Duplython is amazing".encode('utf-8')
>>> hashlib.md5(example_text).hexdigest()
'73a14f46eadcc04f4e04bec8eb66f2ab'

Giải thích chút, bạn chỉ cần import hashlib và sau đó sử dụng phương thức md5 để tạo hash và cuối cùng sử dụng hexdigest để tạo chuỗi hash.

Ví dụ trên đã cho chúng ta thấy cách băm một chuỗi nhưng khi xem xét mối việc này với dự án sắp thực hiện, thì chúng ta phải quan tâm đến các File hơn là chuỗi đúng không? Một câu hỏi khác đã được đặt ra.

Chúng ta Hash file như thế nào?

Các File hash (băm) tương tự như chuỗi băm nhưng lại có một sự khác biệt nhỏ, trong quá trình băm File, trước tiên chúng ta cần mở File ở dạng nhị phân và sau đó băm giá trị nhị phân của File.

Băm file

Giả sử bạn có tài liệu văn bản đơn giản trên thư mục dự án của mình với tên learn.txt. Đây là cách mà chúng ta sẽ thực hiện.

>>> import hashlib
>>> file = open('learn.txt', 'rb').read()
>>> hashlib.md5(file).hexdigest()
'0534cf6d5816c4f1ace48fff75f616c9'

Hàm này sẽ trả ra các giá trị băm giống nhau nếu các file đó có nội dung giống nhau khi đó dễ dàng tìm và Xoá các File trùng lặp bằng Python. Lưu ý: khác tên nhưng giống nội dung thì vẫn trả ra giá trị băm giống nhau nhé.

Thách thức nảy sinh khi chúng ta cố gắng đọc một File khá lớn sẽ mất một lúc để tải nó. Do đó, thay vì đợi toàn bộ File vào bộ nhớ, chúng ta có thể tiếp tục tính toán hàm băm khi đọc File.

Việc tính toán hàm băm trong khi đọc File yêu cầu chúng ta đọc File theo các khối có kích thước nhất định và liên tục cập nhật các hàm băm khi chúng ta tiếp tục đọc File cho đến khi băm hoàn chỉnh toàn bộ File. Nói đơn giản là chia file làm nhiều phần, sau đó đọc từng phần, từng phần đó sẽ được hash, sau khi hash sẽ được update vào biến khác.

Làm theo cách này có thể giúp chúng ta tiết kiệm rất nhiều thời gian chờ đợi mà chúng ta có thể sử dụng để đợi toàn bộ File sẵn sàng.

Ví dụ

>>> import hashlib
>>> block_size = 1024
>>> hash = hashlib.md5()
>>> with open('learn.txt', 'rb') as file:
... block = file.read(block_size)
... while len(block)>0:
... hash.update(block)
... block = file.read(block_size)
... print(hash)
...
0534cf6d5816c4f1ace48fff75f616c9

Nhưng băm chỉ là một bước chúng ta cần để thực sự loại bỏ các bản sao, do đó chúng ta sẽ sử dụng module OS để xóa các bản sao.

Chúng ta sẽ sử dụng hàm remove() trong module OS để xoá các File trùng lặp.

Sử dụng module OS để xoá file learn.txt

Ví dụ:

>>> import os
>>> os.listdir()
['Desktop-File-cleaner', '.git', 'learn.txt', 'app.py', 'README.md']
>>> os.remove('learn.txt')
>>> os.listdir()
['Desktop-File-cleaner', '.git', 'app.py', 'README.md']

Sau khi đã xoá được file với hàm remove(), chúng ta sẽ bắt đầu xây dựng ứng dụng.

  Top 15 câu hỏi phỏng vấn Python lý thuyết + thực hành

Cách tạo ứng dụng xoá các File trùng lặp

Những thư viện cần thiết:

import time
import os
from hashlib import sha256

Mình là một người rất thích lập trình hướng đối tượng nên trong bài viết này, mình sẽ xây dựng tool dưới dạng một class duy nhất, code bên dưới chỉ là khung sườn của chương trình.

import time
import os
from hashlib import sha256

class Duplython:
def __init__(self):
self.home_dir = os.getcwd(); self.File_hashes = []
self.Cleaned_dirs = []; self.Total_bytes_saved = 0
self.block_size = 65536; self.count_cleaned = 0

def welcome(self)->None:
print('******************************************************************')
print('**************** DUPLYTHON ****************************')
print('********************************************************************\n\n')
print('---------------- WELCOME ----------------------------')
time.sleep(3)
print('\nCleaning .................')

def main(self)->None:
self.welcome()

if __name__ == '__main__':
App = Duplython()
App.main()

Đó chỉ là giao diện của chương trình, khi bạn chạy nó sẽ chỉ in lời chào mừng ra màn hình.

$ python3 app.py
******************************************************************
**************** DUPLYTHON ****************************
********************************************************************

---------------- WELCOME ----------------------------
​
Cleaning .................

Bây giờ chúng ta sẽ tạo một hàm đơn giản dùng để băm một File với đường dẫn nhất định bằng cách sử dụng kiến ​​thức băm mà chúng ta đã học ở trên.

import time
import os
from hashlib import sha256

class Duplython:
def __init__(self):
self.home_dir = os.getcwd(); self.File_hashes = []
self.Cleaned_dirs = []; self.Total_bytes_saved = 0
self.block_size = 65536; self.count_cleaned = 0

def welcome(self)->None:
print('******************************************************************')
print('**************** DUPLYTHON ****************************')
print('********************************************************************\n\n')
print('---------------- WELCOME ----------------------------')
time.sleep(3)
print('\nCleaning .................')

def generate_hash(self, Filename:str)->str:
Filehash = sha256()
try:
with open(Filename, 'rb') as File:
fileblock = File.read(self.block_size)
while len(fileblock)>0:
Filehash.update(fileblock)
fileblock = File.read(self.block_size)
Filehash = Filehash.hexdigest()
return Filehash
except:
return False

def main(self)->None:
self.welcome()

if __name__ == '__main__':
App = Duplython()
App.main()

Triển khai logic cho chương trình

Sau khi tạo hàm băm File, chúng ta phải triển khai ở nơi sẽ so sánh các chuỗi băm đó và loại bỏ bất kỳ bản sao nào được tìm thấy.

Tôi sẽ tạo một hàm đơn giản được gọi là clean () như hình bên dưới.

import time
import os
from hashlib import sha256
​
class Duplython:
def __init__(self):
self.home_dir = os.getcwd(); self.File_hashes = []
self.Cleaned_dirs = []; self.Total_bytes_saved = 0
self.block_size = 65536; self.count_cleaned = 0
​
def welcome(self)->None:
print('******************************************************************')
print('**************** DUPLYTHON ****************************')
print('********************************************************************\n\n')
print('---------------- WELCOME ----------------------------')
time.sleep(3)
print('\nCleaning .................')

def generate_hash(self, Filename:str)->str:
Filehash = sha256()
try:
with open(Filename, 'rb') as File:
fileblock = File.read(self.block_size)
while len(fileblock)>0:
Filehash.update(fileblock)
fileblock = File.read(self.block_size)
Filehash = Filehash.hexdigest()
return Filehash
except:
return False
​
def clean(self)->None:
all_dirs = [path[0] for path in os.walk('.')]
for path in all_dirs:
os.chdir(path)
All_Files =[file for file in os.listdir() if os.path.isfile(file)]
for file in All_Files:
filehash = self.generate_hash(file)
if not filehash in self.File_hashes:
if filehash:
self.File_hashes.append(filehash)
#print(file)
else:
byte_saved = os.path.getsize(file); self.count_cleaned+=1
self.Total_bytes_saved+=byte_saved
os.remove(file); filename = file.split('/')[-1]
print(filename, '.. cleaned ')
os.chdir(self.home_dir)

def main(self)->None:
self.welcome();self.clean()
​
if __name__ == '__main__':
App = Duplython()
App.main()

Bây giờ chương trình của chúng ta đã gần hoàn tất, việc cuối cùng là phải hiển thị kết quả của quá trình dọn dẹp cho người dùng xem.

Xem thêm:  Javascript Hoa mai đào rơi trang trí Tết cho Website

Mình đã tạo ra hàm Cleaning_summary() chỉ để làm việc đó. In kết quả của quá trình dọn dẹp ra màn hình để hoàn thành chương trình.

import time
import os
import shutil
from hashlib import sha256

class Duplython:
def __init__(self):
self.home_dir = os.getcwd(); self.File_hashes = []
self.Cleaned_dirs = []; self.Total_bytes_saved = 0
self.block_size = 65536; self.count_cleaned = 0

def welcome(self)->None:
print('******************************************************************')
print('**************** DUPLYTHON ****************************')
print('********************************************************************\n\n')
print('---------------- WELCOME ----------------------------')
time.sleep(3)
print('\nCleaning .................')

def generate_hash(self, Filename:str)->str:
Filehash = sha256()
try:
with open(Filename, 'rb') as File:
fileblock = File.read(self.block_size)
while len(fileblock)>0:
Filehash.update(fileblock)
fileblock = File.read(self.block_size)
Filehash = Filehash.hexdigest()
return Filehash
except:
return False

def clean(self)->None:
all_dirs = [path[0] for path in os.walk('.')]
for path in all_dirs:
os.chdir(path)
All_Files =[file for file in os.listdir() if os.path.isfile(file)]
for file in All_Files:
filehash = self.generate_hash(file)
if not filehash in self.File_hashes:
if filehash:
self.File_hashes.append(filehash)
#print(file)
else:
byte_saved = os.path.getsize(file); self.count_cleaned+=1
self.Total_bytes_saved+=byte_saved
os.remove(file); filename = file.split('/')[-1]
print(filename, '.. cleaned ')
os.chdir(self.home_dir)

def cleaning_summary(self)->None:
mb_saved = self.Total_bytes_saved/1048576
mb_saved = round(mb_saved, 2)
print('\n\n--------------FINISHED CLEANING ------------')
print('File cleaned : ', self.count_cleaned)
print('Total Space saved : ', mb_saved, 'MB')
print('-----------------------------------------------')

def main(self)->None:
self.welcome();self.clean();self.cleaning_summary()

if __name__ == '__main__':
App = Duplython()
App.main()

Ứng dụng Xoá các File trùng lặp bằng Python của chúng ta đã hoàn tất, bây giờ để chạy ứng dụng, hãy chạy nó trong thư mục cụ thể mà bạn muốn dọn dẹp và nó sẽ đệ quy qua một thư mục nhất định để tìm tất cả các File và xóa File trùng lặp.

Kết quả

$ python3 app.py
******************************************************************
**************** DUPLYTHON ****************************
********************************************************************
​
​
---------------- WELCOME ----------------------------
​
Cleaning .................
0(copy).jpeg .. cleaned
0 (1)(copy).jpeg .. cleaned
0 (2)(copy).jpeg .. cleaned

​
--------------FINISHED CLEANING ------------
File cleaned : 3
Total Space saved : 0.38 MB

Sử dụng flat state trong Vue Store

Sử dụng flat state trong Vue Store

Bài viết được sự cho phép của tác giả Lưu Bình An

Đầu tiên chúng ta cần trả lời câu hỏi global state có phải là phương thuốc chữa bá bệnh cho các vấn đề liên quan tới state? Mình chỉ đưa dữ liệu vào Vuex store như là lựa chọn cuối cùng và có một lý do cụ thế để phải sử dụng. Điều thứ 2, luôn giữ global state ở dạng cây một cấp, nghĩa là chúng ta không lồng dữ liệu liệu vào nhau như bên dưới

  3 phút làm quen với Vue.js
  Autosaving cùng Vuex

Đọc thêm https://markus.oberlehner.net/blog/should-i-store-this-data-in-vuex/ để có khái niệm khi nào cần dữ liệu trong store và khi nào không.

Quan điểm về flat state (không lưu dữ liệu lồng nhau trong store) được lấy cảm hứng từ chú Matt Biilmann chia sẽ về quan điểm về Redux sau khi làm cái dashboard cho Netlify trong bài phỏng vấn Architecting the Netlify Dashboard with React and Redux

cap_1: {
    cap_2: {
        cap_3: {
        }
    }
}

Rất khó để sync dữ liệu ở dạng lồng ghép như vậy.

Ví dụ, có danh sách bài viết, mỗi bài viết được nhét thông tin tác giả bên trong, có nhiều bài viết có cùng một tác giả, rồi ngày đẹp trời tác giả này đổi tên, thì chúng ta phải đi sync lại toàn bộ tất cả bài viết của ổng.

const articles = [
  // bài viết này được load trước
  {
    author: {
      avatar: 'https://picsum.photos/id/1011/25',
      id: 1,
      name: 'Jane Doe',
    },
    id: 1,
    intro: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr.',
    title: 'Lorem Ipsum',
  },
  // tác giả đó ổng vô đổi avatar,
  // rồi chúng ta load thêm bài viết
  // avatar của ổng đã không còn như xưa
  {
    author: {
      avatar: 'https://picsum.photos/id/2000/25',
      id: 1,
      name: 'Jane Doe',
    },
    id: 2,
    intro: 'Stet clita kasd gubergren, no sea takimata sanctus est.',
    title: 'Dolor sit',
  },
];

Cách mà chúng ta nên lưu, tách riêng 2 thằng

const articles = {
  1: {
    author: 1,
    id: 1,
    intro: 'Lorem ipsum dolor sit amet, consetetur sadipscing elitr.',
    title: 'Lorem Ipsum',
  },
  2: {
    author: 1,
    id: 2,
    intro: 'Stet clita kasd gubergren, no sea takimata sanctus est.',
    title: 'Dolor sit',
  },
};

const authors = {
  1: {
    avatar: 'https://picsum.photos/id/2000/25',
    id: 1,
    name: 'Jane Doe',
  },
};

Những kiểu thực thể khác nhau, chúng ta tách ra thành các module riêng biệt, dùng khái niệm foreign key (khóa ngoại) như trong database

// src/store/modules/article.js
import Vue from 'vue';

import { normalizeRelations, resolveRelations } from '../helpers';
import articleService from '../../services/article';

const state = {
  byId: {},
  allIds: [],
};

const getters = {
  // trả về một article với giá trị id được truyền vào
  find: (state, _, __, rootGetters) => id => {
    // dùng ID để lấy thông tin tác giả
    return resolveRelations(state.byId[id], ['author'], rootGetters);
  },
  // trả về danh sách articles
  list: (state, getters) => {
    return state.allIds.map(id => getters.find(id));
  },
};

const actions = {
  load: async ({ commit }) => {
    const articles = await articleService.list();
    articles.forEach((item) => {
      commit('add', normalizeRelations(item, ['author']));
      // thêm hoặc update order
      commit('author/add', item.author, {
        root: true,
      });
    });
  },
};

const mutations = {
  add: (state, item) => {
    Vue.set(state.byId, item.id, item);
    if (state.allIds.includes(item.id)) return;
    state.allIds.push(item.id);
  },
};

export default {
  actions,
  getters,
  mutations,
  namespaced: true,
  state,
};
// src/store/helpers.js
export function normalizeRelations(data, fields) {
  return {
    ...data,
    ...fields.reduce((prev, field) => ({
      ...prev,
      [field]: Array.isArray(data[field])
        ? data[field].map(x => x.id)
        : data[field].id,
    }), {}),
  };
}

export function resolveRelations(data, fields, rootGetters) {
  return {
    ...data,
    ...fields.reduce((prev, field) => ({
      ...prev,
      [field]: Array.isArray(data[field])
        ? data[field].map(x => rootGetters[`${field}/find`](x))
        : rootGetters[`${field}/find`](data[field]),
    }), {}),
  };
}

Sử dụng

<template>
  <div id="app">
    <ArticleList :articles="articles"/>
  </div>
</template>

<script>
// src/App.vue
import { mapActions, mapGetters } from 'vuex';

import ArticleList from './components/ArticleList';

export default {
  name: 'App',
  components: {
    ArticleList,
  },
  computed: {
    ...mapGetters('article', { articles: 'list' }),
  },
  created() {
    this.loadArticles();
  },
  methods: {
    ...mapActions('article', { loadArticles: 'load' }),
  },
};
</script>

Trong component App.vue chúng ta lấy các getter và action trong article module, khi vừa khởi tạo component, gọi action loadArticle để lấy dữ liệu

<template>
  <ul class="ArticleList">
    <li
      v-for="article in articles"
      :key="article.id"
    >
      <h2>{{ article.title }}</h2>
      <p>{{ article.intro }}</p>
      <div class="ArticleList__author">
        <img class="ArticleList__avatar" :src="article.author.avatar" :alt="article.author.name">
        {{ article.author.name }}
      </div>
    </li>
  </ul>
</template>

<script>
export default {
  name: 'ArticleList',
  props: {
    articles: {
      required: true,
      type: Array,
    },
  },
};
</script>

Nhờ vào các hàm getter và resolveRelations(), chúng ta có thể dễ dàng truy cập author của từng article

📜 Make your Vuex State Flat: State Normalization with Vuex

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

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

Xem thêm các việc làm Developer hấp dẫn tại TopDev

Software Developer và 5 bài học kinh nghiệm quan trọng

5 bài học kinh nghiệm quan trọng được đúc kết bởi một Software Developer

Dịch từ bài viết của tác giả Stephen McLean

Với 4 năm làm việc ở vị trí Software Developer tôi đã rút ra được nhiều bài học lớn cho bản thân và hy vọng bài viết này sẽ giúp các dev học hỏi thêm những điều mình chưa biết.

  10 Công cụ Go-To Tech dành riêng cho các Software Developer
  Biến Git và GitHub trở thành công cụ đắc lực cho Software Engineer

Những bài học kinh nghiệm của Software Developer

1. Đừng cho rằng mọi thứ luôn hoạt động trơn tru

Ở job đầu tiên của mình sau khi ra trường, tôi được giao một task nhỏ trong chuỗi dự án dài hạn. Dự án này có sự tham gia của rất nhiều dev và phải chạy nước rút nhiều lần để hoàn thành. Nó có lượng codebase cực kỳ lớn, phức tạp và tích hợp với nhiều dịch vụ outsource.

Xem thêm Thị trường Outsourcing Vietnam 2019 – Thiên đường Outsourcing mới của thế giới

Công việc của tôi là fix một số unit tests không thể chạy liên tục, code của unit tests này tương đối cũ và được viết bởi một Senior Developer. Vì chúng hoạt động tốt trên UI và đã thông qua bài kiểm tra QA nên tôi nghĩ rằng sai sót có thể nằm ở kỹ năng kiểm thử của mình.

topdev

Tôi dành gần 3 ngày để fix những tests không có vấn đề gì như thế nên thời gian lâu hơn. Khi trình bày với sếp, anh ấy nói với tôi rằng đừng bao giờ cho rằng code của người khác thì luôn đúng. Lời khuyên này dường như không chỉ đúng với việc viết code:

  • Đừng nghĩ rằng khi bạn giao việc gì thì người thực hiện đều làm đúng theo như vậy mà thay vào đó, hãy có một thỏa thuận rõ ràng và theo dõi kỹ càng các task đã giao để đạt được kết quả tốt.
  • Đừng cho rằng đối phương đã hiểu những gì bạn nói kể cả khi họ nói đã hiểu và có thể làm được. Tôi rút ra bài học này sau khi là mentor của nhiều Junior Developer. Để chắc chắn bạn nên yêu cầu họ trình bày lại những gì bạn đã hướng dẫn theo cách họ hiểu.
  • Đừng nghĩ rằng đối phương luôn sai. Nhiều người quá tin tưởng vào code của mình và đổ lỗi cho người khác khi code không chạy được. Bạn sẽ được đánh giá cao hơn nếu biết nhìn nhận và test lại code của mình để đảm bảo sự chính xác hơn là chỉ chối lỗi.

Xem thêm Junior developer là gì? Những quy tắc bất biến dành cho Junior developer

2. Hãy suy nghĩ trước khi code

Sự thật là đa phần các dev đều thích automation, họ luôn tìm cách tự động hóa mọi thứ để cải thiện vấn đề. Tuy nhiên, đừng vội vàng viết code để làm điều đó, nhất là khi coding để sửa lỗi sai. Hãy nghiên cứu kỹ nguyên nhân vấn đề chứ đừng vội vàng tìm giải pháp. Trao đổi với nhiều người khác nhau không chỉ các dev để xem đây là lỗi kỹ thuật hay do quy trình, sau đấy hãy tìm giải pháp thực hiện. Vì nếu không hiểu được ngọn nguồn vấn đề, các dev và team của mình sẽ tiếp tục phạm phải nhiều sai lầm hơn khi làm việc mà thôi. 

Tham khảo tuyển dụng software engineer lương cao trên TopDev

3. Kết quả quan trọng hơn cách tạo ra kết quả

Sau 4 năm là Software Developer tôi nhận ra rằng, tools được sử dụng để xây dựng phần mềm là gì không quan trọng, miễn là nó có thể giúp tôi hoàn thành tốt nhiệm vụ là được. Khách hàng cũng chỉ quan tâm đến sản phẩm cuối cùng và hoạt động của nó có hiệu quả hay không, họ không để ý đến việc làm sao để nó hoạt động được như vậy.

topdev

4. Những vấn đề không do lỗi kỹ thuật mới là vấn đề khó giải quyết nhất

Khi ở giảng đường, mọi sai sót đều do kỹ thuật và bạn dễ dàng tìm được cách để đoạn code mình viết chạy được. Nhưng trong công việc thì không đơn giản như vậy. Bạn sẽ gặp rất nhiều chuyện phát sinh khi chạy một dự án: Làm sao để đảm bảo sự kết nối giữa các bên liên quan với nhau tốt nhất dù khác múi giờ làm việc, làm sao đảm bảo quy trình hoạt động và document được lưu trữ đầy đủ, giúp đỡ các dev mới trong team, giới thiệu cách hoạt động dự án cho khách hàng một cách dễ hiểu nhất,… Đó chỉ là một trong rất nhiều các vấn đề bạn phải giải quyết khi là Software Developer.

  Liệu Software Engineer có phải là nghề dễ ăn?
  20 trường hợp sử dụng lệnh Docker cho developer

5. Mọi vai trò trong team đều quan trọng như nhau

Một dự án sẽ không thể diễn ra suôn sẻ nếu không có sự kết hợp giữa các team liên quan và mỗi thành viên trong một team với nhau. Mỗi người sẽ đóng một vai trò nhất định từ BA, QA, quản lý dự án, quản lý các bên liên quan khác đến các dev. Code sẽ vô nghĩa nếu không có các stakeholder cùng nhau xây dựng dự án.

Kết luận

Hy vọng rằng những chia sẻ trong bài viết này có thể giúp bạn có thêm kinh nghiệm để hoạt động hiệu quả hơn với tư cách là một Software Developer.

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

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

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

QUnit — Những bước chân TDD đầu tiên trên JavaScript

QUnit — Những bước chân TDD đầu tiên trên JavaScript

Bài viết được sự cho phép của BBT Tạp chí Lập trình

TDD là gì?

TDD (Test Driven Development) là một phương thức làm việc, hay một quy trình viết mã hiện đại. Lập trình viên sẽ thực hiện thông qua các bước nhỏ (BabyStep) và tiến độ được đảm bảo liên tục bằng cách viết và chạy các bài test tự động (automated tests). Quá trình lập trình trong TDD cực kỳ chú trọng vào các bước liên tục sau:

  1. Viết 1 test case cho hàm mới. Đảm bảo rằng test sẽ fail.
  2. Chuyển qua viết code sơ khai nhất cho hàm đó để test có thể pass.
  3. Tối ưu hóa đoạn code của hàm vừa viết sao cho đảm bảo test vẫn pass và tối ưu nhất cho việc lập trình kế tiếp
  4. Lặp lại cho các hàm khác từ bước 1

Phát triển hướng kiểm thử TDD (Test-Driven Development) là một phương pháp phát triển phần mềm trong đó kết hợp phương pháp Phát triển kiểm thử trước (Test First Development) và điều chỉnh lại mã nguồn (Refactoring).

Mục tiêu quan trọng nhất của TDD là hãy nghĩ về kết qủa của bạn trước khi viết mã nguồn cho chức năng. Nhìn chung, mục tiêu của TDD là viết mã nguồn sáng sủa, rõ ràng và hạn chế lỗi, dễ dàng mở rộng.

Xem việc làm javascript đãi ngộ tốt trên TopDev

QUnit là gì?

QUnit là một framework mạnh, miễn phí và dễ sử dụng để triển khai Kiểm thử Đơn vị (Unit Testing) trong JavaScript. Framework này đã được dùng cho các dự án jQuery, jQuery UI và jQuery Mobile cũng như có thể dùng cho tất cả các mã nguồn JavaScript nói chung.

Cài đặt QUnit

QUnit là một thư viện độc lập, chỉ cần một tệp JavaScript (qunit.js) và một tệp CSS (qunit.css). Bạn có thể tải chúng xuống từ trang QUnit hoặc sao chép chúng từ kho lưu trữ QUnit GitHub, như sau:

 git clone git://github.com/jquery/qunit.git

Hoặc đơn giản hơn, chúng ta có thể nhúng CDN của QUnit vào trang HTML của chúng ta:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width">
    <title>QUnit Example</title>
    <link rel="stylesheet" href="https://code.jquery.com/qunit/qunit-2.10.0.css">
</head>
<body>
<div id="qunit"></div>
<div id="qunit-fixture"></div>
<script src="https://code.jquery.com/qunit/qunit-2.10.0.js"></script>
<script src="tests.js"></script>
</body>
</html>

Sau đó, chúng ta tạo 1 file js là “tests.js” và viết những dòng test case đầu tiên vào đó:

QUnit.test( "hello test", function( assert ) {
    assert.ok( 1 == "1", "Passed!" );
});

Cuối cùng, hãy chạy thử file HTML của bạn và xem kết quả nhé:

QUnit — Những bước chân TDD đầu tiên trên JavaScript

Yeah, bạn đã chạy thành công 1 test case đơn giản đầu tiên, bây giờ hãy thử nâng cấp 1 chút, viết test cho 1 hàm của bạn nhé. Bạn tạo file “app.js” chứa các hàm mà bạn muốn test, và tạo sẵn vào đó hàm sayHello() như sau:

 function sayHello(yourName) {    return yourName; }

Tiếp đó, Viết một test case trong file tests.js dành cho hàm sayHello()

Qunit.test( "test sayHello", function(assert) {
  let expected = "Hello World";
  let result =  sayHello("World");
  assert.ok(expected == result,"Passed!");
});

Chạy thử HTML của bạn sẽ có kết quả như sau:

QUnit — Những bước chân TDD đầu tiên trên JavaScript

Vậy là bạn đã thành công với bước đầu có được test case “fail” với QUnit, công việc của bạn là hoàn chỉnh hàm sayHello() để “pass” được cái test này.

 function sayHello(yourName) {    return "Hello " + yourName; }

Xong rồi chạy lại trang HTML của bạn, nếu hiển thị như này:

Xanh tức là bạn đã “pass” trường hợp đó rồi. Nếu báo đỏ thì bạn hãy kiểm tra lại hàm sayHello() xem có vấn đề gì không nhé. Sau khi pass rồi thì chúng ta viết tiếp những test case mới.

Đến đây tôi đã hoàn tất việc giới thiệu với các bạn về QUnit và một hướng dẫn nho nhỏ để bạn có thể bắt đầu làm Unit Test hay xa hơn nữa là TDD với JavaScript. Bạn có thể tìm hiểu sâu hơn về QUnit tại trang web http://qunitjs.com.

Chúc bạn thành công và có những mã nguồn JavaScript chất lượng!

Author: Dư Thanh Hoàng

Bài viết gốc được đăng tải tại Tạp chí Lập trình

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

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

Một số tool hữu ích dành cho Web Developer có thể bạn chưa biết (Phần 1)

tool cho web developer

Bài viết được sự cho phép của BQT Kinh nghiệm lập trình

Ngày nay lĩnh vực công nghệ phát triển một cách vượt bậc, bên cạnh đó sự trải nghiệm người dùng cũng được theo đó mà tăng lên đáng kể. Đằng sau những giao diện bắt mắt là những ý tưởng mới mẻ, tốn rất nhiều công sức của Developer. Dưới đây mình tổng hợp một số công cụ hữu ích cho một Frontend developer/Designer được chọn lọc qua nhiều nguồn khác nhau.

Font

Trong một layout website thường sẽ có những Icon giúp website đẹp và thân thiện hơn, ngoài ra còn có tác dụng điều hướng người dùng. Trước đây để tạo các Icon đó ta phải thực hiện cắt chúng ra từ file PSD và dùng CSS để gán background hoặc dùng thẻ img để đưa Icon đó vào. Tuy nhiên hiện nay chúng ta đã có giải pháp khác đó là sử dụng Symboy Font (font chữ kiểu ký hiệu). Hiện nay có nhiều thư viện Symboy Font nhưng mạnh nhất và hay sử dụng nhất là Font Awesome, Material icon… vì nó đơn giản và dễ sử dụng.

1. Awesome Font

Font Awesome là một trong những icon font phổ biến nhất hiện nay. Với phiên bản mới nhất hiện tại 5.5.0, Font Awesome hỗ trợ trên 1400 icon free.

Một số tool hữu ích dành cho Web Developer có thể bạn chưa biết (Phần 1)

2. IcoMoon Font

IcoMoon thực chất là một ứng dụng cho phép bạn tuỳ chỉnh icon font, import SVG để tạo ra font riêng, convert font sang SVG, PDF, XAML, CSH… Và IcoMoon cung cấp hơn 5000 icon free bằng cách tối ưu từ nhiều thư viện miễn phí khác nhau

Một số tool hữu ích dành cho Web Developer có thể bạn chưa biết (Phần 1)

CSS Generator

1. CSS tool

Một số tool hữu ích dành cho Web Developer có thể bạn chưa biết (Phần 1)

Đây là công cụ tổng hợp không thể thiếu của một CSS Developer. Có rất nhiều tool dùng để tạo box-shadow, background gradient, text effect, transform…

2. Image Sprites

Với một Frontend developer chắc không xa lạ với kỹ thuật image sprites. Đây là phương pháp giúp tối ưu website, tuy nhiên để xác định tọa độ (background-position) thật là một điều khó khăn. Sau đây làm một công cụ tuyệt vời để giải quyết vấn đề trên với thao tác đơn giản.

Một số tool hữu ích dành cho Web Developer có thể bạn chưa biết (Phần 1)

Tổng kết

Trên đây là một số công cụ cần thiết của một Frontend/Design developer. Hy vọng những công cụ này có thể hỗ trợ phần nào cho công việc lên ý tưởng, hoàn thiện thiết kế UI và phát triển phần code Frontend cho các dự án của các bạn.

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

  Một số tool hữu ích dành cho Web Developer có thể bạn đã biết (Phần 2)

Xem thêm vị trí tuyển dụng web Developer hấp dẫn tại TopDev

Senior là gì? Phân biệt Senior và Junior thật chi tiết

senior là gì
senior là gì

Thị trường tuyển dụng đang phát triển, có rất nhiều thuật ngữ ra đời. Thuật ngữ Senior là một trong số đó. Vậy Senior là gì? Senior không chỉ đơn giản là một người có nhiều năm kinh nghiệm hơn, mà còn là một người đã đạt được một trình độ chuyên môn cao, có khả năng dẫn dắt đội nhóm và đưa ra các quyết định quan trọng. Bài viết này sẽ đi sâu vào khái niệm Senior là gì, những kỹ năng cần có để trở thành một Senior thực thụ, và làm thế nào để liên tục nâng cao trình độ của mình.

Senior là gì?

Senior là thuật ngữ chỉ một người đã có nhiều năm kinh nghiệm (thường là từ 3 năm trở lên), có sự hiểu biết và trải nghiệm dày dặn trong lĩnh vực của mình. Khả năng chuyên môn của họ đã được nâng cao thông qua các thách thức từ những giai đoạn Intern, Fresher, Junior trước đó.

Senior có khả năng làm việc độc lập và đảm nhận các nhiệm vụ phức tạp mà không cần sự giám sát liên tục. Senior không chỉ có kiến thức chuyên môn sâu rộng mà còn có kỹ năng quản lý thời gian, làm việc nhóm và ra quyết định dựa trên kinh nghiệm thực tế.

Senior là gì?
senior là gì

Nhiều người thường nghĩ rằng một Senior sẽ được tôi luyện từ 4 đến 5 năm. Tuy nhiên, đó là cách nghĩ sai lầm. Bạn khó có thể trở thành “tiền bối” nếu chỉ đơn thuần đảm nhận các công việc lặt vặt, dự án với quy mô nhỏ. Không có sự rèn luyện, tiếp thu cái mới về năng lực – kỹ năng, tư duy nghề nghiệp thì bạn phải chấp nhận một sự thật rằng: Bạn vẫn không khác Junior là bao.

Điều đó cho thấy việc tự tích lũy kiến thức theo quá trình mới thật sự quan trọng. Do vậy, không thể đánh giá, phân loại Senior chỉ dựa vào số năm kinh nghiệm. Và tùy thuộc vào từng loại hình công ty, việc phân chia cấp bậc Senior lại có những tiêu chí khác nhau.

Vai trò và công việc của Senior

Trong một tổ chức, vai trò của Senior rất quan trọng. Họ thường là những người dẫn dắt dự án, định hướng kỹ thuật, và đôi khi còn đóng vai trò cố vấn cho các thành viên trẻ hơn trong nhóm. Senior không chỉ đảm bảo rằng công việc được hoàn thành đúng hạn và đạt chất lượng cao mà còn đóng góp vào việc xây dựng văn hóa làm việc tích cực và hiệu quả.

Senior cũng thường là người chịu trách nhiệm trong việc đưa ra các quyết định kỹ thuật quan trọng, đảm bảo rằng các dự án phát triển theo đúng hướng và đáp ứng các yêu cầu kinh doanh. Họ cũng có trách nhiệm đào tạo và hướng dẫn những thành viên mới, giúp họ nhanh chóng nắm bắt công việc và hòa nhập với đội ngũ.

Ngoài ra, Senior cần cung cấp các báo cáo tiến độ thường xuyên cho cấp trên hoặc khách hàng, đảm bảo rằng mọi người đều cập nhật về tình trạng hiện tại của dự án. Đánh giá hiệu suất làm việc của bản thân và các thành viên trong nhóm, đưa ra các phản hồi và đề xuất cải tiến khi cần thiết.

>> Xem thêm: Senior developer là gì? Vai trò và kĩ năng cần có

Những kỹ năng giúp Senior lên “trình” hiệu quả

Kỹ năng về chuyên môn

Kỹ năng chuyên môn phản ánh sự am hiểu các kiến thức nền tảng cần phải có trước khi bạn bước vào giai đoạn phát triển năng lực

Nâng cao không ngừng kiến thức chuyên môn

Một trong những yếu tố quan trọng nhất để một Senior có thể nâng cao trình độ là không ngừng trau dồi và cập nhật kiến thức chuyên môn của mình. Ở cấp độ Senior, bạn cần có sự hiểu biết sâu rộng về lĩnh vực mà mình đang làm việc, từ các công cụ, framework đến các xu hướng công nghệ mới nhất. Việc cập nhật kiến thức liên tục giúp bạn không chỉ giữ vững vị thế mà còn trở thành người dẫn đầu trong việc áp dụng các giải pháp công nghệ tiên tiến.

Để phát triển kỹ năng chuyên môn, bạn có thể:

  • Tham gia các khóa học nâng cao, hội thảo và seminar liên quan đến lĩnh vực của mình.
  • Tham gia vào các cộng đồng chuyên môn để trao đổi và học hỏi từ các chuyên gia khác.
  • Đọc sách chuyên ngành, bài viết và nghiên cứu để nắm bắt các xu hướng mới.

Khả năng phân tích và giải quyết vấn đề

Một Senior không chỉ cần biết cách làm việc mà còn phải hiểu rõ lý do và nguyên nhân sâu xa của các vấn đề trong công việc. Kỹ năng phân tích và giải quyết vấn đề là rất cần thiết, đặc biệt trong những tình huống phức tạp, yêu cầu tư duy logic và sự sáng tạo để tìm ra giải pháp hiệu quả.

Để cải thiện kỹ năng này, bạn có thể:

  • Thực hành phân tích các vấn đề thực tế và đề xuất giải pháp.
  • Thảo luận với đồng nghiệp hoặc nhóm để lắng nghe các góc nhìn khác nhau và tìm ra phương pháp tốt nhất.
  • Tham gia các dự án thử thách để rèn luyện khả năng xử lý tình huống phức tạp.

Kỹ năng làm việc nhóm

Kỹ năng làm việc nhóm là một trong những kỹ năng cốt lõi mà mọi Senior cần phải nắm vững. Ở vị trí này, bạn không chỉ làm việc cá nhân mà còn phối hợp với các thành viên khác trong nhóm để đạt được mục tiêu chung. Hiểu rõ vai trò của mình và của các thành viên khác trong nhóm giúp bạn phối hợp hiệu quả hơn, đảm bảo rằng mọi người đều đóng góp tối đa vào thành công của dự án.

Một Senior thường được kỳ vọng có thể dẫn dắt nhóm, đặc biệt trong các dự án lớn hoặc khi đối mặt với những thách thức khó khăn. Khả năng lãnh đạo không chỉ bao gồm việc đưa ra chỉ đạo mà còn là khả năng truyền cảm hứng, thúc đẩy tinh thần đồng đội và tạo ra một môi trường làm việc tích cực.

Để phát triển kỹ năng lãnh đạo nhóm:

  • Hãy thể hiện tinh thần trách nhiệm và cam kết với công việc của nhóm.
  • Lắng nghe và hỗ trợ các thành viên trong nhóm khi họ gặp khó khăn.
  • Đưa ra các giải pháp và hướng dẫn rõ ràng để nhóm có thể thực hiện công việc một cách hiệu quả.

Làm việc Client

Làm việc với Client/User là một kỹ năng quan trọng đối với một Senior, đặc biệt trong các lĩnh vực yêu cầu sự tương tác trực tiếp với khách hàng như công nghệ thông tin, thiết kế, hay marketing. Hiểu rõ nhu cầu và mong muốn của khách hàng giúp bạn đưa ra các giải pháp phù hợp và đáp ứng được kỳ vọng của họ.

Quản lý kỳ vọng của khách hàng là một trong những thách thức lớn mà mọi Senior đều phải đối mặt. Việc này không chỉ đòi hỏi khả năng giao tiếp tốt mà còn yêu cầu sự nhạy bén trong việc xử lý các tình huống khó khăn, chẳng hạn như khi có sự khác biệt giữa mong đợi của khách hàng và khả năng thực hiện của đội ngũ.

Chuẩn bị các phương án dự phòng và kế hoạch rõ ràng để giải quyết khi có tình huống phát sinh.

Kỹ năng đàm phán

Một Senior không chỉ cần giao tiếp mà còn phải biết đàm phán và thuyết phục, đặc biệt trong các tình huống cần thương lượng về ngân sách, thời gian hoàn thành, hoặc các yêu cầu kỹ thuật. Kỹ năng này giúp bạn đạt được các thỏa thuận có lợi và duy trì mối quan hệ tốt đẹp với các bên liên quan.

Để cải thiện kỹ năng đàm phán:

  • Hãy chuẩn bị kỹ lưỡng trước mỗi cuộc đàm phán, nắm vững thông tin và dữ liệu cần thiết.
  • Hiểu rõ lợi ích của cả hai bên và tìm kiếm giải pháp win-win.
  • Giữ thái độ linh hoạt và sẵn sàng thương lượng để đạt được mục tiêu chung.

So sánh Senior và Junior

Dưới đây là bảng so sánh giữa Senior và Junior để giúp bạn dễ dàng so sánh các yếu tố quan trọng:

Tiêu Chí Junior Senior
Kinh Nghiệm Ít kinh nghiệm hoặc mới bắt đầu sự nghiệp Nhiều năm kinh nghiệm (thường từ 5-10 năm trở lên)
Kiến Thức Chuyên Môn Đang học hỏi và phát triển kỹ năng cơ bản Kiến thức chuyên môn sâu rộng, cập nhật liên tục
Giải Quyết Vấn Đề Cần sự hướng dẫn khi gặp vấn đề Có khả năng phân tích và giải quyết vấn đề phức tạp
Mức Độ Độc Lập Cần sự giám sát và hỗ trợ từ cấp trên Làm việc độc lập mà không cần sự giám sát liên tục
Vai Trò Trong Nhóm Hỗ trợ và thực hiện các nhiệm vụ dưới sự hướng dẫn Lãnh đạo nhóm, đào tạo Junior, chịu trách nhiệm dự án
Giao Tiếp Đang phát triển kỹ năng giao tiếp Giao tiếp hiệu quả, có khả năng thuyết phục và đàm phán
Lãnh Đạo Chủ yếu là người thực hiện nhiệm vụ Định hướng, lãnh đạo và truyền cảm hứng cho đội nhóm
Đóng Góp Vào Tổ Chức Đóng góp ở mức độ công việc cá nhân Tham gia vào chiến lược, cải tiến quy trình, nâng cao hiệu quả tổ chức
Mức thu nhập Mức lương trung bình cho Junior thường từ 8-15 triệu VND/tháng tại Việt Nam. Mức lương trung bình cho Senior có thể từ 25-50 triệu VND/tháng, hoặc hơn tùy vào ngành nghề và công ty.

Khi bạn đang làm việc với chức danh Junior nhưng cảm thấy mình đã đạt được trình độ của Senior, đừng ngần ngại apply vào vị trí Senior bạn nhé, đây chính là thử thách đầu tiên trên con đường phát triển của bạn.

Việc trở thành Senior không phải là điểm dừng mà là một bước tiến mới, đòi hỏi sự tiếp tục học hỏi và phát triển để duy trì và nâng cao năng lực chuyên môn.

>> Xem thêm: So sánh chi tiết Fresher, Junior và Senior

Lời kết

Senior là vị trí đòi hỏi nhiều kỹ năng khác nhau tương ứng với từng ngành nghề nhất định. Hãy đầu tư nhiều vào sự trải nghiệm thay vì mãi loay hoay một nhiệm vụ. Sự đào thải và tính cạnh tranh luôn tồn tại trong môi trường làm việc của các Senior. Đừng để bản thân rơi vào áp lực! Không ngừng nỗ lực, nâng cao trình độ chuyên môn là điều các Senior cần ghi nhớ. TopDev hy vọng, bài viết đã có những chia sẻ bổ ích giúp các bạn có cái nhìn rõ hơn về senior là gì; các kỹ năng cần thiết của một Senior. Chúc các bạn có sự chuẩn bị tốt nhất cho mục tiêu của chính mình.

Tuyển dụng lập trình viên đãi ngộ tốt, tham khảo ngay

Một số đoạn code Python phổ biến bạn nên thuộc lòng

Một số đoạn code Python phổ biến bạn nên thuộc lòng

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

Đảo ngược chuỗi trong Python

Đoạn mã sau đảo ngược một chuỗi bằng cách sử dụng thao tác cắt (slicing) trong Python.

# Đảo ngược chuỗi sử dụng slicing

my_string = "ABCDE"
reversed_string = my_string[::-1]

print(reversed_string)

# Kết quả
# EDCBA

Viết Hoa ký tự đầu tiên của mỗi từ

Đoạn code sau có thể được sử dụng để chuyển đổi một chuỗi thành trường chuỗi mới được viết HOA ký tự đầu tiên của mỗi từ.

Điều này được thực hiện bằng cách sử dụng phương thức title() của string class.

my_string = "đây là một chuỗi"

# Sử dụng hàm title() của lớp string
new_string = my_string.title()

print(new_string)

# kết quả
# Đây Là Một Chuỗi

Tìm việc python các công ty tập đoàn

Tìm các phần tử duy nhất trong một chuỗi

Đoạn code sau có thể được sử dụng để tìm tất cả các phần tử duy nhất trong một chuỗi.

Chúng ta sử dụng tính chất của kiểu dữ liệu set: Tất cả các phần tử trong set là duy nhất.

my_string = "aavvccccddddeee"

# Chuyển chuỗi thành một set
temp_set = set(my_string)

# Chuyển set thành một chuỗi sử dụng join
new_string = ''.join(temp_set)

print(new_string)

# Kết quả
# acdve

# Vì set không có thứ tự
# nên thứ tự chuỗi mới nhận được là ngẫu nhiên

In một Chuỗi hoặc một List n lần

Bạn có thể sử dụng phép nhân (*) với chuỗi hoặc List. Điều này cho phép chúng ta nhân chúng bao nhiêu lần tùy thích.

n = 3 # Số lần lặp lại

my_string = "abcd"
my_list = [1,2,3]

print(my_string*n)
# abcdabcdabcd

print(my_list*n)
# [1,2,3,1,2,3,1,2,3]

Một trường hợp sử dụng thú vị của điều này có thể là để xác định một list với các giá trị không đổi – hãy thử xem:

n = 4
my_list = [0]*n # n Độ dài của list
# [0, 0, 0, 0]
  Quy tắc đặt tên biến trong Python đúng chuẩn 2024

List comprehension

List comprehension cung cấp cho chúng ta một cách đơn giản, thanh lịch để tạo list dựa trên các list khác.

Đoạn code sau tạo một list mới bằng cách nhân từng phần tử của list cũ với 2.

# Nhân mỗi phần tử của list với 2

original_list = [1,2,3,4]

new_list = [2*x for x in original_list]

print(new_list)
# [2,4,6,8]

Hoán đổi giá trị giữa hai biến trong Python

Python làm cho việc hoán đổi giá trị giữa 2 biến khá đơn giản mà không cần sử dụng một biến trung gian khác.

a = 1
b = 2

a, b = b, a

print(a) # 2
print(b) # 1

Tuyển dụng python Hà Nội lương cao, tham khảo ngay!

Tách một chuỗi thành một list

Chúng ta có thể tách một chuỗi thành một list chứa các chuỗi con bằng phương thức .split().

Bạn cũng có thể truyền một đối số (dấu phân cách) để hướng dẫn tách chuỗi theo chỉ định của bạn.

string_1 = "Tên tôi là NIIT Hà Nội"
string_2 = "chuỗi 1/ chuỗi 2"

# Tách chuỗi mặc định sẽ tách từ khoảng trắng ' '
print(string_1.split())
# ['Tên', 'tôi', 'là', 'NIIT', 'Hà', 'Nội']

# Tách chuỗi từ ký tự '/'
print(string_2.split('/'))
# ['chuỗi 1', ' chuỗi 2']

Kết hợp một danh sách các chuỗi thành một chuỗi

Ngược lại ở ví dụ trên, chúng ta có danh sách các chuỗi. Bây giờ ghép chúng lại thành một chuỗi duy nhất.

Chúng ta sẽ sử dụng phương thức join().

Trong trường hợp này, chúng ta truyền đối số (dấu phân tách) để hướng dẫn ghép chuỗi. (Mình sẽ sử dụng dấu phảy)

list_of_strings = ['Tên', 'tôi', 'là', 'NIIT', 'Hà', 'Nội']

# Sử dụng join và phân tách bằng dấu phảy
print(','.join(list_of_strings))

# Output
# Tên,tôi,là,NIIT,Hà,Nội
  Python: Cách in mà không cần dòng mới

Kiểm tra một chuỗi có phải chuỗi đối xứng

Vì chúng ta đã biết cách đảo ngược chuỗi nên việc kiểm tra một chuỗi có phải chuỗi đối xứng hay không sẽ rất đơn giản.

my_string = "abcba"

if my_string == my_string[::-1]:
    print("Chuỗi đối xứng")
else:
    print("Chuỗi không đối xứng")

# Kết quả
# Chuỗi đối xứng

Tình số lần xuất hiện của các phần tử trong một List

Có nhiều cách để làm điều này, nhưng mình thích sử dụng Counter của Python.

Bộ đếm Python theo dõi tần suất của từng phần tử trong container.

Counter() trả về một dictionary với các phần tử là key và số lần xuất hiện là value.

Chúng tôi cũng sử dụng hàm most_common() để lấy phần tử most_frequent (xuất hiện nhiều nhất) trong List.

# Tìm số lần xuất hiện của mỗi phần từ trong List

# import Counter
from collections import Counter

my_list = ['a','a','b','b','b','c','d','d','d','d','d']
count = Counter(my_list) # Xác định đối tượng counter

print(count) # In thông tin tất cả
# Counter({'d': 5, 'b': 3, 'a': 2, 'c': 1})

print(count['b']) # Số lần xuất hiện của phần tử cụ thể
# 3

print(count.most_common(1)) # Phần tử xuất hiện nhiều nhất
# [('d', 5)]

Tìm xem hai chuỗi có đảo chữ không

Một ứng dụng thú vị của Counter là tìm chuỗi đảo chữ.

Đảo chữ là một từ hoặc cụm từ được hình thành bằng cách sắp xếp lại các chữ cái của một từ hoặc cụm từ khác nhau.

Nếu các đối tượng Counter của hai chuỗi bằng nhau, thì chúng là đảo chữ cái.

# import Counter
from collections import Counter

str_1, str_2, str_3 = "acbde", "abced", "abcda"
cnt_1, cnt_2, cnt_3  = Counter(str_1), Counter(str_2), Counter(str_3)

if cnt_1 == cnt_2:
    print('1 và 2 Đảo chữ')
if cnt_1 == cnt_3:
    print('1 và 3 Đảo chữ')

Sử dụng Khối try-except-else

Xử lý lỗi trong Python có thể được thực hiện dễ dàng bằng cách sử dụng khối try / except.

Thêm một câu lệnh else vào khối này rất hữu ích. Nó sẽ chạy khi không có ngoại lệ xảy ra trong khối try.

Nếu bạn cần chạy một cái gì đó không phân biệt ngoại lệ, hãy sử dụng finaly.

a, b = 1,0

try:
    print(a/b)
    # Ngoại lệ xảy ra khi b == 0
except ZeroDivisionError:
    print("Chia cho số 0")
else:
    print("Không có ngoại lệ xảy ra")
finally:
    print("Luôn luôn chạy lệnh này!")

Việc làm python Đà Nẵng đãi ngộ tốt

Sử dụng liệt kê (Enumerate) để nhận các cặp index / value

Kịch bản sau đây sử dụng phép liệt kê (enumerate) để lặp qua các giá trị trong list cùng với các chỉ mục (index) của chúng.

my_list = ['a', 'b', 'c', 'd', 'e']

for index, value in enumerate(my_list):
    print('{0}: {1}'.format(index, value))

# 0: a
# 1: b
# 2: c
# 3: d
# 4: e

Kiểm tra mức sử dụng bộ nhớ của một đối tượng

Đoạn code sau đây có thể được sử dụng để kiểm tra mức sử dụng bộ nhớ của một đối tượng.

import sys

num = 21

print(sys.getsizeof(num))

# Kết quả trong Python 2 là: 24
# Kết quả trong Python 3 là: 28

Hợp nhất hai từ điển

Trong khi ở Python 2, chúng ta đã sử dụng phương thức update() để hợp nhất hai Dictionaries.

Nhưng Python 3.5 làm cho quá trình này đơn giản hơn nhiều.

Trong đoạn code được đưa ra dưới đây, hai Dictionaries được hợp nhất.

Lưu ý: Các value của Dictionaries thứ hai sẽ được sử dụng nếu key bị trùng với key trong Dictionaries thứ nhất.

dict_1 = {'apple': 9, 'banana': 6}
dict_2 = {'banana': 4, 'orange': 8}

combined_dict = {**dict_1, **dict_2}

print(combined_dict)
# Output
# {'apple': 9, 'banana': 4, 'orange': 8}

Nếu bạn muốn giữ các giá trị của chúng, bạn có thể làm như sau:

def mergeDict(dict1, dict2):
   ''' Hợp nhất dictionaries và giữ giá trị của key phổ biến trong list'''
   dict3 = {**dict1, **dict2}
   for key, value in dict3.items():
       if key in dict1 and key in dict2:
               dict3[key] = [value , dict1[key]]
 
   return dict3

# Hợp nhất dictionaries và thêm giá trị của key phổ biến trong list
dict3 = mergeDict(dict1, dict2)
 
print('Dictionary 3 :')
print(dict3)

Tính thời gian thực hiện để thực thi một đoạn code trong Python

Đoạn code sau sử dụng thư viện time để dễ dàng giúp chúng ta tính thời gian thực để thực thi một đoạn code trong Python.

# import thư viện time
import time

# Kiểm tra thời gian bắt đầu
start_time = time.time()

# Code cần kiểm tra
a, b = 1,2
c = a+ b

# Kiểm tra thời gian kết thúc
end_time = time.time()

# Tính thời gian chênh lệch
time_taken_in_micro = (end_time- start_time)*(10**6)

# In kết quả
print(" Thời gian thực thi micro_seconds: {0} ms").format(time_taken_in_micro)

Trải phẳng list trong list

Đôi khi bạn không chắc chắn về mức độ lồng trong list của mình và bạn chỉ muốn trải phẳng tất cả các phần tử trong đó thành một list duy nhất.

Đây là cách bạn có thể thực hiện:

from iteration_utilities import deepflatten

# Nếu bạn chỉ có một lồng 1 cấp, sử dụng cái này
def flatten(l):
  return [item for sublist in l for item in sublist]

l = [[1,2,3],[3]]
print(flatten(l))
# [1, 2, 3, 3]

# Nếu bạn không biết list lồng sâu thế nào
l = [[1,2,3],[4,[5],[6,7]],[8,[9,[10]]]]

print(list(deepflatten(l, depth=3)))
# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

Lấy mẫu từ một List

Đoạn mã sau tạo ra n số mẫu ngẫu nhiên từ một list nhất định bằng thư viện random.

# import thư viện
import random

my_list = ['a', 'b', 'c', 'd', 'e']
num_samples = 2

samples = random.sample(my_list,num_samples)
print(samples)

# Kết quả nhận được là ngẫu nhiên:
# [ 'a', 'e']

Bạn cũng có thể sử dụng thư viện secrets để tạo các mẫu ngẫu nhiên để mã hóa.

Đoạn code sau sẽ chỉ hoạt động trên Python 3.

import secrets                              # imports secure module.
secure_random = secrets.SystemRandom()      # Tạo một đối tượng secure ngẫu nghiên.

my_list = ['a','b','c','d','e']
num_samples = 2

samples = secure_random.sample(my_list, num_samples)

print(samples)

# Kết quả nhận được là ngẫu nhiên:
# [ 'e', 'd']

Chuyển đổi một số thành danh sách các chữ số trong Python

Đoạn code sau sẽ chuyển đổi một số nguyên thành một danh sách các chữ số.

num = 123456

# Sử dụng map
list_of_digits = list(map(int, str(num)))

print(list_of_digits)
# [1, 2, 3, 4, 5, 6]

# Sử dụng kỹ thuật list comprehension
list_of_digits = [int(x) for x in str(num)]

print(list_of_digits)
# [1, 2, 3, 4, 5, 6]

Kiểm tra tính duy nhất

Hàm trong ví dụ sau sẽ kiểm tra xem tất cả các phần tử trong list có phải là duy nhất hay không.

def unique(l):
    if len(l) == len(set(l)):
        print("Tất cả phần tử là duy nhất")
    else:
        print("List có phần tử trùng lặp")

unique([1,2,3,4])
# Tất cả phần tử là duy nhất

unique([1,1,2,3])
# List có phần tử trùng lặp

Tổng kết

Đây là một số Đoạn code Python ngắn mình thấy cực kỳ hữu ích trong công việc hàng ngày của mình.

Nếu bạn chưa hiểu lắm, Khóa học Python trên ucode.vn sẽ dạy bạn đầy đủ và chi tiết nhất để bạn hoàn toàn làm chủ Ngôn ngữ Python.

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

Xem thêm các việc làm it hấp dẫn tại TopDev

5 kỹ năng quan trọng cho ngành Nhân sự

ngành nhân sự

Ngành nhân sự ngày nay đòi hỏi nhiều kỹ năng. Đó cũng là thách thức lớn đối với những ai lựa chọn theo đuổi ngành nghề này. Khi thế giới nhân sự phát triển, việc tìm kiếm những người có kỹ năng tốt để đáp ứng sự vận hành hiện đại là ưu tiên hàng đầu. Liệu các kỹ năng nào sẽ giúp bạn có đủ cạnh tranh trong thị trường này? Cùng TopDev điểm qua những kỹ năng mà một HR cần phải.

Giao tiếp

Vấn đề giao tiếp được đánh giá là quan trọng. Vì nó được xem là chiếc chìa khóa giúp bạn thành công. Những người làm nhân sự cần có một khả năng giao tiếp tốt. 

ngành nhân sự

Không chỉ đơn thuần là trao đổi thông tin, bạn còn phải nắm bắt được cảm xúc, suy nghĩ của người tiếp nhân thông tin. Đồng thời, nhận biết những biểu hiện của giao tiếp phi ngôn ngữ: cử chỉ, hành vi,… Chằng hạn trong công tác quản trị nhân sự, mỗi lời nói của các lãnh đạo/nhà quản lý  đều thể hiện một thông điệp nào đó. Và phát ngôn đó đủ sức tạo ra sự ảnh hưởng đến nhân viên.

Tuyển dụng

Sẽ là một thiếu sót lớn nếu bỏ qua kỹ năng này. Vì thực tế, nó chính là một phần công việc mà người người thuộc lĩnh vực nhân sự cần phải thực hiện.

  Những sai lầm phổ biến trong Tuyển dụng Nhân sự

ngành nhân sự

Các thách thức trong việc tìm kiếm, thu hút ứng viên tài năng; và làm thế nào để quản trị nguồn nhân lực hiệu quả đang là mối quan tâm lớn của nhà tuyển dụng. Đó là lý do tại sao họ cần những HR giàu kinh nghiệm và kỹ năng. Điều này mở ra một cuộc chiến tuyển dụng lớn. Và nếu bạn là người có kỹ năng tốt, bạn sẽ có lợi thế nhiều hơn trong cuộc chơi tuyển dụng. 

Công nghệ nhân sự và phân tích dữ liệu

Công nghệ nhân sự là kỹ năng gia tăng các cơ hội tuyển dụng. Những lợi thế mà nó mang lại rất lớn do HR và công nghệ đang ngày càng gắn kết chặt chẽ với nhau.

Việc quản trị nguồn nhân lực đang đi vào thời đại kỹ thuật số. Ngày càng nhiều quá trình được tự động hóa và tăng cường bởi công nghệ. Vì thế, nếu có những hiểu biết cơ bản về công nghệ, bạn sẽ chạm gần hơn với sự thành công.

ngành nhân sự

Đồng thời, nhiều người nghĩ rằng phân tích dữ liệu là một kỹ năng không quá quan trọng. Và họ bỏ qua chúng, điều này thật sai lầm!

Với sự phát triển nguồn dữ liệu đa dạng, nhà tuyển dụng cần những người có khả năng đọc được dữ liệu tốt. Điều này giúp cho công tác nhân sự trở nên chặt chẽ hơn. Từ đó, việc tiếp cận và khai thác nguồn thông tin nhiều hơn.

Trí tuệ cảm xúc – EI

Trí tuệ cảm xúc là tiêu chí quan trọng để đánh giá bạn có thể trở thành một lãnh đạo nhân sự giỏi.

Đối với ngành Nhân sự, trí tuệ cảm xúc đã trở thành một chiến lược quan trọng. Tại sao? Vì nó là một trong những yếu tố quyết định liệu bạn có đủ sự phù hợp với vai trò ứng tuyển hay không. Ngoài ra, sự hiểu biết từ EI có thể giúp bạn xác định xu hướng hành vi của tổ chức/doanh nghiệp. 

  Trí tuệ cảm xúc là gì và áp dụng như thế nào trong ngành Nhân sự

ngành nhân sự

Với EI, bạn có thể khám phá cảm xúcnhững tác động đa chiều xung quanh. Đồng thời, EI còn giúp hình thành nên một môi trường làm việc thân thiện, vui vẻ. Từ đó thúc đẩy việc gia tăng hiệu suất công việc của toàn tổ chức. Chính vì điều này, bạn nên học cách nhận biết những cảm xúc. Hãy rèn luyện để bạn có thể điều khiển được tích cách, suy nghĩ và hành động của mình một cách hiệu quả.

Khả năng thích ứng và sự nhanh nhẹn

Ngành nghề nhân sự cần những ứng viên có khả năng thích nghi tốt. Đồng thời, họ phải nhanh nhẹn để đáp ứng đủ các tiêu chí.

Những nhà lãnh đạo luôn tìm kiếm những người có thể nắm bắt nhanh tình hình. Họ cũng được trao quyền khi đưa ra các đánh giá, những biện pháp, lập kế hoạch xử lý phù hợp. Điều này giúp giảm thiểu tối đa những ảnh hưởng xấu trong công tác quản trị doanh nghiệp.

ngành nhân sự

Đặc biệt, theo một khía cạnh khác các nhà quản lý nhân sự còn đòi hỏi nhân viên của họ có sự bản lĩnh. Và hơn hết, chính sự thích ứng là chiếc chìa khóa tạo ra sự bản lĩnh cho bạn. Một câu hỏi đặt ra là “Bạn sẽ tiếp tục làm công việc cũ hay bức phá khỏi“vùng an toàn?” Với những tố chất sẵn có từ ngành nhân sự cùng khả năng thích ứng tốt, bạn sẽ có những lựa chọn đúng đắn nhất.

Lời kết

Bối cảnh ngành nhân sự đang phát triển theo xu thế chung của thời đại. Vì thế, các doanh nghiệp rất cần những người đa kỹ năng đáp ứng kịp thời sự phát triển đó. Song, đó là một quá trình tích lũy và rèn luyện lâu dài. TopDev hi vọng các bạn sẽ biết đâu là điều mình cần làm. Từ đó, lập kế hoạch theo đuổi mục tiêu thông quq những hành động cụ thể nhất.


Tuyển Dụng Nhân Tài IT Cùng TopDev
Đăng ký nhận ưu đãi & tư vấn về các giải pháp Tuyển dụng IT & Xây dựng Thương hiệu tuyển dụng ngay!
Hotline: 028.6273.3496 – Email: contact@topdev.vn
Dịch vụ: https://topdev.vn/page/products

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

Xem thêm Top Việc làm Developer trên TopDev

Kiểm thử đơn vị trong C# với Nunit và .Net Core

Kiểm thử đơn vị trong C# với Nunit và .Net Core

Bài viết được sự cho phép của BBT Tạp chí Lập trình

Bài viết sẽ hướng dẫn từng bước xây dựng giải pháp kiểm thử đơn vị. Bài viết này đề cập tới việc kiểm thử một dự án .NET Core.

  So sánh tốc độ List collection và HashSet collection trong C#
  Namespace trong C#

Tạo dự án

Tạo một thư mục có tên là “unit-tests-using-nunit” để lưu trữ solution. Trong thư mục này, hãy chạy lệnh sau để tạo solution mới cho class library và test project:

>> dotnet new sln

Tiếp theo, tạo thư mục PrimeService. Các phác thảo sau đây cho thấy cấu trúc thư mục và tập tin:

Đi đến thư mục PrimeService và chạy lệnh sau để tạo dự án nguồn:

>> dotnet new classlib

Đổi tên Class1.cs thành PrimeService.cs. Tạo ra một triển khai fail của lớp PrimeService:

using System;
namespace Prime.Services
{
    public class PrimeService
    {
        public bool IsPrime(int candidate)
        {
            throw new NotImplementedException("Please create a test first.");
        }
    }
}

Đi đến thư mục “unit-tests-using-nunit”. Chạy lệnh sau để thêm dự án class library vào solution:

>> dotnet sln add PrimeService/PrimeService.csproj

Tạo dự án test

Tiếp theo, tạo thư mục “PrimeService.Tests”. Các phác thảo sau đây cho thấy cấu trúc thư mục:

Đi đến thư mục “PrimeService.Tests” và tạo dự án mới bằng lệnh sau:

>> dotnet new nunit

Lệnh “dotnet new” tạo ra một dự án test sử dụng NUnit làm thư viện test. Xem file cấu hình PrimeService:

using System;
namespace Prime.Services
{
    public class PrimeService
    {
        public bool IsPrime(int candidate)
        {
            throw new NotImplementedException("Please create a test first.");
        }
    }
}

Dự án test yêu cầu các gói khác để tạo và chạy kiểm thử đơn vị. Lệnh “dotnet new” trong bước trước đã thêm SDK test của Microsoft, NUnit test framework và bộ điều hợp thử nghiệm NUnit. Bây giờ, thêm class library PrimeService như một phụ thuộc khác vào dự án. Sử dụng lệnh “dotnet add reference”:

>> dotnet add reference ../PrimeService/PrimeService.csproj

Các phác thảo sau đây cho thấy cấu trúc của solution:

Thực hiện lệnh sau trong thư mục “unit-tests-using-nunit”:

>> dotnet sln add ./PrimeService.Tests/PrimeService.Tests.csproj

Tạo test

Bạn viết một test fail, làm cho nó pass, sau đó lặp lại quá trình. Trong thư mục “PrimeService.Tests”, đổi tên tệp UnitTest1.cs thành PrimeService_IsPrimeShould.cs và thay thế toàn bộ nội dung của nó bằng mã sau:

using NUnit.Framework;
using Prime.Services;

namespace Prime.UnitTests.Services
{
    [TestFixture]
    public class PrimeService_IsPrimeShould
    {
        private PrimeService _primeService;

        [SetUp]
        public void SetUp()
        {
            _primeService = new PrimeService();
        }

        [Test]
        public void IsPrime_InputIs1_ReturnFalse()
        {
            var result = _primeService.IsPrime(1);

            Assert.IsFalse(result, "1 should not be prime");
        }
    }        
}

Thuộc tính [TestFixture] biểu thị một lớp có chứa các phương thức kiểm thử đơn vị. Thuộc tính [Test] chỉ ra một phương thức là một phương thức kiểm thử.

Lưu tệp này và thực hiện lệnh “dotnet test” để build các kiểm thử và class library và sau đó chạy các kiểm thử. NUnit chứa Entry Point (điểm bắt đầu của chương trình)  để chạy các kiểm thử. “dotnet test” bắt đầu trình chạy thử bằng cách sử dụng dự án kiểm thử đơn vị đã tạo.

Kiểm thử sẽ thất bại. Thực hiện kiểm thử này bằng cách viết mã đơn giản nhất trong lớp PrimeService:

public bool IsPrime(int candidate)
{
    if (candidate == 1)
    {
        return false;
    }
    throw new NotImplementedException("Please create a test first.");
}

Trong thư mục “unit-testing-using-nunit”, chạy lại lệnh “dotnet test”. Lệnh “dotnet test” build dự án PrimeService và sau đó là dự án PrimeService.Tests. Sau khi build cả hai dự án, nó chạy test này, kết quả là pass.

Thêm tính năng

Có một vài trường hợp đơn giản khác cho các số nguyên tố: 0, -1. Có thể thêm các test mới với thuộc tính [Test]. Tuy nhiên, có các thuộc tính NUnit khác cho phép viết một bộ các test tương tự.

Thuộc tính [TestCase] ​​được sử dụng để tạo một bộ các test thực thi cùng một mã nhưng có các đối số đầu vào khác nhau. Bạn có thể sử dụng thuộc tính [TestCase] ​​để chỉ định các giá trị cho các đầu vào đó.

Thay vì tạo các test mới, hãy áp dụng thuộc tính này để tạo một test theo hướng dữ liệu. Test hướng dữ liệu là phương pháp test một vài giá trị nhỏ hơn hai, là số nguyên tố thấp nhất:



public bool IsPrime(int candidate)
{
    if (candidate == 1)
    {
        return false;
    }
    throw new NotImplementedException("Please create a test first.");
}

Chạy lệnh “dotnet test” và hai trong số các test này thất bại. Để thực hiện tất cả các test, hãy thay đổi mệnh đề if ở đầu phương thức Main trong file PrimeService.cs:

public bool IsPrime(int candidate)
{
    if (candidate == 1)
    {
        return false;
    }
    throw new NotImplementedException("Please create a test first.");
}

Bài viết đã hoàn thành xây dựng một thư viện nhỏ và một bộ các kiểm thử đơn vị cho thư viện đó.

Author: Nguyễn Khánh Tùng

Bài viết gốc được đăng tải tại Tạp chí Lập trình

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

Xem thêm các việc làm Developer hấp dẫn tại TopDev

Các kiểu dữ liệu trong lập trình C/C++ (Data type)

Các kiểu dữ liệu trong lập trình C/C++ (Data type)

Bài viết được sự cho phép của tác giả Trần Hữu Cương

Kiểu dữ liệu trong C – Data type là gì?

Trong lập trình C/C++ (hoặc các ngôn ngữ khác), kiểu dữ liệu chính là phần xác định các giá trị mà một biến có thể nhận hay giá trị mà một hàm có thể trả về. Các kiểu dữ liệu này đã được lưu trữ trong chương trình C.

Dễ hiểu là, nếu xem biến là một vật và kiểu dữ liệu sẽ là vùng để chứa vật đó, thì chúng ta phải lựa chọn kiểu dữ liệu phù hợp cho biến, giống như việc lựa chọn vật đựng phù hợp để chứa vật. Ví dụ một biến cần nhập một giá trị là số nguyên thì không thể khai báo kiểu dữ liệu String được.

Nhiều vị trí tuyển dụng C++ đãi ngộ tốt trên TopDev

Kiểu dữ liệu của một biến, xác định kích thước (số byte) của biến đó. Có 4 kiểu dữ liệu trong lập trình C/C++ là: Kiểu dữ liệu cơ bản, kiểu dữ liệu enum, kiểu void và kiểu dữ liệu nâng cao.

Tổng hợp các kiểu dữ liệu trong C/C++

Kiểu dữ liệu cơ bản

Kiểu dữ liệu cơ bản là kiểu dữ liệu số học, có thể là số nguyên (integer) hoặc số thực (float).

Kiểu số nguyên (integer)

Với kiểu dữ liệu số nguyên (integer) ta có các loại sau:

Kiểu Kích thước Vùng giá trị
char 1 byte -128 tới 127 hoặc 0 tới 255
unsigned char 1 byte 0 tới 255
signed char 1 byte -128 tới 127
int 2 hoặc 4 bytes -32,768 tới 32,767 hoặc -2,147,483,648 tới 2,147,483,647
unsigned int 2 hoặc 4 bytes 0 tới 65,535 hoặc 0 tới 4,294,967,295
short 2 bytes -32,768 tới 32,767
unsigned short 2 bytes 0 tới 65,535
long 4 bytes -2,147,483,648 tới 2,147,483,647
unsigned long 4 bytes 0 tới 4,294,967,295

Cùng là dữ liệu kiểu số học nhưng ta lại có nhiều kiểu khác nhau. Việc này giúp tiết kiệm bộ nhớ là linh động hơn trong việc lưu dữ liệu.

Ví dụ khi lưu tuổi một người ta chỉ cần dùng kiểu char hoặc unsigned char. Vừa tiết kiệm bộ nhớ nhưng vẫn đảm bảo có thể lưu tất cả các tuổi có thể xảy ra.

Nhưng với trường hợp dữ liệu lớn hơn, như số người trong một quốc gia thì lên tới con số hàng triệu. Do đó ta phải sử dụng loại dữ liệu khác như int

Kiểu số thực (float)

Tương tự với kiểu dữ liệu số thực (dấu phẩy động) ta cũng có các loại sau:

Kiểu Kích thước Vùng giá trị Độ chính xác
float 4 byte 1.2E-38 tới 3.4E+38 6 vị trí thập phân
double 8 byte 2.3E-308 tới 1.7E+308 15 vị trí thập phân
long double 10 byte 3.4E-4932 tới 1.1E+4932 19 vị trí thập phân

Code ví dụ:

#include <stdio.h>
#include <limits.h>

int main() {
int age = 25;
int population = 85000000; // 85 triệu

printf("Age: %d - Population: %d \n", age, population);

float pi = 3.14; // giá trị số pi
printf("pi: %f \n", pi);

printf("Storage size for int : %d \n", sizeof(int)); // kích thước kiểu int
printf("Storage size for float : %d \n", sizeof(float)); // kích thước kiểu float

return 0;
}

Kết quả:

Các kiểu dữ liệu trong lập trình C/C++ (Data type)

Kiểu dữ liệu Enum

Kiểu dữ liệu Enum trong ngôn ngữ C hay còn gọi là kiểu dữ liệu cố định, kiểu liệt kê. Giá trị của một Enum chỉ có thể nhận giá trị là một số các số nguyên cho trước.

Kiểu Enum này khá giống với kiểu Enum trong Java, Node.js hay Python…

Kiểu dữ liệu Void

Kiểu void dùng xác định không có giá trị nào (không phải là null).

Nó được sử dụng trong các trường hợp sau đây:

  • Kiểu trả về của một hàm: khi một không trả về dữ liệu gì thì hàm đó có kiểu void

Ví dụ:

void hello() {
printf("hello world");
}
  • Hàm với tham số void (tức là hàm không có tham số đầu vào)

Ví dụ: 2 cách viết dưới đây tương đương nhau:

void hello() {
printf("hello world");
}
// tương đương với
void hello(void) {
printf("hello world");
}
  • Con trỏ kiểu void void * được dùng để tham chiếu thới địa chỉ của một đối tượng (chứ không phải là một kiểu dữ liệu mới. Phần này hơi khó hiểu mình sẽ có bài riêng)

Kiểu dữ liệu nâng cao

Các kiểu dữ liệu nâng cao của C gồm:

  • Con trỏ (pointer)
  • Kiểu mảng (array)
  • Kiểu cấu trúc (structure)
  • Kiểu union
  • Kiểu hàm (function)

Kiểu dữ liệu boolean

Kiểu dữ liệu Boolean là một kiểu dữ liệu có chỉ có thể nhận một trong hai giá trị như đúng/sai (true/false, yes/no, 1/0) nhằm đại diện cho hai giá trị thật (truth value).

Trong lập trình C kiểu boolean sẽ được gọi là bool (trong Java thì gọi là boolean, trong Python thì gọi là bool… tùy theo ngôn ngữ)

Ban đầu, ngôn ngữ C không hỗ trợ kiểu bool, mà nó dùng số integer để biểu thị true/false (0 tức là false, khác 0 tức là true). Bắt đầu từ phiên bản C99 standard for C language thì mới bắt đầu hỗ trợ kiểu bool.

Lưu ý

Kiểu String

C/C++ không có loại dữ liệu string (text) dùng để hiển thị văn bản. Để hiển thị các giá trị kiểu text/string, ta dùng kiểu char. Thực chất char vẫn là kiểu số, nhưng tùy theo giá trị mà nó được hiểu thành các ký tự trong bảng mã ASCII. Một đoạn text/string trong C/C++ sẽ là một mảng char

Ví dụ số 32 tương ứng với dấu cách, 48 tương ứng với ký tự '0', 65 tương ứng với ký tự 'A'.

Để hiển thị đoạn text ‘hello’ thì ta cần mảng char tương ứng là [104, 101, 108, 108, 111]

Kiểu bool

Trong lập trình C, thực chất bool chính là kiểu integer (0 tức là false, khác 0 tức là true)

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

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

Xem ngay những tin đăng tuyển dụng IT mới nhất trên TopDev