Home Blog Page 110

Làm thế nào để làm theo “Hướng dẫn” một cách thông minh nhất?

làm việc với hướng dẫn
Làm thế nào để làm theo “Hướng dẫn” một cách thông minh nhất?

Tác giả: Jessica Wilkins

Hướng dẫn thực hiện các dự án là một cách rất phổ biến để bắt đầu xây dựng một vài kế hoạch đầu tiên của bạn. Nhưng đáng tiếc là hầu hết mọi người đều đi sai cách và không học được nhiều từ quá trình này. Trong bài viết này, tôi sẽ cung cấp một số mẹo về cách làm việc với hướng dẫn một cách hiệu quả nhất và có được sự tự tin để bắt đầu xây dựng các dự án của riêng bạn.

làm việc với hướng dẫn
Làm việc hiệu quả với hướng dẫn hơn

Tôi đã từng mắc kẹt trong chính những hướng dẫn như thế nào?

Khi tôi mới bắt đầu học cách viết code cách đây 9 tháng, tôi không hiểu rõ một quy trình làm thế nào để bắt đầu xây dựng dự án đầu tiên của mình. Vì vậy, tôi đã đăng ký một khóa học của Udemy và học cách xây dựng một trang web nhà hàng bằng HTML và CSS.

Tôi thích kết quả cuối cùng và quyết định đăng ký thêm một khóa học khác. Tôi đã học cách xây dựng trang đích sản phẩm với một số hình ảnh thú vị. Tôi đã rất tự hào về hai dự án này vì nghĩ mình đã làm được điều gì đó.

Nhưng khi tôi mở trình làm việc của mình, tôi đang vẽ một khoảng trống hoàn toàn. Tôi không có manh mối làm thế nào để bắt đầu hoặc làm thế nào để nghiên cứu. Sau đó, tôi nhận ra rằng trong suốt tháng qua, tôi đã bị mắc kẹt trong việc sử dụng các hướng dẫn mà không có kế hoạch chơi game. Tôi đã có cơ hội học hỏi từ những video này, nhưng tôi đã đi sai cách.

  Codepen là gì ? Hướng dẫn sử dụng Codepen cơ bản
  Hướng dẫn cài đặt Flutter SDK trên Linux

Tất cả những gì tôi đang làm là viết code cùng với người hướng dẫn và nhảy từ dự án này sang dự án khác. Tôi không dừng lại để đặt câu hỏi và xử lý những gì tôi vừa học được. Hướng dẫn có thể là một công cụ học tập tốt, nhưng bạn phải thực hiện nó theo cách đúng đắn, nếu không, bạn có thể trở nên phụ thuộc vào chúng và không thể tự học cách viết code.

Nên làm thế nào để hướng dẫn phát huy được hiệu quả thật sự?

Dưới đây là năm bước tôi dùng để làm việc với các dự án:

1. Nghiên cứu thật kỹ về dự án

Rất nhiều người khi mới bắt đầu, bao gồm cả tôi, sẽ chỉ đi thẳng vào video mà không suy nghĩ trước về dự án. Một phần quan trọng của việc trở thành một nhà phát triển là suy nghĩ về vấn đề trước tiên và sau đó lo lắng về việc triển khai.

Giả sử bạn muốn xem hướng dẫn về cách tạo công cụ thay đổi màu nền ngẫu nhiên. Quá trình suy nghĩ cơ bản của bạn có thể trông giống như sau:

  • Tạo ra một bộ sưu tập các màu sắc khác nhau
  • Tạo một nút mà khi nhấp vào sẽ thay đổi màu nền
  • Tạo một số loại chức năng ngẫu nhiên cho các lựa chọn màu sắc

Ngay cả khi bạn không biết cách triển khai điều đó thành code như thế nào, thì ít nhất bạn cũng đang bắt đầu suy nghĩ về vấn đề.

Xem thêm Kinh nghiệm xương máu sau 9 tháng làm Kỹ sư phần mềm (Phần 1)

2. Hãy thử xây dựng một kế hoạch bằng chính suy nghĩ của mình trước

Rất nhiều người ngại việc tự mình xây dựng một thứ gì đó vì sợ không có kỹ năng hoặc kiến ​​thức. Nhưng hãy cố gắng thử với một số vấn đề trước.

Trước khi xem video, bạn có thể thử chuyển đổi những vấn đề bạn đang nghĩ thành code trước. Nếu bạn Google “bộ sưu tập màu sắc JavaScript”, thì một trong những kết quả sẽ đề cập đến một mảng. Hoặc nếu bạn Google, “JavaScript hàm ngẫu nhiên”, thì kết quả đầu tiên sẽ dành cho Math.random().

Đây chính là cách để bạn triển khai code của mình. Chẳng có vấn đề gì kể cả nếu code của bạn không hoàn toàn đúng. Mục đích của điều này là bạn sẽ nghiên cứu được nhiều hơn và hiểu cặn kẽ được vấn đề mình đang làm việc.

kinh nghiệm lập trình

3. Xem video và đặt ra những câu hỏi

Sau khi đã suy nghĩ về dự án và bắt đầu thử một số cách code của riêng mình. Đã đến lúc bạn bắt tay vào xem video hướng dẫn. Tôi sẽ không khuyên bạn ngồi xuống và xem toàn bộ video mà không dừng lại.

Bộ não của bạn sẽ không thể nào tiêu thụ rất nhiều thông tin cùng một lúc. Sẽ tốt hơn nếu bạn tạm dừng video định kỳ để xử lý những gì bạn vừa học được. Nó cũng sẽ cho bạn cơ hội để nghiên cứu các khái niệm khiến bạn nhầm lẫn trong video.

Đặt câu hỏi và nghiên cứu là một kỹ năng quan trọng để trở thành một nhà phát triển thành công.

4. “Bóc tách” một dự án đã hoàn thành cũng giúp bạn rút ra rất nhiều kinh nghiệm

Sau khi bạn xem xong video và dự án đã hoàn thành, tôi muốn bạn phá hủy nó và cho mọi thứ trở lại từ đầu. Tạo các lỗi nhỏ trong dự án sẽ dạy bạn đọc hiểu các thông báo lỗi. Thông báo lỗi không phải lúc nào cũng là một điều xấu. Bạn có thể học được nhiều điều từ những lỗi này.

Ví dụ, có thể bạn đang thắc mắc tại sao người hướng dẫn lại chọn sử dụng let thay vì const trong một tình huống cụ thể. Hãy thử thay đổi nó thành const và xem điều gì sẽ xảy ra.

Có một thông báo lỗi? Nếu vậy, hãy đọc qua thông báo lỗi đó và bạn sẽ tìm hiểu lý do tại sao người hướng dẫn chọn sử dụng let hơn const.

  5 sai lầm thường thấy khi viết react component

5. Xây dựng lại dự án theo cách của riêng bạn

Nếu bạn muốn tự kiểm tra các khái niệm đã học trong video, hãy xây dựng lại dự án theo cách của riêng bạn. Hãy bắt đầu bằng cách chọn các phương pháp khác nhau từ người hướng dẫn.

Ví dụ: nếu người hướng dẫn sử dụng câu lệnh if / else, có thể bạn muốn thay đổi nó để chuyển đổi thành một câu lệnh khác. Hoặc nếu người hướng dẫn sử dụng một vòng lặp for đơn giản, có thể một vòng lặp forEach cũng sẽ hoạt động.

Bạn cũng có thể thêm một tính năng bổ sung vào dự án. Có thể bạn muốn tạo một số hoạt ảnh tùy chỉnh hoặc thử nghiệm với việc thêm âm thanh. Hoặc có thể bạn muốn sử dụng ứng dụng một trang đó và biến nó thành một trang web nhiều trang.

Học cách xây dựng lại dự án theo cách của riêng bạn sẽ bắt đầu mang lại cho bạn sự tự tin để tự xây dựng dự án. Nó cũng sẽ dạy bạn cách nghiên cứu, đặt câu hỏi và debug cho code của bạn.

Hướng dẫn làm việc với các dự án có thể là một công cụ học tập tuyệt vời nếu bạn sử dụng chúng đúng cách. Vậy nên hãy cố gắng để có thể sử dụng chúng một cách hợp lí và phát triển tư duy làm việc của riêng bạn.

Bài viết được phỏng dịch theo bài viết gốc tại freecodecamp.org

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

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

RxSwift 2: Khái niệm cơ bản về lập trình bất đồng bộ

RxSwift 2: Khái niệm cơ bản về lập trình bất đồng bộ

Bài viết được sự cho phép của tác giả Lê Xuân Quỳnh

Đồng bộ và bất đồng bộ khác nhau như nào? Ví dụ, khi các bạn tính 1+ 1 trên máy tính casio bỏ túi thì nó ra luôn là 2, vậy kết quả đó là tức thời thì nó là đồng bộ. Còn giả sử bạn nhập 1 + 1 trên 1 trang web, rồi bấm nút kết quả, trang đó sẽ gọi lên server xử lý được kết quả và trả về lại cho web là 2 để hiển thị cho bạn, thì như vậy bạn phải đợi trong 1 khoảng thời gian nào đó, giả sử bạn dùng mạng miền núi mất 2s mới trả về, thì đó gọi là bất đồng bộ. Nói nôm na, cái gì mà phải chờ đợi thì bất đồng bộ, còn cái gì tức thời thì đồng bộ.

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

  RxSwift 10: Làm việc với PublishSubjects
  RxSwift 5: Cài đặt RxSwift

Còn trong 1 chương trình IOS, chúng ta có thể có rất nhiều thứ bất đồng bộ, ví dụ 1 app như sau:

  • Sự kiện khi bấm vào 1 nút(button) trên màn hình, ví dụ nút đăng nhập(chúng ta thực sự không biết lúc nào thì user bấm)
  • Hiển thị bàn phím hay ẩn bàn phím trên 1 ô text filed
  • Tải 1 file ảnh lớn từ internet(không biết bao lâu thì xong, tùy thuộc vào mạng nhà bạn)
  • Lưu dữ liệu xuống đĩa
  • Chơi 1 bài hát
  • Và nhiều nữa…

Và các sự kiện trên đều có thể xảy ra cùng 1 lúc, ví dụ bạn vừa nghe nhạc vừa tải 1 ảnh về, vừa mở ô text filed để nhập gì đó. Vậy chúng ta sẽ xử lý từng sự kiện riêng biệt đó như thế nào?

RxSwift 2: Khái niệm cơ bản về lập trình bất đồng bộ
Ứng dụng IOS làm những việc bất đồng bộ đồng thời

Tất cả các việc trên đều không ngăn chặn quá trình thực thi của nhau. IOS cung cấp các APIs để thực thi các việc khác nhau trên các luồng khác nhau(thread) trên các lõi khác nhau của CPU. Tuy nhiên việc viết mã song song khá phức tạp, đặc biệt các việc khác nhau lại cần nguồn dữ liệu giống nhau. Thật khó để xác định đoạn mã nào cập nhật dữ liệu trước hoặc đoạn mã nào có được dữ liệu mới nhất. (Ví dụ bạn không thể xác định được bao lâu thì ảnh mới tải xong, ảnh nào là tải xong đầu tiên…)

Cocoa và các API UIKit bất đồng bộ

Apple cung cấp rất nhiều API trong IOS SDK của họ để giúp bạn viết các đoạn mã bất đồng bộ. Bạn có thể đã sử dụng những thứ này tuy nhiên lại không biết mình đã từng sử dụng, cụ thể những thứ phổ biến mà bạn hay dùng như sau:

  • NotificationCenter: Để thực thi những đoạn code tại 1 thời điểm không biết trước nào đó, ví dụ khi người dùng cầm điện thoại để nó nằm ngang hay dọc, bàn phím ẩn hay hiện trên ứng dụng.
  • The delegate pattern: để thực thi các đoạn code được ủy quyền từ nơi khác, ví dụ bạn muốn xử lý khi có thông báo mới (push notification) đến ứng dụng.
  • Grand Central Dispatch: để giúp bạn thực thi các phần công việc. Bạn có thể viết mã để các công việc thực thi trong 1 hàng đợi nối tiếp hay chạy vô số tác vụ đồng thời trên nhiều hàng đợi khác nhau với sự ưu tiên khác nhau.
  • Closures: để tách các đoạn mã mà bạn có thể chuyển giữa các lớp, để mỗi lớp có thể quyết định thực thi nó hay không, bao nhiêu lần và khi nào

Vì đa số các lớp của bạn đều thực hiện những công việc không đồng bộ, các thành phần giao diện người dùng(UI) cũng hoạt động không đồng bộ, cho nên không thể xác định được mã của bạn sẽ thực thi theo thứ tự nào.

Tóm lại, ứng dụng của bạn hoạt động tùy thuộc vào điều kiện dữ liệu bên ngoài, như dữ liệu đầu vào người dùng, điều kiện mạng internet hay các sự kiện hệ điều hành khác. Mỗi khi người dùng mở ứng dụng của bạn, thì nó sẽ hoạt động khác nhau tùy thuộc vào các yếu tố bên ngoài đó. Chúng ta không hề nói rằng việc viết chương trình không đồng bộ là không thể, vì công bằng mà nói các API của apple là mạnh mẽ so với các nền tảng khác cung cấp.

Vấn đề là mã không đồng bộ trở nên phức tạp do sự đa dạng các API của apple cung cấp trong framework(SDK) của họ như sau:

RxSwift 2: Khái niệm cơ bản về lập trình bất đồng bộ

Việc sử dụng delegate bạn cần áp dụng theo mẫu, hoặc có lúc bạn lại sử dụng closure thay thế, hoặc cũng có thể dùng notification center. Không có 1 quy tắc chung nào cho các API trên, do vậy việc đọc hiểu cũng như suy luận logic code trở nên khó khăn(thích cái gì thì dùng cái đó, không có nguyên tắc cho developer).

Để kết thúc phần này, chúng ta sẽ nghiên cứu 2 đoạn mã đồng bộ và bất đồng bộ sau:

Synchronous code(mã đồng bộ)

Để thực hiện thao tác cho 1 phần tử của 1 mảng thì bạn đã dùng rất nhiều lần. Đó là logic ứng dụng rất đơn giản và có 2 điều bất biến: 1 là các thành phần của mảng, và 2 là nó thực thi đồng bộ.

Hãy thử đoạn code sau trên playground(xcode):

var array = [1, 2, 3]
for number in array {
  print(number)
  array = [4, 5, 6]
}
print(array)

kết quả như sau:

1
2
3
[4, 5, 6]

Rõ ràng mặc dù có thay đổi giá trị của array trong vòng for, tuy nhiên kết quả array vẫn không thay đổi trong quá trình thực thi vòng for. Nó chỉ thực sự thay đổi khi thoát ra khỏi vòng for.

Asynchronous code(mã bất đồng bộ)

Hãy tải code ở link sau:

https://github.com/lexuanquynh/RxLearning.git

hoặc mở xcode và tạo 1 chương trình có dạng:

class ViewController: UIViewController {
    var array = [1, 2, 3]
    var currentIndex = 0
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
    
    @IBAction func onButtonTouched(_ sender: Any) {
        print(array[currentIndex])
        if currentIndex != array.count-1 {
            currentIndex += 1
        }
    }
}

Mỗi lần bấm vào nút button trên màn hình, thì index sẽ in ra và tăng lên 1 cho đến khi nó khác 3. Nếu bạn không thể hiểu đoạn code trên thì nên xem lại kiến thức căn bản về lập trình swift nhé.

Vấn đề là, giả sử có 1 đoạn code khác cũng sử dụng mảng array trên, và trong khi bạn còn chưa bấm nút để tăng index, thì array bị thay đổi giá trị hay index bị thay đổi giá trị, dẫn đến kết quả không còn là 1, 2, 3 nữa. Do vậy với đoạn code bất đồng bộ như vậy sẽ rất khó quản lý kết quả như mong muốn. May mắn thay, RxSwift lại giúp ta việc đó.

Vậy chúng ta hãy tiếp tục trong bài 3 để hiểu rõ hơn về nó nhé.

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

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

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

Mypy – là trai hay là gái?

Mypy - là trai hay là gái?

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

Vài ba năm gần đây, làng Vũ Trụ rộn lên trào lưu thêm “type” vào các ngôn ngữ lập trình dynamic typing.

Python đã già nhưng vẫn đú, cũng không bỏ lỡ cuộc đu trend này. Kết quả là ngày hôm nay, bạn đã có thể thêm type vào code Python – nếu muốn – như DropBoxInstagram… . Python chính thức thêm type hint/type annotation vào từ bản 3.5, chú ý rằng type này không ảnh hưởng/giúp đỡ gì bạn, nếu không sử dụng mypy hay các IDE.

  7 lý do bạn không nên sử dụng TypeScript
  Học kiến thức căn bản TypeScript chỉ trong 30 phút

Mypy là static type checker – tool giúp phân tích code (static analysis) dựa trên type annotation, dự án có sự tham gia của tác giả Python – Guido van Rossum, … và cả HVN

Thêm type để làm gì?

Các ngôn ngữ lập trình dynamic typing: Python, JavaScript, PHP, Ruby được ưa chuộng và luôn chiếm vị trí top các bảng xếp hạng ngôn ngữ lập trình trong những năm gần đây, hay Clojure, LISP, Erlang, Elixir… dù không lên đỉnh nhưng vẫn luôn hot. Dynamic typing giúp code trở nên ngắn gọn và linh hoạt. Vậy thêm type (kiểu) làm gì? không lẽ để dài hơn và bớt linh hoạt hơn?

Code dài dòng thêm thì rõ là không ai muốn, bởi nếu muốn đã quay về viết Java hết rồi, nhưng bớt linh hoạt hơn là một mục đích đáng xem xét.

