Thực Hành Cơ Bản Với Ngôn Ngữ Lập Trình Go (1) - nói dối e blog

Thực Hành Cơ Bản Với Ngôn Ngữ Lập Trình Go (1)

Chạm ngõ lập trình Go (Kỳ 1) Sáng nay bỗng nảy ra ý tưởng xây dựng một dịch vụ truyền tải tập tin nhỏ gọn theo nhu cầu cá nhân. Tôi nhận ra rằng việc chỉ nói suông về các ý tưởng công nghệ giống như kiểu “ngồi trên lưng ngựa không biết đường đi” - một hình ảnh ẩn dụ tôi thường dùng khi phê phán lối làm việc thiếu thực chất. Đặc biệt trong lĩnh vực sản phẩm mạng, việc chỉ có các “quản lý sản phẩm chuyên nghiệp” ngồi mơ mộng mà không chịu tự tay triển khai thì giống như việc xây nhà không bản vẽ chi tiết.

Tôi đã từng nhiều lần sa vào cái bẫy này trong nửa năm qua - suốt nói về các dự án lớn lao nhưng chẳng viết nổi vài dòng code. Kể từ đầu tháng này, khi nhận thấy mình bắt đầu “rỉ sét” vì không chạm vào bàn phím nhiều, tôi quyết định thay đổi. Và cái cớ hoàn hảo để tái khởi động chính là học ngôn ngữ Go - một ngôn ngữ mà tôi đã ngắm nghía từ xa bấy lâu.

Những ngày đầu làm quen với Go thực sự là một trải nghiệm “mở mang tầm mắt”. Mỗi dòng code viết ra đều phải tra cứu tài liệu liên tục, đặc biệt là khi tối hôm qua tôi cố gắng viết 500 dòng trong khi liên tục vấp phải lỗi cú pháp ngớ ngẩn. Nhưng rồi từ từ, thứ gọi là “cảm giác ngôn ngữ” bắt đầu hình thành - giống như việc học bơi, ban đầu vật lộn với nước nhưng rồi cơ thể tự biết cách nổi.

Dưới đây là một đoạn code nhỏ minh họa quá trình học hỏi này. Nhiệm vụ khá thú vị: xây dựng một hàm Go mỗi lần gọi sẽ trả về chuỗi ngẫu nhiên gồm 8 ký tự in hoa (dùng để tạo link rút gọn). Đây là cách tôi triển khai:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package main
import "fmt"
import "rand"
var keyGen func() string
func init() {
  keys := make(chan string)
  go func() {
    for {
      var buf [8]byte
      for i:=0 ; i<8 ; i++ {
        buf[i] = byte(rand.Intn(26)) + byte('A')
      }
      keys <- string(buf[:])
    }
  } ()
  keyGen = func() string {
    return <-keys
  }
}
func main() {
  fmt.Println(keyGen())
  fmt.Println(keyGen())
  fmt.Println(keyGen())
}

Điều khiến tôi tâm đắc nhất ở đoạn code này chính là cách sử dụng goroutine cùng channel. Khác với tư duy lập trình C/C++ truyền thống vốn e ngại đa luồng vì phức tạp, Go lại khuyến khích mô hình “cộng tác” giữa các goroutine thông qua channel. Việc tạo ra một luồng xử lý riêng chỉ để sinh chuỗi ngẫu nhiên tưởng chừng quá mức nhưng lại rất “đúng chất Go” - một minh chứng đẹp cho triết lý “Share memory by communicating” mà tôi đang dần thấm thía.

Có lẽ đây chính là điểm khác biệt lớn nhất giữa lập trình viên mới học Go và những người quen với các ngôn ngữ thế hệ cũ. Thay vì loay hoay với mutex hay semaphore, chúng ta được học cách tư duy theo mô hình CSP (Communicating Sequential Processes) một cách tự nhiên. Và như mọi hành trình học hỏi mới mẻ khác, những bước đi đầu tiên luôn đầy bỡ ngỡ nhưng lại tràn đầy hứng khởi.

0%