tbmk - struggling with Go

16/11/2022 goterminal

#Why?

#Why Struggling?

Vì Slug của Vật lộn không được hay pepe_owo.

#Why Go?

Mình là một người có trí nhớ rất tệ, nhất là trong việc nhớ command. Nghĩ đến cái cảnh buổi sáng tìm command, chiều vẫn phải google lại đến là chán. Nào là command tìm PID theo port, ssh-keygen, git, hay thậm chí là install jdk (yep, bạn không đọc nhầm đâu). Ngoài các command nhiều arguments khó nhớ, thì còn có những command cần nhập file path dài thòng 😖. Nghĩ bụng chắc chắn phải có ai đó làm cái terminal mà cho phép bookmark lại command rồi chớ. Nhưng không, ông trời đâu chiều lòng người, mình tìm hoài không ra cái nào cho Linux - cụ thể là Ubuntu (đến giờ mới biết do mình search gà, haiz). Thế là mình quyết định …cho ý tưởng này vào todo list.

Hơn một năm sau đó, là hiện tại, đang lúc bí đề tài viết blog, mình hiện thực luôn cái ý tưởng này, bất chấp có rất nhiều tool hỗ trợ rồi.

Hmm, ban đầu thì cũng phân vân trong việc chọn Rust hay Go. Nhưng sau một hồi tìm kiếm thấy Go nhiều library hỗ trợ cái mình cần nên thôi thì gét Go golang.

#Vật lộn với Go

Là một người “dục tốc”, mình không đủ kiên nhẫn đọc kỹ docs, nên chỉ đọc lướt qua mục Tour of Go, dự định đến lúc cần gì sẽ search. Biết chắc chắn là sẽ “bất đạt”, nhưng thôi kệ cứ triển vậy. Và kết quả dĩ nhiên là mình đã phải search liên tục trong quá trình làm.

Cú pháp của Golang khác rất nhiều so với Java hay JS mà mình đang làm. Mình có cảm giác là mấy ông viết ngôn ngữ lập trình sợ bị nhận xét là “đạo” cú pháp hay sao ấy, nên họ luôn phải nghĩ ra các cú pháp mới. Điều này chỉ khổ cho Dev 😖. Dưới đây là một số khái niệm mình đã mất thời gian tìm hiểu, và so sánh với các ngôn ngữ mình đã, đang làm việc như Java, JS, PHP.

#Types

Go có một số các type khác biệt, một trong số đó là Pointer. Mặc dù thời sinh viên đã học C++, khái niệm này không còn xa lạ, tuy nhiên mình cũng mất thời gian để làm quen lại. Sơ qua thì mặc định Go pass argument cho function là pass by value. Giá trị khi truyền vào function sẽ được clone sang một địa chỉ mới. Trường hợp chúng ta muốn pass-by-reference thì cần pass poiter của biến.

#OOP

OOP của Go cũng rất khác. Go không có class, thay vào đó là struct. Struct chỉ khai báo property, khai báo method riêng bên ngoài và phải khai báo kèm với receiver.

Encapsulation cũng khá dị, được xác định theo Upper/lower case của ký tự đầu tiên của property/method. Uppercase = public, lowercase = private. Phần này không đọc docs từ đầu làm mình mất kha khá thời gian tìm hiểu vì sao mình không gọi được một function.

#Nil

Ban đầu mình cứ nghĩ nó đơn giản như null của Java nên không quan tâm lắm. Đến lúc muốn so sánh nil với value của struct thì aarrrghh 😡, thì ra nil chỉ dành cho một số type. Làm mình phải đi xác định “null” bằng giá trị của property, hơi phèn nhưng lười dùng Pointer 😅.

#Print

Trong quá trình làm tool tbmk, mình cần print nội dung ra terminal, sẽ không có gì đáng nói nếu như chỉ đơn giản là print. Nhưng sau đó mình cần assign giá trị trả về của chương trình cho một biến của Bash:

output=$(tbmk search -query="$query")

exploding, chương trình chạy nhưng terminal trắng trơn. Thì ra là khi dùng fmt.Print, Go sẽ write ra Stdout và biến output sẽ “nuốt” hết các nội dung mình muốn print ra. Mình đành lợi dụng Stderr cho việc hiển thị giao diện, còn giá trị cần return về sẽ vẫn write ra Stdout.

#tbmk

Không dài dòng nữa, đây là phần giới thiệu ẻm. Vì không nghĩ được tên gì hay nên mình lấy tạm viết tắt của Terminal bookmarker.

Code cực kỳ lởm, nhưng dù sao thì đây là thành quả của mình:

tbmk

Tính năng:

Hiện tại v1.0.0-beta-2 chỉ hoạt động trên Linux bash và Zsh. Có thời gian mình sẽ cố gắng update thêm cho shell khác, Windows terminal, cũng như Mac.

#Kết

Thank you for reading, here're some potatoes .