Khi mọi thứ linh hoạt, nếu không tuân theo các quy tắc, không có kỷ luật cá nhân tốt, sẽ dẫn tới rối loạn. Hoặc khi hệ thống trở nên phức tạp hơn, nhiều tính năng phụ thuộc vào nhau, cũng dẫn tới việc không kiểm soát được.

Điều này sẽ dễ thấy hơn khi tham gia một dự án có nhiều lập trình viên. Một team 5 Python dev làm việc đã quen với nhau, code cùng chuẩn PEP8, cùng không thích OOP, … hay nói cách khác là một team thực thụ, sẽ code nhanh như tên lửa, vài giờ một tính năng, bay vèo vèo như YouTube dev .

Một nhóm người khác với 5 lập trình viên, học lập trình từ các nguồn khác nhau, trình độ khác nhau, thậm chí ngôn ngữ thành thạo cũng khác nhau, nếu làm cùng một dự án sẽ rất rối loạn. Có chỗ viết 3 class để gọi 1 function cho đúng chuẩn kế thừa, OOP của Java, có function viết theo kiểu recursive, có chỗ đặt tên biến một chữ cái, không viết function, một hàm main dài hàng trăm dòng, function mỗi nhánh trả về một kiểu khác, viết decorator chỉ để dùng 1 lần và thể hiện, sửa một function rồi các function khác hỏng theo… và hàng trăm thứ khác có thể sai hơn nữa. Một team như vậy phát triển sẽ rất chậm, nhiều bug, khó thêm tính năng, thậm chí gây mệt mỏi, stress khi phải làm việc với nhau. Giải pháp thì lại không thể là giải tán, cãi nhau, vậy làm gì?

Type là một phần giải pháp, type giúp đặt ràng buộc rõ ràng đầu vào đầu ra, đảm bảo một function luôn trả về cùng 1 kiểu dù ở nhánh nào. Function là kiến trúc cơ bản của 1 chương trình, một hệ thống. Khi function định nghĩa rõ ràng, các bên tương tác (gọi function) với nhau cũng sẽ rõ ràng. Nhân viên mới tuyển, sinh viên mới ra trường, vào sửa function trả về nhầm kiểu sẽ bị type bắt lại ngay.

  • Type là một thứ CÔNG CỤ giúp giảm sự linh hoạt của code, tăng thêm kỷ luật, đảm bảo code ít bị rối loạn hơn. Nếu code 1 mình, hay bạn chắc chăn mình và các đồng nghiệp đủ kỷ luật để không viết function trả về các kiểu khác nhau thì type cũng không cần thiết.
  • Type không nên là thứ can thiệp/cản trở nhiều vào mục đích của lập trình viên. Ta muốn có công cụ trợ giúp, chứ không muốn nó chống lại mình. Type dài dòng như của Java là một ví dụ điển hình khiến việc viết code cũng trở nên ngại.

Sử dụng mypy

Cài đặt

pip install mypy

Ví dụ 1 – đơn giản để bắt đầu

Ví dụ 1: đoạn code không có type:

File mypy_simple.py

def sum_of_three(a, b, c):
    result = a + b + c
    return result

def main():
    result = sum_of_three(6, 9, 6) * 2
    message = "The answer of life: " + result
    print(message)

main()

Chạy mypy:

$ mypy mypy_simple.py
Success: no issues found in 1 source file

Không có gì xảy ra, do không function/name nào có type annotation cả. Mặc định này giúp việc thêm type là tùy ý. Team có thể có người viết type, có người không ở các function khác nhau, đều OK. Nếu cực nghiêm khắc, có thể bật chế độ strict lên:

$ mypy --strict mypy_simple.py
mypy_simple.py:1: error: Function is missing a type annotation
mypy_simple.py:5: error: Function is missing a return type annotation
mypy_simple.py:5: note: Use "-> None" if function does not return a value
mypy_simple.py:6: error: Call to untyped function "sum_of_three" in typed context
mypy_simple.py:10: error: Call to untyped function "main" in typed context
Found 4 errors in 1 file (checked 1 source file)

Ở chế độ này, mọi thứ thiếu type annotation đều bị thông báo, đây chỉ là ví dụ cực đoan, phải tốn khá nhiều công sức và làm quen mới có thể bật chế độ này lên, vậy nên khó quá tạm thời bỏ qua.

Thêm type cho đoạn code trong ví dụ 1: với Python type annotation, ta thường chỉ thêm cho định nghĩa của các function, ít khi phải khai báo cho các variable. Ví dụ trên có 2 function, sau khi thêm type vào sum_of_three sẽ trông như sau:

def sum_of_three(a: int, b: int, c: int) -> int:
    result = a + b + c
    return result

def main() -> None:
    result = sum_of_three(6, 9, 6) * 2
    message = "The answer of life: {}".format(result)
    print(message)

3 argument đều có kiểu là : int-> int nói rằng function này trả về kiểu int. Chạy lại lệnh mypy

$ mypy mypy_simple.py
Success: no issues found in 1 source file

Vẫn trông như không có gì xảy ra, nhưng thật ra là có, do code của ta không có vấn đề gì nên mypy cũng không báo gì. Thử đổi trong function main, cộng kết quả của sum_of_three (kiểu int) với một str:

def main() -> None:
    result = sum_of_three(6, 9, 6) * 2
    message = "The answer of life: " + result
    print(message)

Nếu là lập trình viên JavaScript, bạn sẽ mong đợi một kết quả str bình thường, "The answer of life: 42", bởi JavaScript thuộc loại weak typing, còn Python là strong typing: int là int, str là str, không cộng trừ lẫn lộn.

Nếu là một PyMier chân chính, bạn sẽ nhận ra ngay đoạn code này gặp exception khi CHẠY THẬT, do cộng một str với một số int.

$ python mypy_simple.py
Traceback (most recent call last):
  File "mypy_simple.py", line 12, in <module>
    main()
  File "mypy_simple.py", line 8, in main
    message = "The answer of life: " + result
TypeError: must be str, not int
Command exited with non-zero status 1

Vậy ta chỉ biết, khi chạy thật, mà lúc ấy mới biết thì “toang” rồi. Có cách nào biết trước khi chạy không? Mypy sẽ giúp làm chuyện ấy:

$ mypy mypy_simple.py
mypy_simple.py:8: error: Unsupported operand types for + ("str" and "int")
Found 1 error in 1 file (checked 1 source file)

Chú ý: việc phân tích function main chỉ xảy ra khi nó có type annotation:

def main() -> None:

Function main không nhận argument, trả về kiểu None. Nếu bỏ -> None đi, mypy sẽ không kiểm tra function main.

Ví dụ 2 – các containers: list, tuple, dict, set

from typing import List, Tuple

def with_index(names: List[str]) -> List[Tuple[int, str]]:
    return [(idx, name) for idx, name in enumerate(names)]

def main() -> None:
    result = 21 * 2

    result = with_index(["Corona", "Tiger Nau", "TrucBach"])
    print(result)

main()

Chỉ có str, int, float, bool, None là các kiểu dùng ngay. Với list, tuple, set, dict, cần phải import type tương ứng từ standard lib typing, các type viết Hoa chữ cái đầu. Có thể khai báo qua loa def with_index(names: List) -> List: hoặc chi tiết như trong ví dụ 2.

$ mypy mypy_simple.py
mypy_simple.py:11: error: Incompatible types in assignment (expression has type "List[Tuple[int, str]]", variable has type "int")

Lỗi này thường gặp, do chuyện dùng chung tên result, mypy lần đầu gặp sẽ nghĩ result là kiểu int, qua dòng tiếp theo lại suy luận nó được gán giá trị kiểu List[Tuple[int, str]]. Việc dùng một biến để chỉ tới nhiều kiểu khác nhau không hiếm trong dynamic typing, nhưng là chuyện không thể trong các ngôn ngữ static typing. Cách giải quyết chuẩn nhất là đổi tên biến.

Ví dụ 3 – các object phức tạp, thư viện bên ngoài

Với các lập trình viên Python, type là một thứ lạ, nên không phải dẽ gì ngồi đọc ngay ra kiểu của resp sau đây là gì mà gõ vào:

from typing import Any
import requests

def process_response(resp: Any, msg: str = 'From: ') -> str:
    return msg + resp.json()['origin']

r = requests.get('https://httpbin.org/ip')
output = process_response(r)# + 10
print(output)

Any giúp điền vào chỗ trống khi không biết kiểu gì, đồng nghĩa với việc mất đi một chút bảo vệ của mypy do mypy sẽ cho phép gọi function process_response với argument đầu tiên thuộc bất kỳ kiểu nào.

msg: str = 'From: ' là argument msg, kiểu str, với giá trị default From:.

$ python mypy_simple.py
From: 111.212.107.29

Có một cách khác để nhờ mypy tìm giúp kiểu của resp, đó là khai báo sai kiểu, thay Any thành int, chạy mypy sẽ thấy:

$ mypy mypy_simple.py
mypy_simple.py:5: error: "int" has no attribute "json"
mypy_simple.py:8: error: Argument 1 to "process_response" has incompatible type "Response"; expected "int"
Found 2 errors in 1 file (checked 1 source file)

Vậy kiểu của resp cần khai báo là Response, đầy đủ là requests.models.Response có thể tìm ra bằng cách print(type(r))

Ví dụ 4 – function nhận vào nhiều kiểu

Cũng có lúc, ta muốn chủ ý nhận vào nhiều loại input khác kiểu, nhưng chỉ giới hạn trong 1 nhóm, ví dụ như int, str, float, chứ không phải dict hay list, nếu dùng Any thì dễ dãi quá:

def any_number(n: int) -> str:
    return "This is {}".format(n)

any_number(6)
any_number("9")

### mypy check
error: Argument 1 to "any_number" has incompatible type "str"; expected "int"

Giải pháp là dùng Union.

from typing import Union

def any_number(n: Union[int,float,str]) -> str:

Các kiểu type khác: https://mypy.readthedocs.io/en/stable/kinds_of_types.html đáng chú ý như Optional khi có thể trả về None, hay Callable là kiểu cho function.

Stub

import boto3
mypy mypy_simple.py
mypy_simple.py:1: error: No library stub file for module 'boto3'
mypy_simple.py:1: note: (Stub files are from https://github.com/python/typeshed)

Sau khi Python chính thức thêm type notation, không có nghĩa là các core developer sẽ đi sửa hàng loạt các file thư viện đã chạy ổn định vài chục năm để thêm type. Thay vào đó, họ tạo ra các stub file. stub file là file chứa type annotation của các function trong library. Nó tương tự header file trong C/C++.

Ví dụ itertools

Các stub file của Python standard lib được gom lại tại python/typeshed.

Các thư viện bên ngoài thường ít khi có sẵn stub file, Ví dụ như boto3 – thư viện cực kỳ phổ biến – và chính thức để làm việc với API của AWS, tới nay vẫn chưa có stub file chính thức từ AWS. Nên để đơn giản, thay vì phải chiến đấu với type, ta có thể bỏ qua:

$ mypy --ignore-missing-import .

hay tự tạo stub như htlcnn. Xem hướng dẫn tự tạo stub file tại mypy wiki

Những vấn đề type giúp giải quyết

  • Kiểm tra kiểu, đảm bảo function trả về thống nhất một kiểu, nhận được đúng kiểu đầu vào.
  • Giúp nhìn vào dòng def (thuật ngữ chính xác: function signature) là biết luôn cần gọi với argument nào, trả về kiểu gì.

Những vấn đề type KHÔNG giúp giải quyết

  • Thay cho unittest: unittest dùng để kiểm tra logic chứ không phải để kiểm tra kiểu. Do không có ràng buộc về kiểu, nên trong unittest thường kiểm tra cả kiều của đầu ra function, việc này hoàn toàn bị loại bỏ khi dùng mypy.
  • Làm việc nhóm không hiệu quả: type chỉ là một phần giải pháp giúp xóa bớt sự chênh lệch trình độ giữa các lập trình viên. Bạn nên tìm cách đào tạo, chia sẻ kinh nghiệm, luyện tập cùng các đồng nghiệp thì hơn.

Hành động của chúng ta

Thêm ngay dòng sau vào Makefile, hay hệ thống CI của bạn, ngay sau pep8, flake8 hay pylint:

mypy --ignore-missing-import .

Kết luận

Type là một công cụ tốt cho các Pythonista như pylint pep8, giúp phát triển các dự án lớn hơn, nhiều người tham gia một cách dễ dàng hơn, trong khi việc đầu tư thì không có gì to tát cả – chỉ việc share bài viết này.

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 Việc làm ngành cntt hấp dẫn trên TopDev

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Bài viết được sự cho phép của tác giả Trần Hữu Cương

CygWin là gì?

Cygwin là một bộ công cụ mã nguồn mở (GNU) dành cho Windows.

Cygwin cung cấp môi trường * nix (Unix) vào Windows bằng cách mô phỏng nhiều chi tiết nhỏ mà các hệ điều hành dựa trên Unix cung cấp. Do đó ta có thể chạy một số lệnh Unix trên Windows thông qua Cygwin.

Cygwin không phải là một trình biên dịch C/C++ (khả năng biên dịch C/C++ chỉ là một phần của nó). Chính vì CygWin có khả năng biên dịch C/C++ nên khi lập trình C/C++ người ta hay cài CygWin và coi nó như một trình compiler C/C++.

  10 điều bạn có thể làm với Linux mà bạn không thể làm với Windows
  Hướng dẫn cấu hình compiler MinGW, Cygwin cho Dev C++

Cài đặt CygWin trên hệ điều hành Windows

Trong ví dụ này mình cài đặt CygWin trên Windows 10.

Download bản cài đặt cygwin tại:  https://cygwin.com/install.html. Tùy vào máy của mình mà bạn download bản 64bit hay 32bit nhé.

Máy mình là Windows 64bit nên mình sẽ tải bản CygWin 64bit

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Click đúp vào file .exe vừa tải về

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Chọn thư mục cài CygWin:

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Chọn thư mục sẽ chứa các file tải về trong quá trình cài đặt CygWin:

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Chọn một site bất kỳ:

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Phần packages, ngoài các package mặc định được cài, bạn có thể chọn thêm các packages khác:

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Ví dụ mình muốn cài thêm package unzip và zip (chạy lệnh unzip và zip trên command line)

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows  CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Kết quả sau khi cài đặt CygWin thành công:

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Tìm việc làm C++ nhanh chóng trên TopDev

Tạo biến môi trường cho CygWin

Tiếp theo, thêm thư mục vừa cài đặt CygWin vào biến môi trường của Windows (để bạn có thể chạy các lệnh của CygWin bất kỳ folder nào)

Mở My Computer , click chuột phải vào khoảng trống và chọn Properties

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Chọn Tab Advanced và click Enviroment Variables

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Click vào phần Path và chọn Edit

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Click New và thêm folder bin của thư mục cài MinGW sau đó click OK.

(Bên trên mình cài MinGW ở C:\cygwin64 nên thư mục bin sẽ là C:\cygwin64\bin)

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Kiểm tra version của bản Cygwin vừa cài bằng lệnh:

  • cygcheck vesion

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Ở bên trên mình có cài đặt thêm pakage unzip, nên mình có thể sử dụng lệnh unzip bên trong cửa sổ dòng lệnh:

CygWin là gì? Cài đặt Compiler C/C++ CygWin trên Windows

Okay, Done!

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

Một vài điều cần lưu ý khi bạn làm việc với JS

Một vài điều cần lưu ý khi bạn làm việc với JS

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

Array.sort() cho kết quả khác nhau trên các trình duyệt khác nhau

Khi bạn cần sort các phần tử trong một mảng, khả năng rất cao là bạn sẽ sử dụng callback như: sort((x, y) => x < y).

  10 câu hỏi javascript để nâng cao trình độ
  10 trình quản lý file hàng đầu trong JavaScript

Đây là kết quả của Chrome và Firefox

Một vài điều cần lưu ý khi bạn làm việc với JS

Hàm callback chúng ta truyền vào phải return một trong ba giá trị 1, 0, -1, vì chúng ta đang return một giá trị boolean, nên sẽ tùy vào trình duyệt quyết định

Sử dụng JSON.stringify với tham số

Là một web developer, ít nhất một lần trong đời bạn sẽ sử dụng đến hàm JSON.stringify. Nhưng bạn có biết hàm này còn một tham số thứ 2 có thể truyền vào? Nó sẽ được sử dụng như một danh sách whitelist khi parse (chỉ có những giá trị key nằm trong whitelist mới được parse)

Một vài điều cần lưu ý khi bạn làm việc với JS

Không chỉ giới hạn là một mảng, có thể truyền một function để validatereplaceparse cặp keyvalue nhận được

Một vài điều cần lưu ý khi bạn làm việc với JS

Array.filter() không làm việc với Promise

Một công việc cũng hay sử lý trên mảng: thực hiện một số xử lý async trên các phần tử trong mảng, lặp qua các phần tử để xử lý dữ liệu rồi filter những phần tử không mong muốn.

Ví dụ, để kiểm tra user có quyền thực hiện một số tính năng nào đó không, chúng ta cần kiểm tra tất cả các giá trị trong mảng permissions

Một vài điều cần lưu ý khi bạn làm việc với JS

Một vài điều cần lưu ý khi bạn làm việc với JS

Code trên hoàn toàn hợp lý và đúng 100%

Tính huống tiếp theo, nếu bên trong hàm userCan chúng ta có một xử lý async?

Một vài điều cần lưu ý khi bạn làm việc với JS

Không chạy đúng đâu. Để sửa lại cho nó chạy đúng, chúng ta phải dùng map trước khi dùng đến filter

Một vài điều cần lưu ý khi bạn làm việc với JS

Nullish vs OR

Ai cũng biết viết OR

const foo = buzz || 'fallback'

Trong trường hợp bạn muốn foo bằng 0 khi buzz bằng 0, nói cách khác 0 vẫn được xem là một giá trị hợp lệ thì cách viết trên toang.

Một vài điều cần lưu ý khi bạn làm việc với JS

Nullish tương đối mới và được hỗ trợ từ TypeScript 3.7, các phiên bản trình duyệt mới, cũng nên lưu ý điểm này nhé.

Promise constructor anti-pattern

Tạo một Promise không vì một lý do gì cả.

Nếu bạn có một xử lý async thì bản chất nó đã return một promise, việc bạn new Promise chẳng có ý nghĩa gì cả

Một vài điều cần lưu ý khi bạn làm việc với JS

Chỉ đơn giản return fetchThing() là được (fetchThing là một async function)

Một vài điều cần lưu ý khi bạn làm việc với JS

Catch await error

Nếu sử dụng Promise bạn sẽ dùng then và catch, còn dùng async/await bạn sẽ dùng try/catch như thế này

Một vài điều cần lưu ý khi bạn làm việc với JS

Một cách thần kỳ chúng ta vẫn có thể dùng .catch ngay trên await

Một vài điều cần lưu ý khi bạn làm việc với JS

Nếu ngồi chiêm nghiệm thật kỹ bạn sẽ hiểu vì sao chúng ta vẫn viết được như vậy, gợi ý await là một cách viết cũng dựa trên Promise mà ra

Optional chain trên function

Optional chain trong object không xa lạ, nhưng optional chain trên function thì bạn có dùng chưa?

Một vài điều cần lưu ý khi bạn làm việc với JS

Một tình huống bạn sẽ sử dụng rất nhiều trong React là callback prop. Sẽ không còn cần phải viết onClick={onClick && () => onClick(param)}

10 Things 2020 has taught me

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

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

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

Thiết kế Messaging Service WhatsApp – P2

Thiết kế Messaging Service WhatsApp

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

Tiếp theo phần 1 về thiết kế hệ thống Messaging Service WhatsApp. Bài viết thứ hai này sẽ cho ta một cái nhìn toàn diện và sâu hơn về thiết kế tổng quan đã trình bày ở phần trước.

Nội dung này có thể xem là High Level Design cho System. Trình bày và giải thích cụ thể hơn cho từng thành phần trong hệ thống.

  Discord đã lưu trữ hàng tỉ messages mỗi ngày như thế nào
  Kiểm tra HTML5 validation message

1. Quay lại với hệ thống

Quay lại với hệ thống Messaging Service WhatsApp, ở phần 1 ta đã có cái nhìn tổng quan về các thành phần trong hệ thống.

  • Load Balancer
  • App Servers
  • Memcached
  • APN/GCM
  • Job Queue
  • Workers
messaging-service-design-system

Tiếp tục đi sâu hơn nhằm trả lời các câu hỏi có thể phát sinh trong thực tiễn khi triển khai hệ thống.

2. Chi tiết Messaging Service WhatsApp

Bắt đầu từ gốc tới ngọn, ta sẽ xem xét Database Model trước. Ở hệ thống chat này, ta có thể sử dụng NoSQL, có 2 phương án để lựa chọn:

2.1 Database Model

  • Thứ nhất là Wide-Column Store. Loại này tương tự như HBase và Cassandra
  • Thư hai là NoSQL Key Value Stores, kiểu lưu trữ này chỉ có key và value, phân tán trên nhiều database nhỏ (Distributed Database). Tốt cho scaling, tiêu biểu có thể chọn là DynamoDB

Schema User như sau:

Java
- id

- username

- password

- device_OS // Xác định service gửi notification

- device_token // Dùng cho Notification

- list<unread_messages>

Lưu ý là bảng User cần có thêm 2 cột là device_OS và device_token. Device_OS cho ta biết nên sử dụng Apple APNS hay Google’s GCM. Device_token để làm việc với các service.

2.2 Distributed Cache

Distributed Cache giúp cải thiện hiệu năng hệ thống, với hệ thống chat, số lượng tin nhắn chờ đọc (unread mesage) rất nhiều. Nếu chỉ giữ ở Distributed Database sẽ dẫn tới database truy xuất quá nhiều lần

Java

- user_id

- list<unread_messages>

List user_id là tương tự với list_user ở table user trong database NoSQL. Sau khi user đã đọc message, ta sẽ xóa nó khỏi Cache. Cache thông thường sẽ được lưu ở RAM, dẫn tới việc không thể lưu quá nhiều. Sau khi đã đọc thì sẽ xóa nó đi, hình thức tương tự như Queue First-In-First-Out (FIFO)

3. Phân tích tính năng – Feature Walkthrough

Sau khi đã cái nhìn toàn diện về các thành phần trong hệ thống, ta sẽ tìm hiểu tiếp về các Feature (tính năng). Hệ thống chat tất nhiên những tính năng quan trọng nhất sẽ là

  • Sending a Message – Gửi tin nhắn
  • Receiving a Message – Nhận tin nhắn

3.1 Gửi tin nhắn

Khi có request từ phía client gửi tin nhắn. Ta có thể hiện thực method sau

Java

sendMessage(string message_text, int sender_id, int reciever_id)

AppServer sẽ handle sender_id (người gửi) và receicer_id (người nhận). Ngoài ra, AppServer cũng đảm nhận nhiệm vụ cung cấp time_stamp (thời gian gửi). Thành phần có thể được sử dụng làm key trong table, do thời gian không bao giờ trùng lặp nhau.

Thuộc tính của message sẽ bao gồm: <message_text, sender_id, timestamp>. App Server lúc này sẽ thêm nội dung message vào 2 chỗ:

  • The Distributed Cache – in User reciever_id’s list of unread messages.
  • The NoSQL Store – Again, in User reciever_id’s list of unread messages.

Sau khi đã lưu trữ message, sẽ tiếp tục gửi request notification tới APNS/GCM (tùy thuộc vào device_OS). Phần tính năng gửi tin nhắn xem như xong, tiếp tục là Receiving a Message – Nhận tin nhắn

3.2 Nhận tin nhắn

Khi nhận được notification, click vào notification sẽ open app và gọi tới server để lấy unread message. Nội dung request chắc chắn sẽ cần tới receiver id (người nhận tin nhắn).

Java

getUnreadMessages(int reciever_id)

App Server sẽ thực hiện query từ cache với reciever_id, nếu nội dung tìm thấy, thực hiện trả response cho device. Nếu trong cache không tồn tại tin nhắn, App Server sẽ thực hiện query tới NoSQL Database (trả về nếu tồn tại).

Một lưu ý nhỏ về timestamp, timestamp sẽ lấy giờ ở Server, không thể sử dụng timestamp ở phía device do thiết lập giờ ở phía client có thể sai. Hoặc cũng có trường hợp timezone của device khác nhau giữa các quốc gia.

Sau khi đã nhận được tin nhắn, phía server sẽ thực hiện xóa unread message từ cache thông qua một job bất đồng bộ (asynchronous job).

App cũng sẽ không hiển thị status “sent” cho tới khi nó được gửi thành công tới Server

3.3 Websocket

Trường hợp sử dụng WebSocket, ta có thể thiết lập connect alive 24/7 từ phía client tới server. Tuy nhiên, không phải device nào cũng online liên tục, nên nếu giữ kết nối liên tục sẽ dẫn tới lãng phí tài nguyên

  • One way to do this is to keep a WebSocket connection alive 24/7 for each device. Nếu giữ kết connection 24/7, sẽ lãng phí tài nguyên.
  • Another way is to set up the WebSocket connection as soon as the messaging app becomes active, i.e, the user opens the app. Cách khác là chỉ mở connection khi messaging app được bật trở lại.

Nếu User A (Server X) muốn nhắn tin cưa cẩm User B (connect tới Server Y), ta sẽ cần TCP connect giữa 2 server.

System design lúc này cần bổ sung thêm kết nối giữa các server với nhau.

Trường hợp một Client lost connection tới Server (thực tế diễn ra thường xuyên). Distributed Cache in memory lúc này trở nên hữu dụng, unread message vẫn được giữ ở đây để gửi cho user khi user online trở lại.

Trời má, viết hoài không hết, vậy vẫn phải cần Part 3 để trả lời thêm cho một số câu hỏi:

  • Which server will send Push Notifications? – Server nào sẽ chịu trách nhiểm đẩy noti đi
  • Will servers send entire messages to each other? – Có cần phải gửi tất cả tin nhắn đi không?
  • How to handle Chat Server failures? – Xử lí chat server thế nào khi failures?

4. Tham khảo

Thank you again for read all part of article – Have a great job – Happy coding!

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

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

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

JavaScript Runtime Environment là gì?

JavaScript Runtime Environment là gì?

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

Một khái niệm, thành phần khá quan trọng trong lập trình JavaScript đó là JavaScript Runtime Enviroment.

JavaScript Runtime Environment là gì?

Trước tiên, mình giải thích lại cách hoạt động của JavaScript. JavaScript khác với các ngôn ngữ biên dịch như C/C++. JavaScript chạy trong một container – container này chính là một phần mềm thực hiện đọc code JavaScript và thực thi nó.

Phần đọc code và chuyển thành các đoạn mã để container có thể hiểu chính là nhiệm vụ của JavaScript Engine.

Phần thực thi các đoạn mã đó lại thuộc về JavaScript Runtime Enviroment. JavaScript Runtime Enviroment cung cấp các đối tượng, môi trường để JavaScript giao tiếp với máy tính.

  Các thuật toán sắp xếp phổ biến trong JavaScript

Ví dụ Chrome Browser và Node.js đều sử dụng chung JavaScript Engine là V8. Tuy nhiên JavaScript Runtime Enviroment trong 2 trường hợp này lại khác nhau:

  • Chrome Browser sử dụng các đối tượng như window, DOM object hay các method như AJAX… để giao tiếp với network và hiển thị.
  • Node.js lại cung cấp các thư viện cho phép truy cập trực tiếp các file trên máy tính, truy cập database, tiến trình (Chrome Browser không làm được các việc này)

Ví dụ: dưới đây chính là JavaScript Runtime Enviroment hoạt động trên Chrome Browser:

JavaScript Runtime Environment là gì?

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

  JavaScript Runtime Environment là gì?
thêm một lần nào nữa”]

Xem thêm Javascript Jobs hấp dẫn trên TopDev

RxSwift 5: Cài đặt RxSwift

RxSwift 5: Cài đặt RxSwift

Bài viết được sự cho phép của tác giả Lê Xuân Quỳnh

RxCocoa

RxSwift triển khai các hàm tương tự của Cocoa. RxCocoa hỗ trợ tất cả các API của UIKit và Cocoa. Ngoài ra RxCocoa còn có các tính năng mở rộng, và bạn cũng có thể tự viết hàm mở rộng cho nó.

Tuyển swift lương cao hấp dẫn cho bạn

  RxSwift 10: Làm việc với PublishSubjects
  RxSwift 3: Thuật ngữ về lập trình bất đồng bộ (Asynchronous programming glossary)

Ví dụ về Rx hỗ trợ lắng nghe sự kiện nút switch:

toggleSwitch.rx.isOn
  .subscribe(onNext: { enabled in
    print( enabled ? "it's ON" : "it's OFF" )
  })

trong sự kiện onNext, mỗi khi có sự thay đổi trạng thái của nút mà hiển thị nó đang bật hay tắt, hoặc xử lý tùy ý theo logic app. RxCocoa cung cấp rx.isOn để bạn có thể đăng ký lắng nghe sự kiện đó.

Tương tự, RxCocoa cung cấp API cho nhiều control khác như UITextField, URLSesion, UIViewController…

Cài đặt RxSwift

RxSwift có sẵn trên github tại đường dẫn:

https://github.com/ReactiveX/RxSwift.

RxSwift được phát hành dưới giấy phép MIT, nói đơn giản là bạn có quyền làm gì tùy ý với source code, với điều kiện bạn phải thông báo quyền phải được bao gồm trong các ứng dụng bạn phân phối. Có rất nhiều thứ cần khám phá trong repository này, bao gồm thư viện RxSwift và RxCocoa, nhưng bạn vẫn có thể tìm thấy RxTest và RxBlocking trong đó, cho phép bạn viết unit test. Bên cạnh mã nguồn tuyệt vời, bạn sẽ thấy Rx.playground, trình diễn nhiều toán tử của nó, hay RxExample, chứa nhiều ví dụ trong thực tế. Có nhiều cách để cài đặt RxSwift:

  1. Cài đặt bằng CocoaPods

B1: Đầu tiên các bạn tạo project của mình.

B2: init pod file bằng lệnh: pod init.

Trường hợp nếu máy bạn chưa cài CocoaPod thì gõ lệnh này trước:

sudo gem install cocoapods

B3: sửa Podfile thành:

# Podfile
use_frameworks!

target 'YOUR_TARGET_NAME' do
    pod 'RxSwift', '6.0.0-rc.2'
    pod 'RxCocoa', '6.0.0-rc.2'
end

# RxTest and RxBlocking make the most sense in the context of unit/integration tests
target 'YOUR_TESTING_TARGET' do
    pod 'RxBlocking', '6.0.0-rc.2'
    pod 'RxTest', '6.0.0-rc.2'
end

B4: Gõ pod install và thư viện đã cài xong.

2. Cài đặt RxSwift bằng Carthage

B1: Cài đặt Carthage theo hướng dẫn:

https://github.com/ Carthage/Carthage#installing-carthage

B2: Thêm file mới tên là Cartfile vào project của bạn, và thêm dòng:

github "ReactiveX/RxSwift" "6.0.0-rc.2"

B3: Gõ lệnh:

carthage update

Cộng đồng RxSwift

Cộng đồng hiện tại đang hoạt động rất sôi nổi, nhiệt tình và giúp đỡ nhau. Bạn có thể tham gia cộng đồng tại đường dẫn:

http://community.rxswift.org

Nhiều thư viện mới mọc lên như nấm sau mưa, xem tại đây:

https://github.com/RxSwiftCommunity

Tiếp theo là bạn có thể tham gia chat với các developer khác tại Slack:

http://rxswift-slack.herokuapp.com

Tổng kết

Vậy qua 5 bài đầu tiên, bạn đã có 1 cái nhìn cơ bản về RxSwift. Bạn đã tìm hiểu về sự phức tạp của lập trình bất đồng bộ, chia sẻ state, tạo ra side effects.

Bây giờ bạn đã biết RxSwift là giải pháp tuyệt vời để giải quyết các khó khăn đó. Chúng ta sẽ cùng nhau đi sâu vào từng phần của RxSwift trong bài tiếp theo. Cùng nghiên cứu về Observables.

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

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

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

Lib requests có gì hay mà dùng thay urllib

Lib requests có gì hay mà dùng thay urllib

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

Python là một ngôn ngữ già, có thể bạn chưa biết, Python tuổi dê Python ra đời từ thời mới có HTTP, và nổi tiếng là hỗ trợ tận răng, nên không có gì lạ nếu Python có kèm sẵn thư viện standard để thực hiện HTTP request với tên urllib.

Vậy nhưng khi lên mạng tìm kiếm hay hỏi quanh đây: dùng gì để gọi HTTP trong Python?, câu trả lời phần lớn đều là cài: pip install requests.

  Biến toàn cục (global), biến cục bộ (local), biến nonlocal trong Python
  11 tip học Python dành cho các “newbie”

Requests không phải có từ ngày Python xuất hiện, nhưng vào thời Python 2.6 2.7 (cỡ 2012-2013), requests đã rất phổ biến, ví dụ như câu trả lời trên StackOverFlow năm 2013.

Requests (có chữ s) xuất hiện với một API cực kỳ thân thiệt, với motto (khẩu hiệu): Python HTTP for Humans do urllib có sẵn trong Python2 quá rắc rối. API của requests nổi tiếng đến mức gần như ngôn ngữ lập trình nào cũng có một thư viện “nhái” requests của Python, nó quá đơn giản, tới mức … trước đây không thư viện nào từng làm vậy.

(API của thư viện là các function mà thư viện đó public cho người dùng sử dụng, ví dụ requests có: requests.get, requests.post.)

requests logo

Sau gần chục năm phát triển, requests giờ đã nằm dưới mái nhà Python Software Foundation.

Với các tính năng được quảng cáo ở bản v1.0.0, cuối năm 2012

    International Domains and URLs
    Keep-Alive & Connection Pooling
    Sessions with Cookie Persistence
    Browser-style SSL Verification
    Basic/Digest Authentication
    Elegant Key/Value Cookies
    Automatic Decompression
    Unicode Response Bodies
    Multipart File Uploads
    Connection Timeouts
    Thread-safety

Có thể dễ đoán rằng những tính năng được quảng cáo trên chính là những gì urllib Python thời đó chưa hỗ trợ (trong Python còn có cả thư viện tên urllib2… để thêm phần phức tạp). Nhưng với Python 3.5 trở đi, rất nhiều trong số trên đã được hỗ trợ trong urllib.

Còn đây là các tính năng được quảng cáo ở phiên bản mới nhất:

    Keep-Alive & Connection Pooling
    International Domains and URLs
    Sessions with Cookie Persistence
    Browser-style SSL Verification
    Automatic Content Decoding
    Basic/Digest Authentication
    Elegant Key/Value Cookies
    Automatic Decompression
    Unicode Response Bodies
    HTTP(S) Proxy Support
    Multipart File Uploads
    Streaming Downloads
    Connection Timeouts
    Chunked Requests
    .netrc Support

Nếu bạn đọc các tính năng này mà không hiểu gì, thì nó chỉ chứng minh một điều là HTTP là một giao thức rất lằng nhằng và phức tạp. Đáng kể nhất có:

Changed in version 3.4.3: This class now performs all the necessary certificate and hostname checks by default. To revert to the previous, unverified, behavior ssl._create_unverified_context() can be passed to the context parameter.

  • Connection Pooling: bình thường khi viết code truy cập vào 1 website, ta có thể nghĩ đơn giản là requests.get rồi lấy kết quả là xong chuyện, hết phiên. Nếu muốn truy cập trang khác cùng website đó, ta lại requests.get để truy cập mới. Phía dưới requests.get thực hiện tạo 1 TCP connection, sau đó mới gửi HTTP request qua connection này. Việc tạo connection là công việc khá tốn kém (CPU, thời gian), đặc biệt với HTTPS, tạo SSL connection còn tốn hơn nhiều lần. Do vậy, để tăng hiệu năng, requests sẽ tự giữ lại connection và dùng lại để truy cập website nếu như các yêu cầu sau đó cùng website, khác page. Xem code tại adapters.py.

Việc này ảnh hưởng tới hiệu năng, nhưng không ảnh hưởng gì nếu bạn chỉ gọi 1 request tới mỗi website.

Đọc code requests

Lib requests thuộc loại nhỏ, tổng cộng 5000 dòng gồm rất nhiều comment. Nó tận dụng các thư viện ngoài khác thay vì tự làm tất cả: urllib3 để thực hiện connection pooling, thực hiện HTTP requests, dùng certifi để cung cấp các SSL certificate mới nhất như các trình duyệt.

$ wc -l *| sort -nr
wc: __pycache__: Is a directory
   5049 total
    982 utils.py
    954 models.py
    767 sessions.py
    549 cookies.py
    533 adapters.py
    305 auth.py
    161 api.py
    131 __init__.py
    126 exceptions.py
    123 status_codes.py
    119 help.py
    105 structures.py
     72 compat.py
     42 _internal_utils.py
     34 hooks.py
     18 certs.py
     14 __version__.py
     14 packages.py

Phần API đơn giản lừng danh nằm trong file api.py, trích bỏ comment:

from . import sessions

def request(method, url, **kwargs):
    # By using the 'with' statement we are sure the session is closed, thus we
    # avoid leaving sockets open which can trigger a ResourceWarning in some
    # cases, and look like a memory leak in others.
    with sessions.Session() as session:
        return session.request(method=method, url=url, **kwargs)

def get(url, params=None, **kwargs):
    kwargs.setdefault('allow_redirects', True)
    return request('get', url, params=params, **kwargs)

def options(url, **kwargs):
    kwargs.setdefault('allow_redirects', True)
    return request('options', url, **kwargs)

def head(url, **kwargs):
    kwargs.setdefault('allow_redirects', False)
    return request('head', url, **kwargs)

def post(url, data=None, json=None, **kwargs):
    return request('post', url, data=data, json=json, **kwargs)

def put(url, data=None, **kwargs):
    return request('put', url, data=data, **kwargs)

def patch(url, data=None, **kwargs):
    return request('patch', url, data=data, **kwargs)

def delete(url, **kwargs):
    return request('delete', url, **kwargs)

urllib3

urllib3 là dependency quan trọng của requests, nó đảm nhận những công việc nặng nề:

urllib3 brings many critical features that are missing from the Python standard libraries:

Thread safety.
Connection pooling.
Client-side SSL/TLS verification.
File uploads with multipart encoding.
Helpers for retrying requests and dealing with HTTP redirects.
Support for gzip and deflate encoding.
Proxy support for HTTP and SOCKS.

Code mẫu:

>>> import urllib3
>>> http = urllib3.PoolManager()
>>> r = http.request('GET', 'http://httpbin.org/robots.txt')
>>> r.status
200
>>> r.data
'User-agent: *\nDisallow: /deny\n'

urllib

urllib và urllib2 thời Python2.7 là những em gái dính lời nguyền mà ai cũng muốn tha thứ. Nhưng ở Python 3.6+, việc dùng urllib không còn quá phức tạp, hãy coi nó như 1 file, nhớ đóng file, hoặc dùng with.

urllib đã kiểm tra SSL certificate

Python 3.6.9 (default, Nov  7 2019, 10:44:02)
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import urllib.request
>>> from urllib.request import urlopen
>>> with urlopen("https://dantri.com") as f:
...     content = f.read()
...     print(content[:100])
...
Traceback (most recent call last):
  File "/usr/lib/python3.6/urllib/request.py", line 1318, in do_open
    ...
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)
...
    raise URLError(err)
urllib.error.URLError: <urlopen error [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)>

Kết quả tương tự khi dùng requests do URL https://dantri.com SSL certificate đẫ hết hạn Expire: January 19, 2020

>>> import requests
>>> requests.get("https://dantri.com")
Traceback (most recent call last):
  File "/home/hvn/py3/lib/python3.6/site-packages/urllib3/connectionpool.py", line 672, in urlopen
    ...
  File "/usr/lib/python3.6/ssl.py", line 689, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:852)

urllib redirect ngon lành

urllib với JSON API

>>> import json
>>> from urllib.request import urlopen
>>> with urlopen("https://httpbin.org/ip") as f:
...     content = json.load(f)
...     print(content)
...
{'origin': '171.247.169.69'}

>>> import json
>>> from urllib.request import Request, urlopen
>>> with urlopen(
...   Request("https://httpbin.org/post", method="POST",
...           data=json.dumps({"name": "Pymi", "since": 2015}).encode('utf-8'),
...           headers={'Content-Type': "application/json"})
...           ) as resp:
...     print(json.load(resp)['json'])
...
{'name': 'Pymi', 'since': 2015}

Tra cứu thông tin COVID-19

>>> with urlopen("https://corona-stats.online/IT") as f:
...     print(f.read().decode("utf-8"))
...
╔═══════╤═══════╤═══════════╤═══════════╤════════╤════════╤═════════════╤═════════════╤═════════╤══════════╗
        State  Confirmed  Recovered  Deaths  Active  Mortality %  Recovered %  1 Day   1 Week  
╟───────┼───────┼───────────┼───────────┼────────┼────────┼─────────────┼─────────────┼─────────┼──────────╢
 Italy  Total     31,506      2,941   2,503  26,062         7.94         9.33  3,526   21,357  
╚═══════╧═══════╧═══════════╧═══════════╧════════╧════════╧═════════════╧═════════════╧═════════╧══════════╝

Stay safe. Stay inside.

Code: https://github.com/sagarkarira/coronavirus-tracker-cli
Twitter: https://twitter.com/ekrysis

Last Updated on: 18-Mar-2020 16:03 UTC

Hành động của chúng ta

Có thể dùng urllib khi script/chương trình chỉ truy cập mỗi website một lần, dùng trong các script ngắn, hay khi không tiện cài requests. Nhớ sử dụng requests Session khi truy cập 1 website nhiều lần để tăng hiệu năng.

Kết luận

Requests thành công vì sự đơn giản không thể hơn của nó, chứ không phải vì kỹ thuật cao siêu phức tạp.

A designer knows he has achieved perfection not when there is nothing left to add, but when there is nothing left to take away. The New Hacker’s Dictionary – Eric S. Raymond,

Nhớ mặc định là dùng requests, nhưng không bị sốc khi thấy người ta dùng urllib.

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 Việc làm Developer hấp dẫn trên TopDev

RxSwift 4: nền tảng RxSwift

RxSwift 4: nền tảng RxSwift

Bài viết được sự cho phép của tác giả Lê Xuân Quỳnh

Lập trình reactive không phải là một khái niệm mới, nó đã tồn tại trong thời gian khá dài. Tuy nhiên không phải lập trình viên nào cũng muốn học về nó. Nếu bạn đang đọc bài này, bạn ít nhiều quan tâm đến nó. Khi đến 1 trình độ nào đó, bạn sẽ thấy các vấn đề xoay quanh lập trình tuần tự liên quan đến tính bất đồng bộ của chương trình, từ phía web, ứng dụng, server. Do vậy nhu cầu xử lý tính bất đồng bộ của chương trình là cần thiết.

Tìm công việc swift lương cao cho bạn

  RxSwift 10: Làm việc với PublishSubjects
  RxSwift 3: Thuật ngữ về lập trình bất đồng bộ (Asynchronous programming glossary)

Lịch sử ra đời từ 1 nhóm của Microsoft, muốn xử lý các vấn đề này. Năm 2009 họ tạo ra 1 nền tảng cung cấp cho .Net, gọi là Rx. Sau này nó được open source, các bạn có thể xem thêm tại đây:

http://reactivex.io.

Biểu tượng cho dự án Rx có tên là Volta – 1 con lươn điện!

GitHub - ReactiveX/RxSwift: Reactive Programming in Swift

Chúng ta sẽ lần lượt tìm hiểu các khái niệm của “lươn điện”: observablesoperators và schedulers. Nào chúng ta cùng tìm hiểu nào!

Observables

Một lớp Observable<T> cung cấp cho Rx khả năng tạo ra 1 chuỗi các sự kiện không đồng bộ, tại bất cứ thời gian nào, mà các lớp khác có thể đăng ký lắng nghe được. Nghĩa là có thể nhiều lớp cùng đăng ký lắng nghe(observers) các sự kiện xảy ra trong thời gian thực. Observable có thể hiểu đơn giản là 1 cái trạm phát sóng, và các quan sát viên(giống như cái radio) gọi là observers, có thể lắng nghe 1 trong 3 loại sự kiện:

  • Một next event: là sự kiện mới nhất, đây là cách observers nhận dữ liệu.
  • Một completed event: nghĩa là sự kiện thành công, nghĩa là trạm phát observable đã hoàn thành công việc của mình và không phát ra thêm tín hiệu nào nữa.
  • Một error event: nghĩa là phát ra 1 lỗi và sẽ không phát thêm sự kiện nào nữa.

Nhấn mạnh: Hãy lẩm bẩm trong miệng 2 khái niệm mới đến khi thuộc lòng và hiểu bản chất:

Observable – trạm phát tín hiệu

observers – các quan sát viên thu tín hiệu

Ví dụ, 1 chuỗi phát ra các giá trị nguyên theo thời gian thực được mô tả ở hình sau:

Ngoài số nguyên, bạn có thể phát ra bất cứ thứ gì bạn muốn. Và một trạm phát có thể có nhiều quan sát viên, do vậy bạn thích bao nhiêu observer cũng được, mà không cần phải kế thừa hay ủy quyền gì cả.

1 trạm phát và 3 quan sát viên

Để hiểu hơn, chúng ta xét tình huống cụ thể, khi ứng dụng ios đang tải xuống 1 file lớn trên mạng. Các sự kiện của chuỗi phát ra như sau:

  • File bắt đầu tải, bắt đầu quan sát dữ liệu đến
  • Sau đó, chúng ta liên tục nhận được các phần dữ liệu tải về
  • Nếu có lỗi kết nối mạng, quá trình tải xuống dừng do lỗi
  • Nếu không file tải thành công và quá trình kết thúc thành công

Follow code sẽ như sau:

API.download(file: "http://www...")
  .subscribe(onNext: { data in
    ... nối các phần của file lại
  },
  onError: { error in
    ... hiển thị lỗi cho người dùng
  },
  onCompleted: {
    ... sử dụng file download xong
  })

Trong đoạn code trên, API.Download sẽ trả về 1 Observable<Data>, phát ra chuỗi các data gửi về qua mạng. Bạn đăng ký nghe các sự kiện ở onNext, ở trên là nối các phần của file tải về và lưu tạm vào ổ đĩa. Bạn đăng ký lắng nghe lỗi ở onError, có thể hiển thị lỗi cho người dùng biết. Bạn đăng ký sự kiện tải file thành công ở onCompleted, có thể mở file, hay làm bất cứ thứ gì mà logic app của bạn muốn.

Infinite observable sequences

Hay còn gọi là chuỗi quan sát vô hạn. Không giống như ví dụ trên, chúng ta sẽ có những tính huống quan sát các sự kiện vô hạn. Ví dụ khi bạn muốn quan sát sự kiện thiết bị người dùng thay đổi khung hình ngang hay dọc.

Chuỗi này là không có kết thúc, bạn chỉ biết thời điểm bắt đầu khi bạn quan sát, và luôn xử lý nó cho đến khi ứng dụng kết thúc.

thiết bị xoay ngang hay xoay dọc

Trong RxSwift, code được mô tả như sau:

UIDevice.rx.orientation
  .subscribe(onNext: { current in
    switch current {
      case .landscape:
        ... sắp xếp giao diện người dùng ngang
      case .portrait:
        ... sắp xếp giao diện người dùng dọc
    }
})

Lưu ý đoạn code trên là hư cấu(không chạy được), để mô tả việc rx phát ra chuỗi phát thiết bị đang ở chế độ ngang hay dọc. Tuy nhiên chúng ta sẽ dễ dàng biến điều hư cấu trên thành thật bằng cách tự viết được đoạn code cho nó trong các bài tiếp theo.

Operators

Khác với toán tử thông thường, các toán tử trong Rx cung cấp khả năng mở rộng để giải quyết các phương thức tính toán trừu tượng, giải quyết các vấn đề phức tạp của bất đồng bộ. Bởi vì chúng có khả năng tách biệt và đồng bộ, nên gọi là toán tử. Chúng có khả năng nhận đầu vào không đồng bộ, kết hợp với nhau tạo thành 1 bức tranh lớn hơn về logic app.

Ví dụ phép tính số học thông thường (5 + 6) * 10 – 2. Chúng ta vận dụng thứ tự ưu tiên trong ngoặc trước, nhân chia trước, cộng trừ sau để đưa ra kết quả cuối cùng. Tương tự trong Rx, các toán tử cũng được kết hợp như vậy, theo thứ tự ưu tiên xác định, cuối cùng đưa ra kết quả.

Ví dụ lại cách Rx lắng nghe sự kiện thiết bị thay đổi chiều:

UIDevice.rx.orientation
  .filter { value in
    return value != .landscape
  }
.map { _ in
    return "Portrait is the best!"
  }
  .subscribe(onNext: { string in
    showAlert(text: string)
  })

Mỗi khi thiết bị xoay ngang hay dọc thì rx sẽ phát ra sự kiện đó.

Đầu tiên chúng ta dùng toán tử filter để lọc những giá trị không phải là landscape. Tiếp theo chúng ta dùng toán tử map để trả về 1 đoạn string thông báo “Portrait is the best!”

Schedulers

Hiểu sơ sơ nó na ná giống bộ lập lịch của Apple, tuy nhiên chúng ta sẽ nghiên cứu chúng sau khi đã hoàn thành các kiến thức cơ bản về RxSwift.

  • Trong hình ảnh trên, phần network màu xanh biển sẽ chạy trên NSOperation based scheduler
  • Phần data binddings màu xanh lá cây chạy trên bộ lập lịch background GDC
  • Phần màu đỏ UI để cập nhật các sự kiện UI trên main thread

Trông có vẻ đơn giản đúng không? Nhưng tạm thời chúng ta sẽ quan tâm nó vào các bài sau cùng nhé.

Kiến trúc ứng dụng

Chúng ta có thể chọn lựa bất kỳ loại kiến trúc nào cho RxSwift, có thể MVC – kiến trúc base của apple. Hoặc bạn có thể dùng MVVM – để giải quyết các vấn đề của MVC. Nó là sự chọn lựa của bạn.

Điều đó có nghĩa là bạn cũng có thể dùng RxSwift với những tính năng mới của app, không bắt buộc phải dùng từ đầu.

Có 1 điều là, bằng kinh nghiệm thực tiễn thì MVVM và RxSwift là 1 sự kết hợp tuyệt vời. Sau này có thể bạn ngầm hiểu dùng RxSwift thì mặc định dùng MVVM để triển khai project của mình.

View Model sẽ cho phép bạn hiển thị các thuộc tính quan sát được, bạn có thể liên kết trực tiếp với UI nên dễ dàng cho việc viết mã.

Tuy nhiên tất cả các ví dụ sau này chúng ta sẽ dùng MVC cho việc học RxSwift đơn giản nhất.

Vậy là chúng ta đã hiểu một phần về RxSwift. Trong bài tiếp theo chúng ta sẽ nghiên cứu cách cài đặt môi trường RxSwift cho việc nghiên cứu bộ môn Rx tuy cũ nhưng lại hay ho này.

NoSQL Key Value Stores must know

NoSQL Key Value Stores must know

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

Tìm hiểu về NoSQL và Amazon Web Services tất nhiên không thể bỏ qua khái niệm về Key Value Stores. Đây là nội dung quan trọng cần nắm vững.

Hiểu biết về cơ chế, cách thức lưu trữ và ưu nhược điểm giúp phát triển hệ thống thành công. Ngoài ra, nó cũng rất có ích cho những ai đang muốn thiết kế các hệ thống phân tán lớn.

Bắt đầu ngay thôi nào!

1. Key Value Stores là gì?

key-value store, or key-value database is a simple database that uses an associative array (think of a map or dictionary) as the fundamental data model where each key is associated with one and only one value in a collection. This relationship is referred to as a key-value pair.

Key value stores, hoặc key value database là kiểu cơ sở dữ liệu sử dụng mảng kết hợp. Trong đó mỗi key sẽ tồn tại duy nhất một value trong collection. Mối quan hệ này được gọi là một cặp key-value

Đối với hệ cơ sở dữ liệu phân tán (Distributed System), các khối dữ liệu dữ liệu có thể lên tới vài triệu khối

Key Value Stores

Theo cách thông thường, mỗi table sẽ tồn tại nhiều column. Đơn cử như video, ta có video id, title, url, description, …

Đối với Key Value Stores, key ở đây là video id, tất cả các thành phần khác như title, url, description đều có thể gom thành 1 trong object Json.

Đại điện của kiểu lưu trữ này là Dynamo DB, một số use case phổ biến có thể đề cập tới là:

1.1 Use case

Session store: A session-oriented application such as a web application starts a session when a user logs in and is active until the user logs out or the session times out. During this period, the application stores all session-related data either in the main memory or in a database. Session data may include user profile information, messages, personalized data and themes, recommendations, targeted promotions, and discounts.

Lưu trữ session như web application có thể bắt đầu các session khi user đã đăng nhập. Tất cả sẽ biến mất khi user logout hoặc session hết hạn. Trong quá trình này, ứng dụng sẽ lưu trữ tất cả dữ liệu session vào bộ nhớ hoặc DB. Session có thể bao gồm thông tin cá nhân, tin nhắn, cấu hình dữ liệu và themes, …

Do chỉ với một key và value, kiểu lưu trữ này còn ứng dụng trong Shopping Cart

During the holiday shopping season, an e-commerce website may receive billions of orders in seconds. Key-value databases can handle the scaling of large amounts of data and extremely high volumes of state changes while servicing millions of simultaneous users through distributed processing and storage.

Trong mùa nghỉ lễ mua sắm, các trang thương mại điện tử có thể nhận tới hàng tỷ đơn hàng. Key-value databases có thể giải quyết vấn đề scaling cho lượng dữ liệu khổng lồ này. Phục vụ hàng triệu người dùng đồng thời thông qua quá trình xử lý và lưu trữ phân tán.

2. Hai kiểu Key Value Stores

Có hai kiểu Key Value Stores thường được sử dụng khi thiết kế hệ thống là Object Stores và In Memory DB. Ta sẽ tìm hiểu cả hai kiểu này trong bài viết. Đại diện cho Object Stores là Amazon S3 và In Memory DB là Amazon Redis.

2.1 Object Stores

Object storage, often referred to as object-based storage, is a data storage architecture for handling large amounts of unstructured data

Object storage, hay còn được gọi là object-based storage, là kiến trúc lưu trữ dữ liệu handle dữ liệu lớn (không có cấu trúc)

Về cách lưu trữ này, dữ liệu được chia thành các đơn vị rời rạc được gọi là object và được lưu giữ trong một kho lưu trữ duy nhất, thay vì được lưu giữ dưới dạng tệp trong thư mục hoặc dưới dạng khối trên server.

Object Storage chia dữ liệu lớn thành các unit nhỏ (có kích thước giới hạn). Mỗi Object bao gồm data, meta data (for index, management). Cuối cùng là ID, sử dụng để tìm kiếm trong hệ cơ sở dữ liệu phân tán (Distributed System)

Ngoài ra, Object Storage còn cho phép lưu trữ nhiều bản copy của dữ liệu, nếu một phiên bản bị mất có thể backup hoặc sử dụng phiên bản thay thế một cách nhanh chóng

  • Performs best for big content and high stream throughput – Cung cấp hiệu năng tuyệt vời cho dữ liệu lớn và luồng dữ liệu khổng lồ.
  • Data can be stored across multiple regions – Dữ liệu có thể được lưu trữ trên nhiều vùng.
  • Scales infinitely to petabytes and beyond – Quy mô lớn, mở rộng lên tới hàng petabytes.
  Vì sao SQL tốt hơn NoSQL? (Phần 1)
  NoSQL là gì? Điểm mạnh vượt trội của NoSQL

2.2 In-Memory Databases

In Memory DB giống như cái tên của nó. Thay về sử dụng SSD, Hard Disk để lưu trữ dữ liệu. IM DB muốn sử dụng Ram hoặc các phần Memory khác để lưu trữ dữ liệu.

Đại diện tiêu biểu của In Memory là Amazon Elasticache for Redis.

Use case phổ biến thường được áp dụng là Real-time bidding (đấu giá trực tuyến)

Real-time bidding refers to the buying and selling of online ad impressions. Usually the bid has to be made while the user is loading a webpage, in 100-120 milliseconds and sometimes as little as 50 milliseconds.

Real-time bidding đề cập lớn vấn đề mua bán trên các trang online. Thông thường các lệnh đặt được thực hiện khi người dùng đang loading webpage, chỉ trong 100-120 milliseconds, đôi khi là dưới 50 milliseconds.

Để đáp ứng độ trễ này, In Memory tỏ ra là giải pháp hoàn hảo. Tất nhiên, IMDB cũng là vị trí lưu trữ, cách thức lưu trữ thì vẫn giống như Object Store. Cả hai đều là Key Value Stores.

Key Value StoresVới IMDB, actions writes, reads thực hiện vô cùng nhanh

4. Tham khảo

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

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

Xem thêm IT Jobs for Developer hấp dẫn trên TopDev

JavaScript Engine là gì? Tìm hiểu JavaScript Engine

JavaScript Engine là gì? Tìm hiểu JavaScript Engine

Bài viết được sự cho phép của tác giả Trần Hữu Cương

JavaScript Engine là gì?

JavaScript Engine là một chương trình máy tính thực thi các đoạn code JavaScript (JS).

JavaScript đọc các đoạn mã JavaScript rồi chuyển nó sang mã máy để máy tính (hoặc phần mềm máy tính như trình duyệt web, server node.js…) có thể hiểu và chạy được.

  10 tip tối ưu code trên JavaScript mà web developer nào cũng nên biết
  10 trình quản lý file hàng đầu trong JavaScript

JavaScript Engine là gì? Tìm hiểu JavaScript Engine

Nếu bạn đã lập trình với Java hay C/C++ thì có thể hiểu JavaScript tương đương với JDK trong Java hay trình Compiler C/C++ trong lập trình C/C++.

Các bản JavaScript Engine phổ biến

Có nhiều bản JavaScript Engine được phát triển bởi các các vendor (nhà cung cấp) khác nhau. Một số JavaScript Engine phổ biến như:

  • SpiderMonkey  – Phiên bản Javascript engine đầu tiên, được dùng trên trình duyệt web đầu tiên trên thế giới – Netscape Navigator, hiện tại đang được sử dụng trên Firefox, viết bằng C và C++.
  • Chakra – Là một Javascript engine cũng khá lâu đời, ban đầu được sử dụng trên Internet Explorer và biên dịch JScript, nay được dùng cho Microsoft Edge, viết bằng C++.
  • Rhino – Một Engine viết hoàn toàn bằng Java, cũng có lịch sử phát triển lâu đời từ Netscape Navigator, hiện tại được phát triển bởi Mozilla Foundation.
  • Google V8 – Được phát triển bới Google (Chromium Project).

Ngoài các JS Engine trên, còn rất nhiều JavaScript Engine khác như Carakan, JavaScriptCore, TamarinNashorn

JavaScript dùng ở đâu?

Đầu tiên, các JavaScript Engine chủ yếu được phát triển và cài đặt cho các trình duyệt web (web browser). Ví dụ Chrome V8 dùng cho Google Chrome, SpiderMonkey dùng cho trình duyệt FireFox… Tức là chỉ dùng cho client.

Sau này, các JavaScript Engine được áp dụng để lập trình server với Node.js runtime system.

Một số phần mềm cũng áp dụng JavaScript Engine để lập trình phần mềm bằng JavaScript như MongoDB…

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

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

Xem thêm tìm việc javascript lương cao hấp dẫn trên TopDev

black – quên đi nỗi lo PEP8

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

Code Python phải chuẩn PEP8

Ngay khi bạn mới làm quen với Python được vài tuần, mới biết tí for loop hay function, PEP8 từ đâu đó sẽ hiện ra. PEP8 là hướng dẫn viết code chuẩn Python, chứ không phải chuẩn C, Java, hay không có chuẩn nào cả. Nếu tự hoc code một mình, có khi giờ này bạn đã làm ra vài chục script, chạy ầm ầm mà vẫn chưa 1 lần nghe PEP8. Tiêu chuẩn code là thứ chỉ hiện ra rõ ràng, khi ta làm việc với người khác, chỉ sau vài function, sự mâu thuẫn về style sẽ hiện ra ngay, và khi ông Chí Phèo không đồng ý với style của Bá Kiến, thì cả 2 phải lên phường và thống nhất dùng chuẩn chung mà làng Vũ Đại đặt ra – hay ở đây ta gọi là PEP8.

  20 tài liệu học Python thiết thực để trở thành lập trình viên chuyên nghiệp
  10 tips để trở thành Java Developer xịn hơn

PEP8 có thể xem chi tiết tại PEP0008 hay https://pep8.org/, tiêu chuẩn PEP8 được chấp nhận trên toàn trái đất, thậm chí CIA, Google cũng chỉ sửa đi chút xíu, bởi nó là chuẩn hay, chuẩn tốt.

Chuyện đau đầu về xì tai (style)

Style vốn là một thứ dễ gây ra tranh cãi. Tôi thích kiểu Việt Nam dịu dàng, anh thích kiểu Pháp say đắm, ông kia thích kiểu Mỹ mạnh mẽ và hùng hục. Vậy ai là người sai? Cuộc tranh cãi về style viết code đã kéo dài suốt từ ngày lập trình xuất hiện, tới giờ vẫn chưa kết thúc. Bởi đã là style, thì khó nói chuyện đúng sai.

Thế rồi mọi cuộc chơi vui, cũng phải đến hồi kết. Một ngôn ngữ lập trình đơn giản xuất hiện với tên hai chữ Go (sau để tránh nhầm lẫn thì gọi là Golang), và để tăng thêm sự đơn giản, nó đi kèm sẵn một chương trình với tên gofmt (đọc là gâu phằm) – chương trình này sẽ format tất cả code trong thư mục về một chuẩn mà nó đã quy định. Ban đầu, người ta vẫn còn tranh cãi về việc bị ép style, nhưng rồi sau một hồi, lợi ích của mỗi cái tôi đã sụp đổ trước lợi ích tập thể mà gofmt mang lại: mọi đoạn code đều trông giống nhau, khiến style không còn gì để tranh cãi, lập trình viên nhìn code của thằng kia cũng giống như của mình, dễ đọc – dễ hiểu hơn, expert hay newbie đều chung 1 style cả.

gofmt không phải là chương trình đầu tiên làm vậy, trước đây, trong cộng đồng Python đã xuất hiện 1 chương trình tên autopep8 hay Google cũng có YAPF. Nhưng Go là ngôn ngữ đầu tiên mang code formatter vào chính thống, chính thức chấm dứt cuộc chiến vô bổ về style kéo dài vài thập kỷ. Để rồi từ đó, các ngôn ngữ lập trình khác đua nhau học theo như RustElixir và Python thì có black.

Không có giải pháp nào để giải quyết 1 vấn đề tốt hơn là làm cho nó biến mất.

black là gì

Black là một câu lệnh cài bằng pip: pip install black, yêu cầu Python3.6 trở lên mới chạy. black xuất hiện như một project của một lập trình viên nào đó trên in tơ nét, sau vài năm trở nên cực kỳ phổ biến, và giờ đã chính thức được nằm dưới mái nhà PSF (Python Software Foundation) cùng với requests.

Code của black chỉ vọn vẹn 4000 dòng, sử dụng các tính năng mới nhất của Python như f-string, type annotation, asyncio… (vì thế nên yêu cầu Python3.6+ để chạy, mặc dù vẫn có thể format code 2.7)

Dùng black để format code Python

Ví dụ có 1 file foo.py

def sum_two(a,b):
    c= a  + b


    return c

Nếu thành thạo PEP8, thấy ngay có 4 chỗ phải sửa ở đây: a,b thiếu dấu space sau ,c thiếu dấu space theo sau, sau a thừa 1 space, thừa 1 dòng trống trước return. Vậy chỉ 3 dòng code, người review phải gõ ra 4 “vấn đề” về style, và người code ra 3 dòng này, khi đọc review cũng chẳng vui vẻ gì, kể cả người ta nói đúng.

Chạy:

$ black foo.py
reformatted foo.py
All done! ✨ 🍰 ✨
1 file reformatted.

$ cat foo.py
def sum_two(a, b):
    c = a + b

    return c

Đẹp, chuẩn, ngon! Không còn gì mong đợi thêm. black có nhiều option để chỉnh style cho phù hợp với tiêu chuẩn của bạn, hay dùng nhất là để set độ dài của 1 dòng, vốn là 79 ký tự theo chuẩn PEP8, thì black mặc định là 88:

  -l, --line-length INTEGER       How many characters per line to allow.
                                  [default: 88]

Bạn có thể gọi black -l79 . để theo PEP8.

Hành động của chúng ta

Đã đến lúc để quên đi việc format code bằng tay, nhớ vài chục tiêu chuẩn của PEP8, format code hãy để cho đen (black) không vâu lo – việc này để đen không vâu lo. Thêm dòng này vào Makefile của bạn:

fmt:
    black -l79 .

hay cài đặt text editor/IDE tự động chạy black sau mỗi lần save code.

Thêm dòng sau vào CI để bắt quả tang thằng nào không dùng black:

black --check .

Black sẽ thông báo các file chưa chuẩn format:

$ black --check .
would reformat /home/hvn/me/people/content/mypy_simple.py
would reformat /home/hvn/me/people/publishconf.py
would reformat /home/hvn/me/people/pelicanconf.py
would reformat /home/hvn/me/people/fabfile.py
Oh no! 💥 💔 💥
4 files would be reformatted, 1 file would be left unchanged.

Kết luận

Hãy dùng black! Và đừng quên share bài viết này, để cộng đồng code Python không còn mất thời gian ít bổ.

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 Việc làm Developer hấp dẫn trên TopDev

Đánh giá chất lượng từ trải nghiệm người dùng

trải nghiệm người dùng
Đánh giá chất lượng từ trải nghiệm người dùng

Qualitative Testing – Đánh giá chất lượng là gì?

Đánh giá chất lượng có thể được thực hiện dưới hình thức phỏng vấn hoặc các thử nghiệm khả năng sử dụng được quan sát trực tiếp khác. Nó mang tính chất khám phá và với mục tiêu hiểu sâu hơn về trải nghiệm của người dùng. Nhằm mục đích thu thập thông tin về động cơ và trải nghiệm cuộc sống hàng ngày của người dùng hoặc nhóm để xem những chi tiết này có thể ảnh hưởng như thế nào đến việc sử dụng sản phẩm hoặc công cụ của họ.

tối ưu trải nghiệm người dùng
Đánh giá chất lượng trải nghiệm người dùng giúp cải thiện chất lượng app

Tổng hợp và phân tích kết quả

Khi sử dụng các phương pháp đánh giá chất lượng, điều quan trọng là nhà nghiên cứu phải nhận ra rằng chúng có thể có ảnh hưởng đến kết quả nghiên cứu. Vì trải nghiệm của con người đang được nghiên cứu thay vì dữ liệu cứng (số lần nhấp chuột, xu hướng vị trí đăng nhập,…), rất khó để duy trì sự khách quan một cách tuyệt đối trong quá trình thử nghiệm hoặc khi đánh giá kết quả.

Kết quả cũng không nhất thiết phải được sử dụng lại. Điều này là do các yếu tố ảnh hưởng đến trải nghiệm của người dùng rất đa dạng và có thể thay đổi hàng ngày.

Những yếu tố này có thể khiến người dùng bị căng thẳng vào ngày này hơn ngày khác do những sự kiện mới trong cuộc sống của họ hoặc có nhiều trách nhiệm hơn vào ngày hôm đó, người dùng có trải nghiệm cuộc sống hoàn toàn khác nhau. Thậm chí, cả các yếu tố như thời tiết xấu cũng ảnh hưởng đến tâm trạng của người dùng và bất cứ điều gì khác ảnh hưởng đến cuộc sống cá nhân hoặc tình cảm của một người.

  3 bài học xương máu mà mỗi Product Manager đều phải trải qua.
  Kinh Nghiệm Học Coding Dành Cho Dân Trái Ngành

Các phương pháp kiểm tra trải nghiệm người dùng

Tham khảo thêm từ chia sẻ của Kevin Dalvi “12 UX Research Techniques (Quantitative and Qualitative)”.

Phỏng vấn

Thông thường gồm ba loại phỏng vấn:

  • Phỏng vấn trực tiếp: nhà nghiên cứu đặt câu hỏi cụ thể cho người dùng và cố gắng so sánh câu trả lời với những người dùng khác.
  • Phỏng vấn gián tiếp: nhà nghiên cứu cố gắng thảo luận chung nhiều hơn với (các) người dùng.
  • Phỏng vấn mang tính cộng đồng: nhà nghiên cứu quan sát (các) người dùng trong môi trường của chính họ để hiểu cách họ tiếp cận các khía cạnh nhất định, hoàn thành các nhiệm vụ nhất định.

Thực hiện khảo sát

Đây là một cách nhanh chóng để thu thập thông tin từ một số lượng lớn người dùng. Nhưng hạn chế rõ ràng của nó chính là thiếu sự tương tác giữa nhà nghiên cứu và người dùng.

Kiểm tra khả năng sử dụng

  • Kiểm tra có kiểm duyệt: người dùng được đưa vào phòng thí nghiệm và được giao các nhiệm vụ hoặc bài kiểm tra cụ thể để thực hiện.
  • Kiểm tra không kiểm duyệt: người dùng hoàn thành kiểm tra theo thời gian của họ thường từ xa.
  • Kiểm tra đột xuất: là một hình thức thử nghiệm thông thường hơn trong đó người dùng ngẫu nhiên tại một địa điểm xã hội hoặc cộng đồng được yêu cầu sử dụng ứng dụng / sản phẩm và cung cấp phản hồi không chính thức.

Bài viết được phỏng dịch theo bài viết gốc tại freecodecamp.org

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

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

Vẽ đồ thị trong Python với thư viện Matplotlib

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

Trước khi bắt đầu với câu hỏi Tại sao Matplotlib là một thư viện phổ biến trong Python? chúng ta đến với vài câu nói đúc kết của người xưa mà còn nguyên giá trị đến nay.

A picture is worth a thousand words – Một bức tranh hơn ngàn lời nói

Ngạn ngữ Anh

Như chúng ta đã biết Python được sử dụng nhiều nhất trong lĩnh vực phân tích dữ liệu, mà trong khoa học dữ liệu, việc trực quan hóa thông qua các đồ thị, biểu đồ giúp cho chúng ta hiểu được các mối quan hệ trong dữ liệu dễ dàng hơn rất nhiều. Matplotlib là một thư viện sử dụng để vẽ các đồ thị trong Python, chính vì vậy nó là thư viện cực phổ biến của Python. Bạn thử tưởng tượng một file dữ liệu khoảng 20MB, khi vẽ ra đồ thị từ dữ liệu này bạn sướng như phát điên vì có thể hiểu được ngay 20MB đó nói lên cái gì? Ngày nay, khi Big data đang trở thành thực tế, hàng ngày có quá nhiều dữ liệu, việc trực quan hóa dữ liệu càng trở nên cấp thiết và càng thúc đẩy những thư viện như Matplotlib phát triển hơn.

Mục đích của bài hướng dẫn này giúp bạn hiểu được cách vẽ các đồ thị, biểu đồ với thư viện matplotlib và từ đó bạn có thể sử dụng thành thạo nó cho trực quan hóa dữ liệu.

Tìm việc làm python lương cao các vị trí cho bạn

PyLab – Matplotib Cơ Bản

Matplotlib là một thư viện vẽ đồ thị trong Python, cho phép bạn tạo ra các biểu đồ và hình ảnh chất lượng cao. PyLab là một mô-đun trong Matplotlib, cung cấp một giao diện giống như Matlab để làm việc với các biểu đồ một cách dễ dàng.

John D. Hunter, một nhà thần kinh học bắt đầu phát triển matplotlib năm 2003 để mô phỏng các tập lệnh MATLAB, ông qua đời năm 2012 ở tuổi 44. Matplotlib giờ được phát triển và duy trì bởi cộng đồng các nhà phát triển khác.

Trong MATLAB, chúng ta không cần import gì mà có thể sử dụng các hàm có sẵn ngay lập tức khác với Python phải thực hiện import các thư viện cần thiết. Matplotlib có nguồn gốc từ MATLAB do đó module Pylab trong thư viện Matplotlib được xây dựng để có được cách thức sử dụng hàm như MATLAB. Nó đưa một số hàm và lớp từ Numpy và Matplotlib vào namespace giúp cho người dùng MATLAB có thể chuyển đổi sang Python sử dụng dễ dàng.

Khi bạn thực hiện lệnh import sau vào Python:

from pylab import *

Bạn có thể sử dụng ược ngay các hàm như plot(), array() như trong MATLAB. Vấn đề là với câu lệnh import này không ổn, nó bị chồng chéo các module sử dụng trong chương trình Python. Pylab do lịch sử để lại và nó không được khuyến cáo sử dụng, nó sử dụng các tên vô tội vạ với các chức năng ẩn giấu bên trong và rất khó để kiểm tra lỗi, do đó nên sử dụng Matplotlib.

Trong Pylab có rất nhiều các import tiền ẩn khả năng xung đột được che đậy kín. Matplotlib đã từ bỏ module này và khuyến cáo không nên sử dụng Pylab, mang mọi thứ trở nên rõ ràng hơn là để ngầm định. Không có pylab, chúng ta thường sử dụng một câu lệnh thay thế một cách chính tắc:

import matplotlib.pyplot as plt

Phân cấp đối tượng trong Matplotlib

Nếu bạn đã đọc tài liệu của Matplotlib, dòng code dưới đây là một phân cấp với các đối tượng Python lồng vào nhau. Phân cấp ở đây nghĩa là kiểu cấu trúc cây các đối tượng Matplotlib trả về từ plot(). Đối tượng Figure là nơi chứa đồ họa Matplotlib, nó có thể chứa các đối tượng Axes. Dưới Axes là hệ thống phân cấp các đối tượng nhỏ hơn như các đường thẳng, các textbox… Hầu hết các phần tử của đồ thị đều có thể tương tác như đối tượng trong Python.

plt.plot([1, 2, 3])

Ví dụ:

>>> fig, _ = plt.subplots()
>>> type(fig)
<class 'matplotlib.figure.Figure'>

Trong đoạn code trên chúng ta tạo ra hai biến với plt.subplots(), biến đầu tiên là fig chứa Figure, biến thứ hai _ chứa những thứ khác. Đây là cấu trúc Tuple trong Python do plt.subplots() cũng trả về kiểu Tuple. Do cấu trúc phân cấp hình cây, chúng ta muốn truy xuất đến phần tử đánh dấu chẳng hạn:

>>> one_tick = fig.axes[0].yaxis.get_major_ticks()[0]
>>> type(one_tick)
<class 'matplotlib.axis.YTick'>

Biến fig là instance của lớp Figure chứa bên trong nhiều các đối tượng Axes. Mỗi Axes có một yaxis và xaxis và chúng lại chứa một tập các major_sticks và chúng ta lấy cái đầu tiên.

Một ví dụ sau đến từ Matplotlib cho chúng ta hiểu hơn về phân cấp đối tượng trong Matplotlib.

Vẽ đồ thị trong Python với thư viện Matplotlib

Hình ảnh trên được sinh ra từ đoạn code sau đây, bạn có thể tham khảo tại Matplotlib.

Vẽ đồ thị với plot()

import matplotlib.pyplot as plt
%matplotlib inline

plt.plot([1,2,3,4,10])
plt.show()

Khi sử dụng module pylot trong thư viện matplotlib chúng ta sẽ import vào với tên ngắn gọn là plt. %matplotlib inline là câu lệnh của Jupyter Notebook để vẽ được các đồ thị bên trong cell của Jupyter Notebook.

Để vẽ một dạng đồ thị, chúng ta cần xem đối tượng plt có những phương thức nào, bạn có thể sử dụng:

dir(plt)

Câu lệnh plt.plot() sẽ vẽ một đồ thị bằng cách nối các điểm bằng đường thẳng (matplotlib.lines.Line2D). Trong ví dụ này, chúng ta đưa vào một List các số và Matplotlib sẽ vẽ ra đồ thị bằng cách nối các điểm. Bởi vì plt.plot() trả về một đối tượng, do vậy khi muốn hiển thị đồ thị, chúng ta cần gọi plt.show().

Phương thức plot() có 3 tham số:

plot(x, y, format)
  • Tham số x là danh sách các tọa độ trục x
  • Tham số y là danh sách các tọa độ trục y
  • format định dạng đồ thị

Trong ví dụ đầu, khi chúng ta đưa vào một List thì mặc định đó là danh sách tọa độ trục y và định dạng mặc định là vẽ đường thẳng giữa các điểm. Ví dụ trên tương đương với:

plt.plot([1,2,3,4,10])

Kết quả được đường sau khi sử dụng plt.show():

code python vẽ hình

Chú ý, trong bài viết này tôi sẽ sử dụng Jupyter Notebook để demo các ví dụ. Nếu bạn chưa biết cài đặt, sử dụng Jupyter Notebook có thể tham khảo:

Quay lại với phần định dạng đồ thị trong tham số thứ 3 của phương thức plot(). Định dạng này ở dạng viết tắt, nó là tổ hợp của ba thành phần {color}{marker}{line}. Ví dụ “go-” sẽ cho định dạng điểm có màu xanh và nối hai điểm là đường thẳng. Chúng ta thử thực hiện nó xem sao:

Chúng ta có một số định dạng khác như sau:

  • ‘r*–‘ các điểm hình ngôi sao màu đỏ, đường nối các điểm dạng –.
  • ‘bD-.’ các điểm hình kim cương màu xanh dương, đường nối các điểm dạng -.
  • ‘g^-‘ các điểm hình tam giác hướng lên màu xanh lá, đường nối các điểm dạng -.
  • Nếu bạn không muốn các điểm nối với nhau, có thể bỏ định dạng đường thẳng đi, ví dụ ‘go-‘ sẽ thành ‘go’

Vẽ nhiều tập điểm phân tán trên cùng đồ thị

Bạn có thể vẽ nhiều tập điểm phân tán trên cùng một đồ thị bằng cách gọi phương thức plot() nhiều lần. Ví dụ dưới đây sẽ vẽ hai đường đồ thị dựa trên hai tập điểm khác nhau với định dạng khác nhau:

import matplotlib.pyplot as plt

# Vẽ đồ thị
plt.plot([0, 1, 2, 3, 4], [1, 2, 3, 4, 10], 'go-', label='Python')
plt.plot([0, 1, 2, 3, 4], [10, 4, 3, 2, 1], 'ro-', label='C#')
plt.plot([2.5, 2.5, 2.5, 1.5, 0.5], [1, 3, 5, 7, 10], 'bo-', label='Java')

# Đặt tiêu đề và nhãn cho các trục
plt.title('Vẽ đồ thị trong Python với Matplotlib')
plt.xlabel('X')
plt.ylabel('Y')

# Hiển thị chú thích
plt.legend(loc='best')

# Hiển thị đồ thị

thư viện matplotlib

Trong ví dụ này có thêm một số điểm cần chú ý:

  • Thêm nhãn cho từng tập điểm với tham số thứ 4 trong plot().
  • Hiển thị ghi chú các thành phần trong đồ thị với phương thức legend().
  • Hiển thị nhãn các trục tọa độ x, y với xlabel() và ylabel().
  10 Lý do nên học Python trong năm 2024
  11 tip học Python dành cho các “newbie”

Vẽ nhiều đồ thị trong cùng một ảnh

Phần đầu bài viết chúng ta đã biết về phân cấp đối tượng trong Matplotlib, mỗi plt.plot() trả về một đối tượng Figure (là hình ảnh bên ngoài), trong Figure này có rất nhiều các đối tượng Axes là một đồ thị con bên trong. Trong phần này chúng ta sẽ vẽ hai đồ thị cạnh nhau nằm trong cùng một Figure (Hình ảnh).

import matplotlib.pyplot as plt

# Tạo các subplot
fig, (ax1, ax2, ax3) = plt.subplots(1, 3, figsize=(10, 4), sharey=True, dpi=120)

# Vẽ đồ thị cho từng subplot
ax1.plot([0, 1, 2, 3, 4], [1, 2, 3, 4, 10], 'go-')
ax2.plot([0, 1, 2, 3, 4], [10, 4, 3, 2, 1], 'ro-')
ax3.plot([2.5, 2.5, 2.5, 1.5, 0.5], [1, 3, 5, 7, 10], 'bo-')

# Đặt tiêu đề cho từng đồ thị
ax1.set_title('Python')
ax2.set_title('C#')
ax3.set_title('Java')

# Đặt nhãn cho trục X
ax1.set_xlabel('X')
ax2.set_xlabel('X')
ax3.set_xlabel('X')

# Đặt nhãn cho trục Y
ax1.set_ylabel('Y')
ax2.set_ylabel('Y')
ax3.set_ylabel('Y')

# Đặt giới hạn cho trục X
ax1.set_xlim(0, 6)
ax2.set_xlim(0, 6)
ax3.set_xlim(0, 6)

# Đặt giới hạn cho trục Y
ax1.set_ylim(0, 12)
ax2.set_ylim(0, 12)
ax3.set_ylim(0, 12)

# Căn chỉnh bố cục
plt.tight_layout()

# Hiển thị đồ thị
plt.show()

vẽ đồ thị trong python

Vẽ tập hợp điểm phân tán với scatter()

Sự khác biệt giữa plot() và scatter():

  • plot() không có khả năng thay đổi màu và kích thước điểm trong tập hợp điểm ban đầu nhưng scatter() lại có thể.
  • plot() có thể vẽ các đường nối hai điểm liên tiếp, scatter() thì không.

Ví dụ dưới đây vẽ ra các điểm trên đồ thị với dữ liệu về chiều cao và cân nặng, mỗi điểm có màu ngẫu nhiên và có kích thước cũng ngẫu nhiên.

import matplotlib.pyplot as plt
import numpy as np

# Dữ liệu về chiều cao và cân nặng
height = np.array([167, 170, 149, 165, 155, 180, 166, 146, 159, 185, 145, 168, 172, 181, 169])
weight = np.array([86, 74, 66, 78, 68, 79, 90, 73, 70, 88, 66, 84, 67, 84, 77])

# Màu sắc và kích thước cho các điểm dữ liệu
colors = np.random.rand(15)
area = (30 * np.random.rand(15)) ** 2

# Đặt giới hạn cho trục x và y
plt.xlim(140, 200)
plt.ylim(60, 100)

# Tạo biểu đồ phân tán
plt.scatter(height, weight, s=area, c=colors)

# Đặt tiêu đề và nhãn trục
plt.title("Chiều cao và cân nặng")
plt.xlabel("Chiều cao - cm")
plt.ylabel("Cân nặng - kg")

# Hiển thị biểu đồ
plt.show()

Kết quả như sau:

vẽ biểu đồ trong python

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

Xem thêm tuyển dụng it hà nội, đà nẵng, hcm hấp dẫn trên TopDev

Hướng dẫn build java project, maven project trên Jenkins

Hướng dẫn build java project, maven project trên Jenkins

Bài viết được sự cho phép của tác giả Trần Hữu Cương

Hướng dẫn build java project, maven project trên Jenkins

Trong ví dụ này mình sẽ thực hiện clone 1 maven project từ github và thực hiện build nó thành file jar. Tất cả sẽ được thực hiện tự động bằng Jenkins.

  10 Java Web Framework tốt nhất
  10 tip tối ưu code trên JavaScript mà web developer nào cũng nên biết

Yêu cầu:

Trong ví dụ này mình sử dụng 1 project maven trên github có url: https://github.com/stackjava/spring-boot-hello. Đây là 1 ví dụ về spring, đã được cấu hình chạy trên port 8081. Các bạn có thể fork/clone về account github của các bạn để dùng.

(Xem lại: Code ví dụ Spring boot Hello World)

Hướng dẫn build java project, maven project trên Jenkins

Đầu tiên, ta tạo 1 plan build bằng cách click vào New Item

Hướng dẫn build java project, maven project trên Jenkins

Chọn Maven Project và nhập tên cho plan build

Hướng dẫn build java project, maven project trên Jenkins

Ở đây mình dùng source code từ github nên mình sẽ chọn Git (khi build, jenkins sẽ clone source từ github về)

Để Jenkins clone được source code, ta cần cấu hình account git cho nó.

Hướng dẫn build java project, maven project trên Jenkins

Nhập username/password của tài khoản github mà bạn sử dụng để clone source code. (nếu bạn dùng bitbucket, gitlab… thì cũng nhập username/password tương ứng)

Hướng dẫn build java project, maven project trên Jenkins

Nhập repository URL của project git.

Hướng dẫn build java project, maven project trên Jenkins

Phần Credentials chọn account git mà bạn vừa thêm.

Click Save.

Hướng dẫn build java project, maven project trên Jenkins

Sau khi Save, ở màn hình chính chúng ta sẽ thấy plan build vừa tạo.

Click vào icon build để build project.

Hướng dẫn build java project, maven project trên Jenkins

Ở menu bên trái sẽ có trạng thái build của project. Click vào đó để xem.

Hướng dẫn build java project, maven project trên Jenkins

Click vào Console Ouput để xem log realtime của quá trình build.

Bạn sẽ thấy Jenkins tạo workspace, clone source code từ github về workspace, thực hiện build maven project (download các thư viện) thành file jar.

Hướng dẫn build java project, maven project trên Jenkins

Kết quả:

Hướng dẫn build java project, maven project trên Jenkins

Mở workspace ta sẽ thấy file jar được build ra.

Hướng dẫn build java project, maven project trên Jenkins

Chạy thử file jar vừa được build bằng lệnh:

  • java -jar spring-boot-hello-0.0.1-SNAPSHOT.jar

Hướng dẫn build java project, maven project trên Jenkins

Mở trình duyệt và truy cập địa chỉ http://localhost:8081

Hướng dẫn build java project, maven project trên Jenkins

Trong ví dụ tiếp theo chúng ta sẽ thực hiện deploy project, tức là quá trình chạy file jar sẽ được chạy tự động. Có thể là chạy giống như 1 service, up lên server tomcat…

Okay, Done!

References: https://www.jenkins.io/doc/

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

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

Xem thêm Tuyển dụng Java hấp dẫn trên TopDev

Thiết kế Messaging Service WhatsApp – P1

Thiết kế Messaging Service WhatsApp Part 1

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

Tiếp sau chuỗi bài viết về thiết kế hệ thống TinyURL, Kieblog tiếp tục giới thiệu chuỗi bài viết về System Design, hôm nay là Messaging Service.

  Discord đã lưu trữ hàng tỉ messages mỗi ngày như thế nào
  Kafka là gì? Ứng dụng Kafka cơ bản cho hệ thống message

Chat là hệ thống lớn, bao gồm nhiều thành phần và nhiều vấn đề cần giải quyết. Đại thể có thể nói tới: gửi file, các tệp định dạng khác nhau, group chat, thả reaction, …

Chính vì vậy, tóm gọn trong nội dung bài viết, ta chỉ xem xét qua thiết kế hệ thống Chat ở mức basic nhất có thể, qua đó hiểu thêm về Load Balancers và Scalable Web Application.

Bắt đầu ngay thôi!

1. Yêu cầu hệ thống

Messaging Service khi thiết kế yêu cầu phải có những tính năng tối thiểu như sau:

  • Send and receive text messages between two devices – Gửi và nhận tin nhắn giữa hai thiết bị
  • One-on-one conversations with different users – Giao tiếp 1 vs 1 với các user khác nhau trong hệ thống
  • User can see the time of each message – User có thể thấy được thời gian khi gửi từng tin nhắn

Do bài viết có giới hạn nên mình chỉ đề cập tới thiết kế một hệ thống Chat đơn giản:

  • Messages are one-on-one only, i.e, no group messages – Tin nhắn gửi 1-1, không có chat theo nhóm
  • Our server will not store the messages after they’re delivered – Server sẽ không lưu tin nhắn sau khi đã gửi
  • Our messages will be text-only – Nội dung tin nhắn tạm thời chỉ là text.

2. User case Messaging Service

Về user case cơ bản của hệ thống được thiết kế gồm có:

  • Send a message to a person – Gửi tin nhắn tới ai đó
  • If you receive a message and you are online, immediately deliver it. – Nếu nhận được tin nhắn và đang online, tin nhắn tới ngay lập tức.
  • If you receive a message and you are offline, wait till you come online – Nếu nhận được tin nhắn và đang offline, chờ tới khi online trở lại.
  • Get a notification and receive a message – Thông báo khi nhận được tin nhắn mới
Messaging Service

Về phía user, nội dung lưu trữ cũng không cần quá nhiều.

Java

User:

- id

- username

- password

- list<unread_messages>

Java

Message Properties:

- message text

- timestamp

- sender's Id

Rồi, cơ bản về User, System Requirement đơn giản chỉ cần có vậy. Bắt đầu đi sâu hơn vào phần thiết kế tính năng quan trọng nhất – Gửi tin nhắn.

3. Xử lí gửi và nhận tin nhắn

Không lòng vòng lèo vèo, về cơ bản, có hai cách để xử lí gửi tin nhắn là Push và Pull. Ta sẽ tìm hiểu chi tiết từng loại, ưu nhược điểm khi sử dụng trong Messaging Service System.

Đầu tiên là PULL

This is a less sophisticated way to “send” notifications. The device can periodically ask the server if there are any new messages. Say every 2 minutes, the device sends a REST API request to check if there are new messages, and the server responds with yes or no.

PULL là cách đơn giản để gửi notifications. Thiết bị sẽ gửi request tới server định kì trong một khoảng thời gian nhất định về tin nhắn mới. Cứ mỗi 2 phút, sẽ gửi REST API kiểm tra xem có tin nhắn mới hay không, server sẽ phản hồi với có hoặc không.

Cách này rõ ràng tồn tại hai nhược điểm lớn:

  • Độ trễ cao, nếu thời gian định kì lớn thì tin nhắn bị delay quá lâu, không thể chấp nhận tới tận 2 phút.
  • Tuy nhiên, nếu thời gian quá ngắn, request server phải nhận là cực kì lớn. Số lượng người dùng tới vài triệu -> toang.

Một phương thức khác cũng sử dụng PULL là Long Polling. Khi gửi request, server sẽ hold cho tới khi có tin nhắn mới và trả về response.

Thứ hai là PUSH

Thay vì chỉ giao tiếp một chiều với client ở phía chủ động gửi request. Tại sao không giữ connection liên tục giữa client và server sau khi đã mở

Once the client initiates the connection though, it can be kept alive and there can be bi-directional communication.

Tuy nhiên, một khi client khởi tạo kết nối, nó có thể được giữ nguyên và có thể giao tiếp hai chiều. Đó là cơ sở để đẩy dữ liệu đến các device.

3.1 Websocket

Websocket là lựa chọn tốt, đáng để cân nhắc

These are a good choice. WebSockets give you a single bi-directional connection over TCP. Once the connection is established, the client and server can freely exchange information.

Websocket cung cấp kết nối hai chiều (bi-driectional) duy nhất thông 1qua TCP. Một khi kết nối đã được khởi tạo, client và server có thể thoải mái để trao đổi thông tin

3.2 Push Notifications

Với push notification thì hện tại đã có nhiều sự lựa chọn tới từ Google hoặc Apple, mặc dù đôi khi chúng thường chậm hơn Websocket. Tuy nhiên các vấn đề vặt vãnh xung quanh đó thì lại hỗ trợ tốt hơn

Apple thì có Apple Push Notification Service (APNS), hỗ trợ tốt cho các thiết bị iOS. Google thì hỗ trợ với Firebase Cloud Messaging (FCM).

Messaging Service

Với tam giác ba điểm kết nối, Notification cho device iOS hay Android trở nên đơn giản hơn bao giờ hết. Mỗi khi server nhận được tin nhắn mới, nó sẽ gửi request Push Notification tới APNS hoặc GCM. Tuy nhiên, giới hạn cho notification với APNS là nội dung maximum có thể gửi tối đa dừng ở mức 2KB

3.3 Còn với XMPP?

XMPP cũng là một loại protocol phổ biến để messaging communications. XMPP is a protocol (giống như HTTP). Cũng có thể kết hợp XMPP với Websockets và Long Polling

4. Bắt tay vào thiết kế

Thiết kế đơng giản cho Messaging Service như sau. Lưu ý phần Caching và CDN có thể xử lí sau

Messaging Service
  • Đầu tiên, phía App Server sẽ là stateless, không quan tâm tới trạng thái của client. Cũng không lưu trữ gì ở đây (not store anything). App Server sẽ chỉ nhận request và lưu vào distributed In-Memory Cache và NoSQL
  • Khi App Server nhận được request từ notification rằng có message mới, App Servers sẽ đọc từ cache, nếu cache không có thì thực hiện query
  • Phần Load Balancer và Distributed Database tất nhiên là phần không thể thiếu cho các hệ thống muốn large scale

Trên đây là thiết kế tổng quan cho hệ thống, sẽ có phần 2 phân tích kĩ càng hơn về các feature, trả lời các câu hỏi về kĩ thuật cũng như các vấn đề có thể phải giải quyết trong thực tế.

5. Tham khảo

Thank for reading – Have a great week – Happy coding!

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

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

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

RxSwift 3: Thuật ngữ về lập trình bất đồng bộ (Asynchronous programming glossary)

RxSwift 3: Thuật ngữ về lập trình bất đồng bộ(Asynchronous programming glossary)

Bài viết được sự cho phép của tác giả Lê Xuân Quỳnh

Để đi sâu vào Rx, trước tiên chúng ta phải hiểu những khái niệm cơ bản nhất của nó. Sau đây Rx sẽ giải quyết các vấn đề về bất đồng bộ thông qua các khái niệm, thuật ngữ như sau:

Tuyển it swift nhiều ngành nghề từ các công ty

  RxSwift 10: Làm việc với PublishSubjects
  RxSwift 6: Observables

Trạng thái (State)

Cụ thể ở đây là trạng thái có thể thay đổi và chia sẻ. Trạng thái khó để mô tả, do vậy chúng ta sẽ hiểu nó thông qua các ví dụ. Khi bạn mở máy tính của mình lên, ban đầu chạy ổn định. Nhưng bạn để chế độ ngủ và tiếp tục mở nó lên, thì sau 1 thời gian nó không còn nhanh nữa, bị crash đột ngột… do trạng thái máy tính đã bị thay đổi. Dữ liệu trong bộ nhớ, tình trạng pin, các thao tác của người dùng vào máy,… là tổng hợp tất cả các trạng thái của máy tính. Quản lý các trạng thái đó, chia sẻ các trạng thái không đồng bộ và xử lý chúng là điều mà các bạn sẽ học ở loạt bài hướng dẫn Rx này.

Lập trình tuần tự

Là mô hình lập trình mà bạn sử dụng mã để thay đổi trạng thái chương trình của mình. Ví dụ bạn đang chơi với 1 con chó, bạn yêu cầu nó nằm, chạy hay sủa.. theo yêu cầu của bạn.

Mã tuần tự là mã mà bạn có thể đơn giản hiểu được, và CPU máy tính cũng làm theo 1 chuỗi tuần tự đơn giản, và vấn đề phức tạp khi làm các ứng dụng không đồng bộ phức tạp sẽ khó xử lý. Cùng xem ví dụ sau:

override func viewDidAppear(_ animated: Bool) {
  super.viewDidAppear(animated)
  setupUI()
  connectUIControls()
  createDataSource()
  listenForChanges()
}

Chúng ta có thể nôm na dịch hiểu đoạn lệnh trên làm những việc sau: tạo giao diện, kết nối các control trên giao diện với controller, tạo data source, và cuối cùng là lắng nghe các sự kiện thay đổi của nó. Chắc chúng ta hằng ngày vẫn làm những việc như này đúng không? Và có thể bạn đã gặp tình huống ai đó thay đổi thứ tự sắp xếp quá trình trên, ví dụ chúng ta lắng nghe sự kiện trước khi kết nối controls, thì crash sẽ xảy ra!

Các trạng thái của ứng dụng – Side effects

Khi người dùng thay đổi các input vào ứng dụng, thì các trạng thái khác nhau của ứng dụng sẽ sinh ra. Và tùy thuộc vào đầu vào mà sẽ sinh những side effects khác nhau. Ví dụ khi login, người dùng bấm sai thì báo alert, khi đăng nhập mà không có mạng, khi nhập thiếu ô,… Rất nhiều các effect khác nhau có thể xảy ra. Rx sẽ giải quyết toàn bộ những side effects đó, thông qua các khái niệm sau.

Declarative code

Trong lập trình tuần tự, bạn thay đổi trạng thái theo ý muốn. Trong lập trình sự kiện, bạn không tạo ra bất cứ side effects nào. Vì bạn đang sống trong 1 thế giới không hoàn hảo, cho nên sẽ có sự giao thoa giữa 2 hướng lập trình trên. RxSwift chính là sự giao thoa đó.

Declarative code – khái niệm cho phép bạn xử lý các side effects của app giống như lập trình tuần tự. Nghĩa là xử lý các sự kiện bất đồng bộ của app như là các sự kiện tuần tự có thể hiểu được.

Reactive systems

Reactive systems – dịch sát nghĩa hơi khó, bạn hiểu nôm na nó là hệ thống phản ứng sự kiện app cũng được! Nó được định nghĩa thông qua các khái niệm trừu tượng sau:

Responsive: luôn luôn cập nhất UI của người dùng, thể hiện trạng thái mới nhất. Nghĩa là trên màn hình của app đang có gì thì nó luôn lấy được trạng thái mới nhất đó.

Resilient: Mỗi hành vi được xác định riêng biệt và linh hoạt, có cơ chế sửa lỗi. Ví dụ hành vi nhập text vào 1 ô được xử lý riêng so với hành vi bấm nút.

Elastic: Mã xử lý các công việc như điền data vào table, thu thập dữ liệu, chia sẻ tài nguyên..

Message driven: Điều hướng sự kiện app nhằm tái sử dụng, tách lớp của các sự kiện trên app.

Bây giờ hẳn đọc đến đây thì bạn vẫn còn mơ hồ lắm chưa hiểu những khái niệm trên là gì. Tuy nhiên đừng hoảng sợ, bạn đầu ai cũng vậy thôi. Thật khó để giải thích nó khi mà không thực hành đúng không nào. Vậy chúng ta hãy đọc tiếp trong bài 4 nhé.

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

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

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

Thuật toán Gradient Descent

Thuật toán Gradient Descent

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

Video trong bài viết

Trong các bài toán machine learning hoặc các bài toán tối ưu, chúng ta thường phải làm việc với những điểm cực trị (thường là điểm cực tiểu) của một hàm số. Hẳn bạn còn nhớ trong Phần 1 của khóa học này về dự đoán doanh thu phim với Linear Regression, chúng ta đã phải cố gắng tìm giá trị nhỏ nhất của hàm chi phí (cost function) mà đôi khi còn gọi là hàm mất mát (loss function). Vậy Thuật toán Gradient Descent là gì?Gradien Descent có liên hệ gì với việc tìm kiếm cực trị bài toán tối ưu?, chúng ta sẽ cùng tìm hiểu trong bài học này nhé.

  Tại sao lại dùng Gradle thay thế Maven và Ant
  10 PHP Instagram Scripts & Widgets tốt nhất

1. Thuật toán Gradient Descent là gì?

Trong kiến thức toán phổ thông chúng ta đã biết, muốn tìm cực trị một hàm số y=f(x)y=f(x) chúng ta sẽ giải phương trình đạo hàm của hàm số f(x)f(x) bằng 0.

f(x)=0f′(x)=0

Tuy nhiên phương trình trên không phải lúc nào cũng giải được dễ dàng, có những trường hợp việc giải phương trình trên là bất khả thi. Vậy khi gặp những tình huống này, chúng ta phải làm gì? May thay, thuật toán Gradient Descent cho chúng ta cách thức tìm các điểm cực tiểu cục bộ này một cách xấp xỉ sau một số vòng lặp. Trong thực tế, các giá trị dữ liệu không có đúng 100% mà đôi khi chúng ta chỉ cần những con số gần đúng. Khi một người hỏi tôi, xác suất cho lần đầu tư chứng khoán lần này là 72%, tôi có nên đầu tư không? Thật sự mà nói 72% đã là một con số khá ấn tượng, mọi thứ ngoài đời không bao giờ có 1+1=21+1=2, nên những cách tính toán xấp xỉ, gần đúng là một giải pháp tuyệt vời.

Trước khi đi vào chi tiết thuật toán Gradient Descent, chúng ta hãy cùng trải nghiệm với một tình huống sau đây. Bạn đang ở trên một ngọn núi đầy sương mù, tầm nhìn bị hạn chế, làm cách nào để có thể xuống được thung lũng một cách nhanh nhất (Ở đây thung lũng chính là những điểm cực tiểu trong bài toán tối ưu). Cách đơn giản là nhìn xung quanh chỗ nào cảm nhận dốc nhất thì bạn bước xuống và từng bước một, cho đến khi bạn không cảm nhận được xung quanh có độ dốc thì đấy chính là thung lũng, nơi bằng phẳng và là điểm cực tiểu của đồ thị.

Tuyệt vời phải không, thuật toán Gradient Descent mô tả chính xác những gì bạn đang trải nghiệm ở tình huống trên. Trong bài viết về Đạo hàm hàm số, độ dốc (slope) của hàm số tại điểm x0x0 chính là đạo hàm của hàm số tại điểm x0x0. Bước đi xuống từ điểm x0x0 sang điểm x1x1 sẽ bằng Δ0Δ0. Ta có:

x1=x0+Δ0x1=x0+Δ0

Chúng ta sẽ tìm hiểu xem thành phần của Δ0Δ0 là gì? Để hướng đi xuống chúng ta có

Δ0=ηf(x0)Δ0=−ηf′(x0)

Dấu âm trong độ dốc nghĩa là chúng ta đang đi xuống và với hệ số ηη. Vậy ta có thể viết lại

x1=x0ηf(x0)x1=x0−ηf′(x0)

Như vậy tại bước thứ n chúng ta có:

xn=xn1+Δn1=xn1ηf(xn1)xn=xn−1+Δn−1=xn−1−ηf′(xn−1)

Nhưng đến khi nào thì kết thúc không bước tiếp? Như trong tình huống, khi nào cảm thấy xung quanh không còn dốc, nghĩa là khi đó xnxn1xn≈xn−1 hay xnxn1xn−xn−1 đạt đến một giá trị khá nhỏ mà chúng ta chấp nhận được.

2. Viết code Gradient Descent trong Python

Ví dụ chúng ta có một hàm số y=x26sinxy=x2−6sin⁡x, đây là một hàm số mà phương trình y=0y′=0 không tìm được nghiệm bằng cách giải phương trình, do vậy chúng ta cần dùng đến Gradient Descent để tìm cực tiểu.

Chú ý: Phần này có liên quan đến xuất đồ thị động dạng ảnh động trong Python, bạn nên tham khảo bài Vẽ đồ thị dạng ảnh động với Animation trong thư viện Matplotlib trước khi đến phần tiếp theo.

Sử dụng gradient descent với learning rate = 0.1

Đầu tiên chúng ta import các thư viện cần thiết.

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation

Tiếp đến là định nghĩa hàm f(x) và đạo hàm của nó df(x) trong Python, ở đây chúng ta sử dụng hai quy tắc tính đạo hàm:

y=xny=nxn1y=xn→y′=nxn−1
y=sinxy=cosxy=sin⁡x→y′=cos⁡x

Đây là những kiến thức phổ thông bạn đã biết từ hồi cấp 3, do vậy chúng ta có:

y=x25sinxy=2x5cosxy=x2−5sin⁡x→y′=2x−5cos⁡x
def f(x):
    return x**2 - 5*np.sin(x)

def df(x):
    return 2*x - 5*np.cos(x)

Để vẽ đồ thị động chúng ta cần thiết lập một số thông số cho đồ thị như kích thước ảnh, giới hạn các trục tọa độ, một số text sẽ hiển thị trên đồ thị.

fig = plt.figure(figsize=[10, 7])
ax = plt.axes(xlim=(-8, 8), ylim=(-10, 60))
ax.text(-6, 55, 'Hàm số $y=x^2-5\sin{x}$, $step\_multiplier=0.1$, $precision=0.00001$, $start=-10$', fontsize=12)
label_1 = ax.text(-6, 50, '', fontsize=12)
label_2 = ax.text(0, 30, '', fontsize=20)

line, = ax.plot([], [], 'ro-', lw=5)
x = np.linspace(start=-8, stop=8, num=100)
y = f(x)
ax.plot(x,y)

Giờ là lúc sử dụng thuật toán Gradient Descent ở phần 1, chúng ta thiết lập các giá trị ban đầu:

x_1 = -10
x_0 = 0
step_multiplier = 0.1
precision = 0.00001

Ở đây có 4 biến x_0 chứa giá trị trước đó, x_1 là giá trị trong bước tiếp theo, step_multiplier là hệ số kết hợp với độ dốc, ở phần cuối bài chúng ta sẽ biết đến nó với tên gọi tốc độ học (learning rate). Biến precision quyết định khi nào dừng thuật toán, nó là độ chính xác trong phép tính xấp xỉ mà chúng ta mong muốn, ở đây độ chính xác đến 1/100k.

Tiếp theo, chúng ta sẽ cài đặt thuật toán Gradient Descent kết hợp với định nghĩa các phần vẽ hoạt họa:

def animate(i):
    global x_0, x_1
    step_size = abs(x_1 - x_0)

    if step_size > precision:
        x_0 = x_1
        gradient = df(x_0)
        x_1 = x_0 - step_multiplier * gradient
        x = [x_0, x_1]
        y = [f(x_0), f(x_1)]
        line.set_data(x, y)
        label_2.set_text(str(i))
    label_1.set_text('Lần: ' + str(i) + '/50, cost:' + str(f(x_1)) + ', slope:' + str(df(x_1)))
    return line, 

Thuật toán dừng lại khi độ chính xác đạt như mong muốn hay xnxn1<percisionxn−xn−1<percision. Nếu chưa đạt được độ chính xác tính toán bước tiếp theo x1=x0ηf(x0)x1=x0−ηf′(x0) với

    x_0 = x_1
    gradient = df(x_0)
    x_1 = x_0 - step_multiplier * gradient

Cuối cùng, chúng ta sử dụng hàm FuncAnimation để xuất ra đồ thị dạng hình ảnh động:

anim = FuncAnimation(fig, animate, frames=50, interval=400, blit=True)
anim.save('gradient_descent.gif', writer='imagemagick')

Bạn có thể tải Code Jupyper Notebook. Kết quả chúng ta được hình ảnh động như sau:

Sử dụng gradient descent với learning rate = 0.1

Một số nhận xét về kết quả:

  • Những đoạn có độ dốc lớn thuật toán sẽ vượt qua nhanh chóng, những đoạn độ dốc nhỏ, sẽ rất lâu để vượt qua, ví dụ ở dải x[-4,-2] tại đây phải mất hơn 10 vòng lặp để vượt qua.
  • Khi độ dốc lớn thì bước di chuyển cũng lớn do Δ=xnxn1=ηf(xn1)Δ=xn−xn−1=−ηf′(xn−1).
  • Nhìn vào công thức trên, ta có thể kết luận số bước lặp để đi đến kết quả sẽ phụ thuộc các yếu tố:
    • Giá trị khởi tạo của thuật toán
    • Độ chính xác percision
    • Hệ số step_multiplier hay là tốc độ học (learning rate)

3. Điều chỉnh các thông số trong Gradient Descent

Trong kết quả phần trước chúng ta đã nhận xét một số các yếu tố có liên quan đến kết quả của Gradient Descent, chúng ta sẽ cùng tìm hiểu từng yếu tố liên quan này. Công thức cần nhớ là:

Δ=xnxn1=ηf(xn1)Δ=xn−xn−1=−ηf′(xn−1)

3.1 Giá trị khởi tạo

Giá trị khởi tạo là điểm x0x0, nếu điểm này càng gần với điểm cực tiểu thì số bước lặp ít đi. Do bước nhảy phụ thuộc vào độ dốc do đó nếu điểm x0x0 nằm ở phía có độ dốc lớn thì số bước lặp cũng ít đi. Thật vậy, chúng ta điều chỉnh các thông số trong phần 2 như sau:

x_1 = 10

Tức là điểm khởi tạo sẽ ở x0=10x0=10 và xuất kết quả ra được hình sau:

Điểm khởi tạo Gradient descent cho sự khác biệt

Bạn có thể thấy với điểm khởi tạo ở -10, thuật toán hội tụ (đạt đến điểm cực tiểu mong muốn) sau 33 bước lặp, trong khi với điểm khởi tạo là 10 thì chỉ cần 15 bước lặp thuật toán đã hội tụ. Do vậy, việc lựa chọn điểm khởi tạo cho Gradient Descent cũng rất quan trọng để đạt được kết quả nhanh.

3.2 Độ chính xác mong muốn

Trong ví dụ chính, chúng ta sử dụng độ chính xác là 1/100k, vậy nếu thử tăng độ chính xác thêm 1 chữ số 0 nữa tức là chính xác đến 1/1 triệu xem thuật toán hội tụ sau bao nhiêu bước.

Độ chính xác 1/1 triệu

Chúng ta thấy cần đến 35 bước lặp mới đạt đến độ chính xác 1/1 triệu trong khi chỉ cần 33 bước lặp với độ chính xác 1/100k. Trong thực tế, tùy vào lĩnh vực và bài toán cụ thể mà cần có độ chính xác cao hay thấp. Ví dụ với một bài toán kinh tế, khi đưa ra xác xuất lựa chọn phương án là 70% (1/trăm) và 72.3473% (1/triệu) là như nhau, vậy nên chúng ta chọn độ chính xác percision = 0.01 thì thuật toán sẽ hội tụ nhanh hơn mà vẫn đạt được kết quả mong muốn.

3.3 Tốc độ học – Learning rate

Tốc độ hội tụ của Gradient Descent phụ thuộc vào nhiều vào learning rate ηη. Để kiểm tra chúng ta thử tăng tốc độ học ηη từ 0.1 lên 0.2. Kết quả như hình sau:

Tăng tốc độ học

Chỉ sau 18 bước lặp thuật toán đã hội tụ so với 33 bước khi learning rate tăng từ 0.1 lên 0.2. Câu hỏi đặt ra, vậy có thể tăng tốc độ học lên thật cao không. Trong ví dụ tiếp theo chúng ta sẽ đẩy learning rate lên 0.5 xem thế nào.

Thuật toán không thể hội tụ

Thuật toán nhanh chóng kéo đến điểm cực tiểu nhưng không thể hội tụ, nó chạy qua chạy lại hai bên điểm cực tiểu nhưng không thể tiến đến điểm cực tiêu mặc dù chạy qua hơn 50 bước.

Như vậy có thể thấy việc chọn tốc độ học là rất quan trọng trong Gradient Descent, nếu learning rate bé thì tốc độ hội tụ lâu nhưng nếu chọn lớn quá thì thuật toán không thể hội tụ. Do vậy, trong thực tế để chọn được learning rate phù hợp chúng ta cần thực hiện các tốc độ khác nhau và sau vài lần thực hành, chúng ta sẽ có được con số phù hợp.

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

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

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

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

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

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

I. Markdown

Markdown được nói trong bài này là cú pháp để phục vụ việc chuyển text thành HTML. Tức là khi viết bằng cú pháp markdown, đưa qua 1 chương trình xử lý, nó sẽ cho ra kết quả là HTML.

  25 blogger IT nổi tiếng mà dân lập trình ai cũng phải biết
  Câu chuyện về cái comment tại một blog nọ

Một số cú pháp hay dùng:

Headers

# H1
## H2
### H3
#### H4
##### H5
###### H6

Kết quả: (lưu ý, xem source html của kết quả để biết chính xác, việc trình bày có thể bị ảnh hưởng bới template của blog)

H1

H2

H3

H4

H5

H6

Định dạng chữ:

Chữ nghiêng: *nghiêng* hoặc _nghiêng_. (*: asterik, _: underscore)

Chữ đậm: **đậm** hoặc __đậm__.

Nghiêng đậm: **_nghiêng đậm_** hoặc *__nghiêng đậm__*

Gạch ngang chữ: <s>gạch ngang</s>

Kết quả:

Chữ nghiêng: nghiêng hoặc nghiêng. (*: asterik, _: underscore)

Chữ đậm: đậm hoặc đậm.

Nghiêng đậm: nghiêng đậm hoặc nghiêng đậm

Gạch ngang chữ: gạch ngang

Link

[I'm an inline-style link](http://fml.vn)

[I'm an inline-style link with title](http://fml.vn "FML Academy")

[I'm a reference-style link][Arbitrary case-insensitive reference text]

[I'm a relative reference to a repository file](../blob/master/LICENSE)

[You can use numbers for reference-style link definitions][1]

Or leave it empty and use the [link text itself].

[arbitrary case-insensitive reference text]: http://fml.vn
[1]: http://fml.vn
[link text itself]:http://fml.vn

Kết quả:

I’m an inline-style link

I’m an inline-style link with title

I’m a reference-style link

I’m a relative reference to a repository file

You can use numbers for reference-style link definitions

Or leave it empty and use the link text itself.

Image

Here's our logo (hover to see the title text):

Inline-style: 
![alt text](https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png "Logo Title Text 1")

Reference-style: 
![alt text][logo]

[logo]: https://github.com/adam-p/markdown-here/raw/master/src/common/images/icon48.png "Logo Title Text 2"

Kết quả

Here’s our logo (hover to see the title text):

Inline-style: alt text

Reference-style: alt text

Code

`inline code` không xuống dòng

hoặc

“`python

print(‘This is python code’)

“`

Kết quả

inline code không xuống dòng

hoặc

print('This is python code')

Còn nhiều cú pháp nữa, xem chi tiết tại đây

II. Pelican

Pelican là một công cụ để tự động tạo file html, được viết bằng python. Hỗ trợ cú pháp reStructure (file đuôi .rst) và markdown (file đuôi .md)

1. Tạo virtualenv, kích hoạt và cài pelican, markdown vào virtualenv:

╭─htl@htl-homeserver  ~/pelican  
╰─$ virtualenv -p $(which python3) venv
Running virtualenv with interpreter /usr/local/bin/python3
Using base prefix '/usr/local'
New python executable in venv/bin/python3
Also creating executable in venv/bin/python
Installing setuptools, pip, wheel...done.
╭─htl@htl-homeserver  ~/pelican  
╰─$ source ./venv/bin/activate
(venv)╭─htl@htl-homeserver  ~/pelican  
╰─$ pip install pelican markdown
Collecting pelican
  Using cached pelican-3.6.3-py2.py3-none-any.whl
Collecting markdown
Collecting docutils (from pelican)
  Using cached docutils-0.12-py3-none-any.whl
Collecting six>=1.4 (from pelican)
  Using cached six-1.10.0-py2.py3-none-any.whl
Collecting unidecode (from pelican)
Collecting jinja2>=2.7 (from pelican)
  Using cached Jinja2-2.8-py2.py3-none-any.whl
Collecting feedgenerator>=1.6 (from pelican)
Collecting pytz>=0a (from pelican)
  Using cached pytz-2016.4-py2.py3-none-any.whl
Collecting pygments (from pelican)
  Using cached Pygments-2.1.3-py2.py3-none-any.whl
Collecting blinker (from pelican)
Collecting python-dateutil (from pelican)
  Using cached python_dateutil-2.5.3-py2.py3-none-any.whl
Collecting MarkupSafe (from jinja2>=2.7->pelican)
Installing collected packages: docutils, six, unidecode, MarkupSafe, jinja2, pytz, feedgenerator, pygments, blinker, python-dateutil, pelican, markdown
Successfully installed MarkupSafe-0.23 blinker-1.4 docutils-0.12 feedgenerator-1.8 jinja2-2.8 markdown-2.6.6 pelican-3.6.3 pygments-2.1.3 python-dateutil-2.5.3 pytz-2016.4 six-1.10.0 unidecode-0.4.19

2. Tạo thư mục chứa blog và chạy pelican-quickstart để thiết lập các thông số ban đầu:

(venv)╭─htl@htl-homeserver  ~/pelican  
╰─$ mkdir blog
mkdir: created directory 'blog'
(venv)╭─htl@htl-homeserver  ~/pelican  
╰─$ cd blog
(venv)╭─htl@htl-homeserver  ~/pelican/blog  
╰─$ pelican-quickstart
Welcome to pelican-quickstart v3.6.3.

This script will help you create a new Pelican-based website.

Please answer the following questions so this script can generate the files
needed by Pelican.


> Where do you want to create your new web site? [.] 
> What will be the title of this web site? Test blog
> Who will be the author of this web site? htl
> What will be the default language of this web site? [en] vn
> Do you want to specify a URL prefix? e.g., http://example.com   (Y/n) n
> Do you want to enable article pagination? (Y/n) y
> How many articles per page do you want? [10] 
> What is your time zone? [Europe/Paris] Asia/Ho_Chi_Minh
> Do you want to generate a Fabfile/Makefile to automate generation and publishing? (Y/n) y
> Do you want an auto-reload & simpleHTTP script to assist with theme and site development? (Y/n) y
> Do you want to upload your website using FTP? (y/N) n
> Do you want to upload your website using SSH? (y/N) n
> Do you want to upload your website using Dropbox? (y/N) n
> Do you want to upload your website using S3? (y/N) n
> Do you want to upload your website using Rackspace Cloud Files? (y/N) n
> Do you want to upload your website using GitHub Pages? (y/N) y
> Is this your personal page (username.github.io)? (y/N) n
Done. Your new project is available at /home/htl/pelican/blog

3. Viết blog trong thư mục content:

Đơn giản là chỉ cần tạo 1 file .md tại thư mục /blog/content, nội dung file được định dạng theo cú pháp markdown.

Các thông tin (metadata) cần thiết cho 1 bài viết được ghi ngay trên đầu file. Metadata tối thiểu bắt buộc phải có là Title, ngoài ra với cấu hình mặc định thì nên thêm Date:

Title: Tiêu đề bài viết
Date: 2016-06-28

Nội dung viết ở đây, định dạng **markdown**

Nếu metadata Date không được cung cấp trong nội dung bài viết thì pelican sẽ lấy thời gian tạo ra file, với điều kiện trong file pelicanconf.py phải có dòng (mà mặc định là chưa có):

DEFAULT_DATE = 'fs'

4. Tạo file html:

Điều kiện là khi khởi tạo bằng lệnh pelican-quickstart phải bật công cụ tự động tạo html ở câu hỏi này:

> Do you want to generate a Fabfile/Makefile to automate generation and publishing? (Y/n) y

Khi đó sẽ có file Makefile tại thư mục gốc của blog. Tạo blog bằng cách chạy lệnh make html:

(venv)╭─htl@htl-homeserver  ~/pelican/blog  
╰─$ make html                  
pelican /home/htl/pelican/blog/content -o /home/htl/pelican/blog/output -s /home/htl/pelican/blog/pelicanconf.py 
Done: Processed 1 article, 0 drafts, 0 pages and 0 hidden pages in 0.22 seconds.

Vậy là đã tạo được 1 file html trong thư mục output (ngang hàng với content).

Thử xem blog mình vừa viết trông như thế nào, dùng lệnh make serve:

(venv)╭─htl@htl-homeserver  ~/pelican/blog  
╰─$ make serve
cd /home/htl/pelican/blog/output && python -m pelican.server

Vào http://localhost:8000 để xem thử:

III. Upload lên github pages:

1. Tạo 1 github repo có tên là username.github.io với username là tên tài khoản github của bạn.

2. Clone repo về local:

(venv)╭─htl@htl-homeserver  ~/pelican  
╰─$ git clone git@github.com:fmltestblog/fmltestblog.github.io.git
Cloning into 'fmltestblog.github.io'...
warning: You appear to have cloned an empty repository.

3. Copy tất cả folder output vào thư mục của github repo:

(venv)╭─htl@htl-homeserver  ~/pelican  
╰─$ cd fmltestblog.github.io 
(venv)╭─htl@htl-homeserver  ~/pelican/fmltestblog.github.io  ‹master› 
╰─$ cp -R ../blog/output/* .

4. git add, commit và push:

(venv)╭─htl@htl-homeserver  ~/pelican/fmltestblog.github.io  ‹master*› 
╰─$ git add .
(venv)╭─htl@htl-homeserver  ~/pelican/fmltestblog.github.io  ‹master*› 
╰─$ git commit -m 'first blog commit'
[master (root-commit) 5d4216d] first blog commit
 33 files changed, 1250 insertions(+)
 create mode 100644 archives.html
 create mode 100644 author/htl.html
 create mode 100644 authors.html
 create mode 100644 categories.html
 create mode 100644 category/misc.html
 create mode 100644 index.html
 create mode 100644 tags.html
 create mode 100644 theme/css/main.css
 create mode 100644 theme/css/pygment.css
 create mode 100644 theme/css/reset.css
 create mode 100644 theme/css/typogrify.css
 create mode 100644 theme/css/wide.css
 create mode 100644 theme/images/icons/aboutme.png
 create mode 100644 theme/images/icons/bitbucket.png
 create mode 100644 theme/images/icons/delicious.png
 create mode 100644 theme/images/icons/facebook.png
 create mode 100644 theme/images/icons/github.png
 create mode 100644 theme/images/icons/gitorious.png
 create mode 100644 theme/images/icons/gittip.png
 create mode 100644 theme/images/icons/google-groups.png
 create mode 100644 theme/images/icons/google-plus.png
 create mode 100644 theme/images/icons/hackernews.png
 create mode 100644 theme/images/icons/lastfm.png
 create mode 100644 theme/images/icons/linkedin.png
 create mode 100644 theme/images/icons/reddit.png
 create mode 100644 theme/images/icons/rss.png
 create mode 100644 theme/images/icons/slideshare.png
 create mode 100644 theme/images/icons/speakerdeck.png
 create mode 100644 theme/images/icons/stackoverflow.png
 create mode 100644 theme/images/icons/twitter.png
 create mode 100644 theme/images/icons/vimeo.png
 create mode 100644 theme/images/icons/youtube.png
 create mode 100644 this-is-post-title.html
(venv)╭─htl@htl-homeserver  ~/pelican/fmltestblog.github.io  ‹master› 
╰─$ git push origin master 
Counting objects: 41, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (38/38), done.
Writing objects: 100% (41/41), 24.48 KiB, done.
Total 41 (delta 8), reused 0 (delta 0)
To git@github.com:fmltestblog/fmltestblog.github.io.git
 * [new branch]      master -> master

5. Mở trình duyệt, truy cập https://username.github.io

Blog của bạn đã online. Khi thêm 1 bài viết mới, hãy chạy lại từ bước II.4 và push lên github.

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

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

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