DevOps

Ngày 1: Học một ngôn ngữ lập trình (Go)

Bức tranh toàn cảnh: DevOps & Học một ngôn ngữ lập trình

Nói một cách công bằng, bạn phải biết ít nhất một ngôn ngữ lập trình ở mức độ cơ bản để trở thành một kỹ sư DevOps thành công. Tôi muốn dành phần đầu tiên để tìm hiểu lý do tại sao điều này lại quan trọng như vậy và hi vọng rằng đến sau ngày hôm nay bạn sẽ hiểu rõ hơn về lý do, cách thức và những gì bạn có thể làm để thúc đẩy việc học của mình.

Nếu tôi hỏi trên các mạng xã hội rằng bạn có cần kỹ năng lập trình cho các vai trò liên quan tới DevOps hay không, câu trả lời khả năng cao là “có”. Hãy cho tôi biết nếu bạn không nghĩ như vậy. Nhưng câu hỏi lớn hơn và không có một câu trả lời rõ ràng là ngôn ngữ lập trình nào? Câu trả lời phổ biến nhất có thể là Python hoặc gần đây, ngày càng có nhiều người nói rằng bạn nên học Golang hoặc bạn cần phải học Go.

Hiểu tại sao bạn cần học một ngôn ngữ lập trình

Lý do mà Python và Go thường được khuyến nghị cho các kỹ sư DevOps là có rất nhiều công cụ DevOps được viết bằng Python hoặc Go, điều này rất quan trọng nếu bạn đang chuẩn bị xây dựng các công cụ DevOps và nó quyết định những gì bạn nên học để có lợi nhất. Nếu bạn đang muốn xây dựng hoặc tham gia một nhóm xây dựng các công cụ DevOps, thì việc học cùng một ngôn ngữ là rất hợp lý. Nếu bạn muốn tiếp cận với Kubernetes hoặc Containers thì khả năng cao lựa chọn của bạn sẽ là Go. Đối với tôi, công ty tôi đang làm việc (Kasten by Veeam) nằm trong hệ sinh thái Cloud-Native tập trung vào quản lý dữ liệu cho Kubernetes và mọi thứ được viết bằng Go.

Tuy nhiên, trong trường hợp nếu bạn không có một lý do rõ ràng như vậy ví dụ như bạn đang là sinh viên hoặc đang chuẩn bị cho một bước mới trong sự nghiệp của bạn thì tôi nghĩ bạn nên chọn thứ gì đó phù hợp với ứng dụng hoặc stack công nghệ mà bạn muốn làm việc cùng.

Hãy nhớ rằng chúng ta không muốn trở thành một nhà phát triển phần mềm ở đây mà chỉ muốn hiểu thêm về ngôn ngữ lập trình để có thể đọc và hiểu những công cụ đó đang làm gì từ đó có thể triển khai và cải thiện những thứ khác.

Một điều quan trọng cần biết nữa là cách bạn tương tác, làm việc với các công cụ DevOps, đó có thể là Kasten K10 hoặc Terraform và HCL. Chúng ta gọi chúng là các tệp (file) cấu hình và đó là cách bạn tương tác với các công cụ DevOps và biến mọi thứ thành hiện thực, thông thường sẽ là các file YAML

Xem thêm: Tự động hóa quản lý cấu hình

Tại sao là Go?

Tại sao Golang là ngôn ngữ lập trình tiếp theo cho DevOps và trở thành ngôn ngữ lập trình rất phổ biến trong những năm gần đây. Theo khảo sát của StackOverflow cho năm 2021, Go là ngôn ngữ lập trình đứng thứ 4 trong các ngôn ngữ lập trình, scripting và markup trong khi Python đứng thứ 1 nhưng hãy nghe tôi trình bày.

Tôi đã đề cập đến một số công cụ và nền tảng DevOps được biết đến nhiều nhất được viết bằng Go như Kubernetes, Docker, Grafana và Prometheus.

Xem thêm: Sử dụng Git hiệu quả

Những đặc điểm của Go khiến nó trở nên phù hợp với DevOps là gì?

Xây dựng và Triển khai với Go

Một lợi thế của việc sử dụng ngôn ngữ như Python trong vai trò DevOps là mã được thông dịch và bạn không cần phải biên dịch trước khi chạy các chương trình sử dụng Python. Đặc biệt với các tác vụ tự động hoá nhỏ, bạn không muốn mất thời gian cho quá trình biên dịch, dù vậy Go là một ngôn ngữ lập trình biên dịch và Go biên dịch trực tiếp ra mã máy. Go cũng nổi tiếng với tốc độ biên dịch nhanh.

Go với Python dành cho DevOps

Các chương trình Go được liên kết tĩnh, điều này có nghĩa khi bạn biên dịch một chương trình viết bằng Go, mọi thứ đều được bao gồm trong một tệp thực thi nhị phân duy nhất và không cần cài đặt thêm các phụ thuộc (dependencies) và thư viện bên ngoài trên các máy chủ. Điều này giúp cho việc triển khai các chương trình viết bằng Go dễ dàng hơn so với các chương trình Python sử dụng các thư viện bên ngoài nên bạn phải đảm bảo các thư viện được cài đặt trên máy chủ trước khi bạn có thể chạy chương trình.

Go là một ngôn ngữ độc lập với nền tảng, có nghĩa là bạn có thể tạo ra các tệp thực thi nhị phân cho tất cả các hệ điều hành như Linux, Windows, macOS,v.v và rất dễ để có thể làm như vậy với các hệ điều hành cụ thể. Python không dễ dàng tạo ra các tệp thực thi nhị phân cho các hệ điều hành như vậy.

Go là một ngôn ngữ có hiệu năng cao, nó có khả năng biên dịch, thời gian chạy nhanh và sử dụng ít tài nguyên hơn đặc biệt so với Python. Nhiều tối ưu hóa đã được viết bằng Go mang lại hiệu suất rất cao (nguồn bên dưới)

Xem thêm: Tổng quan về CI/CD pipelines

Không giống như Python thường yêu cầu sử dụng thư viện của bên thứ ba để triển khai một chương trình Python cụ thể, Go có một thư viện tiêu chuẩn có hầu hết các chức năng cần thiết cho DevOps được tích hợp sẵn. Nó bao gồm xử lý tệp, dịch vụ web HTTP, xử lý JSON, hỗ trợ cho xử lý đồng thời và song song (concurency, parallelism) cũng như kiểm thử tích hợp (built-in testing).

Điều này không có nghĩa là chúng ta vứt bỏ Python, tôi chỉ đưa ra những lý do để chọn Go. Nhưng thường thì lý do chính không phải như vậy, chủ yếu là do công ty tôi đang làm việc sử dụng Go để phát triển phần mềm.

Người ta nói rằng một khi bạn học được ngôn ngữ lập trình đầu tiên, việc tiếp nhận các ngôn ngữ khác trở nên dễ dàng hơn. Có lẽ không có công việc nào trong bất kỳ công ty nào không liên quan đến việc quản lý, architect, quản lý và gỡ lỗi các ứng dụng JavaScript hoặc Node JS.

Xem thêm: Điện toán đám mây

Thiết lập môi trường DevOps cho Go & Hello World

Trước khi tìm hiểu một số nguyên tắc cơ bản của Go, chúng ta nên cài đặt Go và làm điều mà mọi tiết học đầu tiên của môn “Lập trình 101” có – ứng dụng Hello World. Để cài đặt Go trên máy trạm của bạn, tôi sẽ cố gắng ghi lại toàn bộ quá trình bằng hình ảnh để mọi người có thể theo dõi.
Trước hết, hãy truy cập vào go.dev/dl và chúng ta sẽ có một số tùy chọn có sẵn để tải xuống.

Nếu bạn đã đi đến ngày hôm này, tôi nghĩ rằng bạn có thể biết hệ điều hành đang chạy trên máy của bạn là hệ điều hành nào.Hãy chọn bản tải xuống thích hợp và sau đó chúng ta có thể bắt đầu cài đặt. (Tôi sẽ sử dụng phiên bản mới nhất tại thời điểm viết bài, nhưng khi bạn đọc bài này, các phiên bản mới hơn có thể đã được phát hành)

Lưu ý rằng nếu bạn đã cài đặt một phiên bản cũ của Go, bạn sẽ phải gỡ bỏ phiên bản đó trước khi cài đặt, việc này được tính hợp trong trình cài đặt của Windows.

Sau khi hoàn tất, chúng ta sử dụng một dấu nhắc lệnh(command prompt)/terminal để kiểm tra xem chúng ta đã cài đặt Go thành công hay chưa. Nếu bạn không nhận được output như ở bên dưới thì Go chưa được cài đặt và bạn sẽ cần phải kiểm tra lại các bước thực hiện của mình.

go version

Tiếp theo, chúng ta sẽ kiểm tra môi trường cho Go để đảm bảo các việc các thư mục làm việc được cấu hình chính xác. Như bạn có thể thấy bên dưới, chúng ta cần đảm bảo rằng những thư mục sau có trên hệ thống của mình.

Bạn đã kiểm tra chưa? Bạn có đang theo kịp không? Bạn có thể sẽ nhận được một lỗi giống như dưới đây khi bạn thử và cố gắng điều hướng đến đó.

Được rồi, hãy tạo thư mục đó bằng cách sử dụng lệnh mkdir trong PowerShell terminal. Chúng ta cũng cần tạo 3 thư mục trong thư mục Go như bạn sẽ thấy bên dưới.

Sau khi chúng ta cài đặt Go và có các thư mục sẵn sàng cho Go hoạt động, chúng ta cần một môi trường phát triển tích hợp (IDE). Có rất nhiều lựa chọn mà bạn có thể sử dụng nhưng phổ biến nhất và code editor mà tôi sử dụng là Visual Studio Code hoặc Code thay cho IDE. Bạn có thể tìm hiểu thêm về các IDEs tại đây.

Nếu bạn chưa tải xuống và cài đặt VSCode trên máy trạm của mình thì bạn có thể thực hiện việc này bằng cách vào đây. Như bạn có thể thấy bên dưới, bạn có các lựa chọn cho các hệ điều hành khác nhau.

Tương tự như với việc cài đặt Go, chúng ta sẽ tải xuống và cài đặt và giữ nguyên các giá trị mặc định. Sau khi hoàn tất, bạn có thể mở VSCode, chọn Open File và điều hướng đến thư mục Go mà chúng ta đã tạo ở trên.

Bạn có thể nhận được một cửa sổ như dưới đây, hãy đọc nó nếu bạn muốn và sau đó nhấn Có và tin tưởng các tác giả (Tôi không chịu trách nhiệm sau này nếu bạn bắt đầu mở những thứ bạn không tin tưởng!)

Bây giờ bạn sẽ thấy ba thư mục chúng ta cũng đã tạo trước đó và những gì chúng ta muốn làm bây giờ là nhấp chuột phải vào thư mục src và tạo một thư mục mới có tên là Hello

Cho tới lúc này, mọi thứ khác dễ dàng đúng không? Bây giờ chúng ta sẽ tạo chương trình Go đầu tiên của mình mà không hiểu bất cứ thứ gì trong giai đoạn tiếp theo.

Tiếp theo, tạo một tệp có tên là main.go trong thư mục Hello. Ngay sau khi bạn nhấn Enter tại file main.go, bạn sẽ được hỏi xem bạn có muốn cài đặt tiện ích mở rộng (extension) cho Go không cũng như các các packages mới. Bạn cũng có thể kiểm tra xem liệu tệp pkg mà chúng ta đã tạo có một số packages mới trong đó hay không?

Bây giờ, hãy bắt đầu ứng dụng Hello World, sao chép mã sau vào tệp main.go mới của bạn và lưu lại.

package main

import "fmt"

func main() {
    fmt.Println("Hello #90DaysOfDevOps")
}

Bây giờ có thể chúng ta đang không hiểu tất cả những điều ở trên, nhưng chúng ta sẽ đề cập nhiều hơn về các chức năng, packages và các chủ để khác trong những ngày tiếp theo. Trở lại với terminal của bạn và thư mục Hello, chúng ta hãy kiểm tra liệu ứng dụng có chạy đúng hay không sử dụng lệnh bên dưới.

go run main.go

Tuy nhiên, không chỉ dừng lại tại đây, nếu chúng ta muốn chạy chương trình của mình trên các máy Windows khác thì sao? Chúng ta có thể xây dựng một tệp thực thi nhị phân bằng câu lệnh dưới đây

go build main.go

Nếu chúng ta chạy tệp đó tại một máy khác, kết quả vẫn sẽ giống như vậy:

$ ./main.exe
Hello #90DaysOfDevOps

Giải thích mã Hello World

Cách Go hoạt động

Trước đó chúng ta đã tiến hành cài đặt Go trên máy trạm của bạn sau đó tạo ứng dụng Go đầu tiên của mình.

Trong phần này, chúng ta sẽ xem xét sâu hơn về mã và tìm hiểu thêm một số điều về Go.

Biên dịch là gì

package main

import "fmt"

func main() {
    fmt.Println("Hello #90DaysOfDevOps")
}

Trước khi tìm hiểu về 6 dòng mã của Hello World, chúng ta cần hiểu về việc biên dịch.

Các ngôn ngữ lập trình mà chúng ta thường sử dụng như Python, Java, Go và C++ là các ngôn ngữ bậc cao. Có nghĩa là mã mà con người có thể đọc được, nhưng khi máy tính thực thi một chương trình, chúng cần phải được dịch ra mã máy. Quá trình đó được gọi là biên dịch.

Bạn có thể thấy những gì chúng ta đã làm  ở trên. Chúng ta đã tạo một tệp main.go đơn giản và sử dụng lệnh go build main.go để biên dịch ra một tệp thực thi.

Gói (Packages) là gì?

Gói là một tập hợp các tệp nguồn trong cùng một thư mục và được biên dịch cùng nhau. Nói một cách đơn giản hơn, một gói là một loạt các tệp .go trong cùng một thư mục. Bạn có nhớ thư mục Hello ở bài viết trước không? Khi bạn viết những chương trình phức tạp hơn bằng Go, bạn có thể thấy có folder1 folder2 và folder3 chứa các tệp .go khác nhau tạo nên chương trình với nhiều gói.

Chúng ta sử dụng các gói để có thể tái sử dụng lại mã của người khác để không phải viết mọi thứ từ đầu. Ví dụ chúng ta muốn có “máy tính” như một phần của chương trình, bạn có thể tìm thấy gói Go chứa các hàm toán học mà bạn có thể sử dụng, giúp bạn tiết kiệm rất nhiều thời gian và công sức.

Go khuyến khích bạn tổ chức mã của mình thành các gói để dễ dàng tái sử dụng và duy trì.

Hello #90DaysOfDevOps Từng dòng một

Bây giờ hãy xem qua tệp main.go của chúng ta.

Trong dòng đầu tiên, bạn có package main có nghĩa là tệp này thuộc về một gói có tên là main. Tất cả các tệp .go cần phải thuộc về một gói, chúng cũng phải có package something trong dòng mở đầu.

Một gói có thể được đặt tên tuỳ ý. Chúng ta bắt buộc phải gọi đây là main vì nó là điểm bắt đầu của chương trình sẽ có trong gói này, đây là một quy tắc. (Tôi cần hiểu thêm về quy tắc này?)

Bất cứ khi nào chúng ta muốn biên dịch và thực thi mã của mình, chúng ta phải cho máy biết nơi thực thi được bắt đầu. Chúng ta thực hiện điều này bằng cách viết một hàm có tên là main. Máy sẽ tìm kiếm một hàm có tên là main để bắt đầu chương trình.

Hàm là một khối mã có thể thực hiện một số tác vụ cụ thể và có thể được sử dụng trong toàn bộ chương trình.

Bạn có thể khai báo một hàm với bất kỳ tên nào bằng cách sử dụng func nhưng trong trường hợp này, chúng ta cần đặt tên nó là main vì đây là nơi mã bắt đầu.

Tiếp theo, chúng ta sẽ xem xét dòng 3, nơi chúng ta import, có nghĩa là bạn muốn đưa một gói khác vào chương trình chính của mình. fmt là một gói tiêu chuẩn do Go cung cấp, gói này chứa hàm Println() và vì chúng ta đã import hàm này nên có thể sử dụng tại dòng 6.

Có một số gói tiêu chuẩn chúng ta có thể đưa vào chương trình và tái sử dụng chúng trong mã, giúp tránh được những rắc rối khi phải viết lại từ đầu. Thư viện chuẩn của Go

Hàm Println() mà chúng ta có ở đây là một cách để ghi đầu ra tiêu chuẩn (standard output) tại thiết bị đầu cuối – nơi mà tệp thực thi đã được thực thi thành công. Bạn có thể tự do thay đổi đoạn mã ở giữa ().

TLDR

  • Dòng 1 = Tệp này sẽ nằm trong gói có tên là main và nó cần được gọi là main vì đó là điểm bắt đầu của chương trình.
  • Dòng 3 = Để chúng ta có thể sử dụng hàm Println(), cần phải import gói fmt để sử dụng gói này tại dòng 6.
  • Dòng 5 = Điểm bắt đầu thực tế, hàm main.
  • Dòng 6 = Điều này sẽ cho phép chúng ta in “Hello #90DaysOfDevOps” trên hệ thống.

Không gian làm việc của Go

chúng ta đã giới thiệu qua về không gian làm việc của Go, khởi động và demo bằng chương trình Hello #90DaysOfDevOps. Tuy nhiên cũng nên tìm hiểu kỹ hơn về không gian làm việc Go.

Hãy nhớ rằng chúng ta đã chọn các giá trị mặc định khi cài đặt Go và sau đó đã tạo các thư mục Go trong GOPATH mặc định đó nhưng trên thực tế, GOPATH có thể được thay đổi thành bất cứ nơi nào bạn muốn.

Nếu bạn chạy

echo $GOPATH

Đầu ra sẽ tương tự như thế này (tên người dùng có thể sẽ khác):

/home/michael/projects/go

Sau đó, ở đây, chúng ta đã tạo 3 thư mục. src, pkg and bin

src là nơi lưu trữ tất cả các chương trình và dự án Go. Điều này xử lý việc quản lý không gian tên của các gói (packages) cho tất cả các kho lưu trữ (repositories) Go. Ở đây bạn có thể thấy rằng máy trạm của tôi có thư mục Hello cho dự án Hello #90DaysOfDevOps.

pkg là một tệp lưu trữ của các gói đã hoặc đang được cài đặt trong chương trình. Điều này giúp tăng tốc quá trình biên dịch dựa trên việc các gói được sử dụng có thay đổi hay không.

bin là nơi lưu trữ tất cả các tệp nhị phân đã được biên dịch.

Hello #90DaysOfDevOps không phải là một chương trình phức tạp, đây là một ví dụ về chương trình Go phức tạp hơn được lấy từ một tài nguyên tuyệt vời khác GoChronicles

Bạn cũng có thể đi sâu vào một số chi tiết về lý do và cách tổ chức một dự án Go. Nó cũng đi sâu hơn một chút về các thư mục khác mà chúng ta chưa đề cập đến GoChronicles

Biên dịch & Chạy mã

Chúng ta cũng đã giới thiệu sơ qua về việc biên dịch mã nhưng hãy đi sâu hơn một chút.
Cần phải biên dịch mã trước khi chạy mã. Có 3 cách để làm vậy với Go

  • go build
  • go install
  • go run

Trước khi đến giai đoạn biên dịch ở trên, chúng ta cần xem xét những gì nhận được sau khi cài đặt Go.

Khi cài đặt Go chúng ta đã cài đặt một thứ được gọi là công cụ Go bao gồm một số chương trình cho phép xây dựng và xử lý các tệp mã nguồn Go của mình. Một trong số những công cụ đó là go

Điều đáng chú ý là bạn có thể cài đặt thêm các công cụ không có trong bản cài đặt Go tiêu chuẩn.

Nếu bạn mở dấu nhắc lệnh của mình và nhập go, bạn sẽ thấy như hình ảnh dưới đây và sau đó bạn sẽ thấy “một số những câu lệnh khác” phía bên dưới, tuy nhiên không chưa cần phải quan tâm tới chúng.

Bạn cũng có thể nhớ rằng chúng ta đã sử dụng ít nhất hai công cụ

Những thứ chúng ta muốn tìm hiểu thêm là build, install and run.

  • go run – Lệnh này biên dịch và chạy gói chính bao gồm các tệp .go được chỉ định trên dòng lệnh. Các file biên dịch được lưu trữ trong một thư mục tạm thời.
  • go build – Để biên dịch các gói và phần phụ thuộc trong thư mục hiện tại. Nếu là gói main, sẽ đặt tệp thực thi trong thư mục hiện tại, nếu không, tệp thực thi sẽ được đặt trong thư mục pkg. go build cũng cho phép bạn tạo một tệp thực thi cho bất kỳ nền tảng, hệ điều hành được hỗ trợ bởi của Go.
  • go install – Tương tự như go build nhưng sẽ đặt tệp thi hành vào thư mục bin

Chúng ta đã chạy qua go build và go run nhưng vui lòng chạy lại chúng ở đây nếu bạn muốn, go install như đã nêu ở trên đặt tệp thực thi vào thư mục bin của chúng ta.

Chúng ta đã sử dụng go build và go run nhưng hãy thử lại nếu bạn muốn, go install như đã trình bày ở trên, sẽ đặt tệp thực thi trong thư mục bin.

Tiếp theo chúng ta sẽ tìm hiểu về Biến, Hằng số và Kiểu dữ liệu trong khi viết một chương trình mới.

Biến và Hằng số trong Go

Hãy bắt đầu bằng cách lên kế hoạch cho ứng dụng của chúng ta. Tôi nghĩ một chương trình cho bạn biết số ngày còn lại trong thử thách #90DaysOfDevOps sẽ là một ý tưởng hay

Đầu tiên là khi chúng ta xây dựng ứng dụng, nó chào mừng người tham gia và nhận phản hồi từ người dùng về số ngày đã hoàn thành. Chúng ta có thể sử dụng thuật ngữ #90DaysOfDevOps nhiều lần trong suốt chương trình và đây là trường hợp hoàn hảo để #90DaysOfDevOps trở thành một biến trong chương trình.

  • Các biến được sử dụng để lưu trữ các giá trị.
  • Giống như một hộp nhỏ chứa thông tin hoặc giá trị của chúng ta.
  • Biến này có thể được sử dụng trong suốt chương trình và cũng có ưu điểm là nếu bạn muốn thay đổi tên thử thách hoặc biến này, bạn chỉ phải thay đổi nó ở một nơi. Nói cách khác, bằng cách thay đổi một giá trị của biến này, nó có thể được chuyển sang các tên các thử thách khác trong cộng đồng.

Để khai báo điều này trong Go, hãy sử dụng từ khóa cho các biến. Khai báo này sẽ được sử dụng trong khối mã func main mà chúng ta sẽ nhắc tới sau. Giải thích chi tết về Từ khoá tại đây.

Hãy nhớ rằng tên biến có tính mô tả. Nếu bạn khai báo một biến, bạn phải sử dụng nó hoặc bạn sẽ gặp lỗi, điều này để tránh có thể có mã chết (mã không bao giờ được sử dụng). Điều này cũng tương tự cho các gói (packages) không được sử dụng.

var challenge = "#90DaysOfDevOps"

Với khai báo ở trên, bạn có thể thấy chúng ta đã sử dụng một biến khi in ra chuỗi ký tự ở đoạn mã dưới đây.

package main

import "fmt"

func main() {
    var challenge = "#90DaysOfDevOps"
    fmt.Println("Welcome to", challenge, "")
}

Sau đó, chúng ta xây dựng mã của với ví dụ trên và nhận được kết quả hiển thị như dưới đây.

Chúng ta cũng biết rằng thử thách này kéo dài ít nhất 90 ngày, nhưng với thử thách tiếp theo, nó có thể là 100 ngày, chính vì thế, chúng ta cũng cần một biến ở đây. Tuy nhiên, với chương trình này, chúng ta muốn khai báo nó như một hằng số. Các hằng số cũng giống như các biến, ngoại trừ việc giá trị của chúng không thể thay đổi trong đoạn mã (chúng ta vẫn có thể tạo một ứng dụng mới với mã được giữ nguyên và thay đổi hằng số này nhưng giá trị 90 sẽ không thay đổi khi chúng ta chạy ứng dụng của mình)

Thêm const vào mã và thêm một dòng mã khác để in ra kết quả.

package main

import "fmt"

func main() {
    var challenge = "#90DaysOfDevOps"
    const daystotal = 90

    fmt.Println("Welcome to", challenge, "")
    fmt.Println("This is a", daystotal, "challenge")
}

Nếu chúng ta thực hiện lại câu lệnh go build và chạy lại, bạn sẽ thấy kết quả bên dưới.

Bây giờ ta sẽ thêm một biến khác cho số ngày đã hoàn thành trong thử thách.

Bên dưới, tôi đã thêm biến dayscomplete với số ngày đã hoàn thành.

package main

import "fmt"

func main() {
    var challenge = "#90DaysOfDevOps"
    const daystotal = 90
    var dayscomplete = 11

    fmt.Println("Welcome to", challenge, "")
    fmt.Println("This is a", daystotal, "challenge and you have completed", dayscomplete, "days")
    fmt.Println("Great work")
}

Hãy chạy lại lệnh go build hoặc có thể sử dụng go run

package main

import "fmt"

func main() {
	var challenge = "#90DaysOfDevOps"
	const daystotal = 90
	var dayscomplete = 11

	fmt.Printf("Welcome to %v\n", challenge)
	fmt.Printf("This is a %v challenge and you have completed %v days\n", daystotal, dayscomplete)
	fmt.Println("Great work")
}

Đây là một số ví dụ khác để làm cho mã dễ đọc và chỉnh sửa hơn. Hiện giờ, chúng ta vẫn đang sử dụng hàm Println nhưng nó có thể được đơn giản hóa bằng cách sử dụng Printf với %v, có nghĩa là các biến theo sẽ được xác định ở cuối dòng mã. Chúng ta cũng có thể sử dụng \n để xuống dòng.

Tôi đang sử dụng %v vì nó là giá trị mặc định, các tùy chọn khác có ở đây trong tài liệu của gói fmt.

Các biến cũng có thể được khai bảo một cách đơn giản hơn trong mã của bạn. Thay vì xác định rằng đó là var type, bạn có thể viết mã này như sau để có cùng kết quả nhưng đoạn mã sẽ gọn, đẹp và đơn giản hơn. Cách này chỉ áp dụng được với các biến, không sử dụng với hằng số.

func main() {
    challenge := "#90DaysOfDevOps"
    const daystotal = 90

Kiểu dữ liệu

Trong các ví dụ trên, chúng ta chưa xác định kiểu dữ liệu của biến, điều này là do chúng ta đã gán cho nó một giá trị và Go đủ thông minh để biết kiểu dữ liệu đó là gì hoặc ít nhất có thể suy ra nó là gì dựa trên giá trị bạn đã gán. Tuy nhiên, nếu chúng ta muốn người dùng nhập dữ liệu, chúng ta phải sử dụng một kiểu dữ liệu cụ thể.

Cho đến giờ, chúng ta đã sử dụng Chuỗi và Số nguyên trong mã của mình. Số nguyên cho số ngày và chuỗi là tên của thử thách.

Điều quan trọng cần lưu ý là mỗi kiểu dữ liệu có thể làm những việc khác nhau và hoạt động khác nhau. Ví dụ: số nguyên có thể nhân lên trong khi chuỗi thì không.
Có bốn loại:

  • Loại cơ bản – Basic type: Số, chuỗi và boolean (Numbers, strings, booleans)
  • Loại tổng hợp – Aggregate type: Mảng và cấu trúc (Array, structs)
  • Loại tham chiếu -Reference type: Con trỏ, lát cắt, bản đồ, chức năng và kênh (Pointers, slices, maps, functions, and channels)
  • Loại giao diện – Interface type

Kiểu dữ liệu là một khái niệm quan trọng trong lập trình. Kiểu dữ liệu chỉ định kích thước và kiểu của các giá trị biến.

Go được nhập tĩnh, có nghĩa là khi một kiểu dữ liệu của biến được xác định, nó chỉ có thể lưu trữ dữ liệu của kiểu đó.

Go có ba kiểu dữ liệu cơ bản:

  • bool: đại diện cho một giá trị boolean hoặc đúng hoặc sai
  • Numeric: đại diện cho kiểu số nguyên, giá trị dấu phẩy động và kiểu phức tạp
  • string: đại diện cho một giá trị chuỗi

Tôi thấy đây là nguồn tài liệu rất chi tết về các kiểu dữ liệu Golang by example

Tôi cũng sẽ đề xuất video Techworld with Nana. Tại thời điểm này, video đề cập chi tiết rất nhiều về các loại dữ liệu trong Go.

Chúng ta có thể làm như sau khi cần khai báo kiểu cho biến của mình:

var TwitterHandle string
var DaysCompleted uint

Bởi vì Go ngụ ý các biến trong đó một giá trị được đưa ra, chúng ta có thể in ra các giá trị đó như sau:

fmt.Printf("challenge is %T, daystotal is %T, dayscomplete is %T\n", conference, daystotal, dayscomplete)

Có nhiều kiểu số nguyên và kiểu float khác nhau, các liên kết ở trên sẽ trình bày chi tiết về những kiểu này.

  • int = số nguyên
  • unint = số nguyên dương
  • các loại dấu phẩy động = các số có chứa thành phần thập phân

Nhận thông tin đầu vào sử dụng con trỏ và chương trình hoàn thiện

Chúng ta đã tạo chương trình Go đầu tiên của mình độc lập và các phần nhận thông tin đầu vào của người dùng đã được tạo dưới dạng các biến trong mã với giá trị cho sẵn. Bây giờ chúng ta muốn hỏi người dùng cho đầu vào của họ để cung cấp cho biến giá trị để có thể in ra thông điệp cuối cùng.

Nhận thông tin đầu vào từ người dùng

Trước khi làm điều đó, chúng ta hãy xem xét lại ứng dụng của mình và xem qua các biến mà chúng ta muốn kiểm tra trước khi nhận thông tin đầu vào của người dùng.

Chúng ta đã xác định thủ công các biến và hằng số challenge, daystotal, dayscomplete.

Bây giờ hãy thêm một biến mới có tên là TwitterName, bạn có thể tìm thấy mã mới này tại day12_example1.go và đây sẽ là đầu ra nếu chạy mã này.

Bây giờ hãy thêm một biến mới có tên là TwitterName và đây sẽ là đầu ra nếu chạy mã này.

Chúng ta đang ở ngày thứ 12 và chúng ta sẽ cần phải thay đổi số ngày đã hoàn thành mỗi ngày và biên dịch lại mã nếu nó này là mã cứng (hard code), điều này có vẻ không tốt cho lắm

Nhận thông tin đầu vào của người dùng, giá trị có thể là tên và số ngày đã hoàn thành. Để thực hiện việc này, chúng ta có thể sử dụng một hàm khác từ bên trong gói fmt.

Các chức năng khác nhau cho đầu vào và đầu ra được định dạng (I/O) có trong gói fmt

  • In ra tin nhắn
  • Nhận thông tin đầu vào của người dùng
  • Ghi thành tệp

Thay vì chỉ định giá trị của một biến, chúng ta sẽ yêu cầu người dùng nhập thông tin đầu vào của họ.

fmt.Scan(&TwitterName)

Lưu ý việc sử dụng & trước biến. Đây được gọi là một con trỏ mà chúng ta sẽ đề cập trong phần tiếp theo.

Trong mã của chúng ta, bạn có thể thấy rằng chúng ta yêu cầu người dùng nhập hai biến, TwitterName DaysCompleted

Bây giờ hãy chạy chương trình và bạn thấy có đầu vào cho cả hai điều trên.

Được rồi, thật tuyệt, chúng ta đã nhận được thông tin người dùng nhập vào và in một tin nhắn nhưng vẫn còn việc cho biết còn bao nhiêu ngày trong thử thách của mình.

Để thực hiện điều đó, chúng ta sẽ tạo một biến có tên gọi là remainingDays và khai báo giá trị này trong mã của mình là 90, sau đó, thay đổi giá trị này để in ra những ngày còn lại sau khi nhận được thông tin người dùng nhập cho DaysCompleted. Có thể làm điều này với thay đổi biến đơn giản này.

remainingDays = remainingDays - DaysCompleted

Nếu chạy chương trình này, bạn có thể thấy phép tính đơn giản được thực hiện dựa trên đầu vào của người dùng và giá trị của remainingDays

Con trỏ là gì? (Biến đặc biệt)

Con trỏ là một biến (đặc biệt) trỏ đến địa chỉ bộ nhớ của một biến khác.

Bạn có thể đọc kỹ hơn tại geeksforgeeks

Hãy đơn giản hóa mã và xem chương trình thay đổi khi có và không có trước một các lệnh in của chúng ta, nó sẽ in ra địa chỉ bộ nhớ của con trỏ.

Dưới đây là kết quả chạy mã này

Tweet tiến trình của bạn với ứng dụng mới của chúng ta

Chúng ta mới chỉ tìm hiểu qua về những vấn đề nổi bật của ngôn ngữ này nhưng đó sẽ là lúc mà chúng ta cần hứng thú và hào hứng để có thể tìm hiểu sâu hơn về nó.

Chúng ta đã viết một ứng dụng từ ý tưởng nhỏ của chúng ta và đã thêm chức năng cho nó. Bây giờ, tôi muốn tận dụng các gói mà chúng ta đã đề cập tới và tạo ra một tính năng giúp chúng ta có thể cập nhận tiến trình của chúng ta trên màn hình mà còn có thể đăng một tweet với thông tin chi tiết về thử thách hiện tại.

Thêm chức năng tweet tiến trình

Điều đầu tiên chúng ta cần làm là thiết lập quyền truy cập API của Twitter để chức năng này có thể hoạt động.

Truy cập Twitter Developer Platform và đăng nhập với tài khoản Twitter của bạn và điền các thông tin cần thiết. Sau khi đó, bạn có thể thấy gì đó tương tự như ở dưới.

Sau đó, bạn cũng có thể muốn yêu cầu quyền truy cập nâng cao, việc này có thể mất một chút thời gian nhưng với tôi thì nó rất nhanh.

Tiếp theo, chúng ta nên chọn “Dự án & Ứng dụng” và tạo ứng dụng của mình. Giới hạn tùy thuộc vào quyền truy cập tài khoản mà bạn có, về cơ bản thì bạn sẽ có một ứng dụng và nếu dự án có quyền cao hơn, bạn có thể có 3 ứng dụng.

Đặt tên cho ứng dụng của bạn

Sau đó, bạn sẽ được cấp các mã API này, và bạn phải lưu chúng ở nơi an toàn. (Tôi đã xóa ứng dụng này) Chúng ta sẽ cần mã này ở các bước sau.

Sau khi ứng dụng của chúng ta được tạo (tôi phải thay đổi tên ứng dụng của mình vì tên ứng dụng trong ảnh chụp màn hình đã bị lấy, tên các ứng dụng phải khác nhau)

Các khóa mà chúng ta đã có được gọi là khóa khách hàng và chúng ta cũng sẽ cần mã truy cập và bí mật (access token and secrets). Chúng ta có thể xem thông tin này trong tab “Keys & Tokens”.

Bây giờ chúng ta đã hoàn tất việc chuẩn bị trên Twitter. Hãy đảm bảo rằng bạn giữ khóa của mình an toàn vì chúng ta sẽ cần chúng sau này.

Twitter Bot

Đây là mà chúng ta bắt đầu trong ứng dụng của mình nhưng trước tiên, chúng ta cần kiểm tra xem mã có đúng để tạo một tweet không

Chúng ta cần viết mã để đưa đầu ra hoặc tin nhắn tới Twitter dưới dạng một tweet. Chúng ta sẽ sử dụng go-twitter – một thư viện client viết bằng Go cho Twitter API.

Để kiểm tra trước khi đưa nó vào ứng dụng chính của chúng ta, tôi đã tạo một thư mục mới trong thư mục src có tên là go-twitter-bot, đã thực hiện lệnh go mod init github.com/michaelcade/go-Twitter-bot trên thư mục để tạo tệp go.mod để chúng ta có thể bắt đầu viết main.go mới của mình và kiểm tra điều này.

Bây giờ chúng ta cần các khóa, các tokens và secrets mà chúng ta lấy từ Twitter. Chúng ta sẽ đặt chúng trong các biến môi trường của hệ điều hành. Việc này sẽ phụ thuộc vào hệ điều hành của bạn:

Windows

set CONSUMER_KEY
set CONSUMER_SECRET
set ACCESS_TOKEN
set ACCESS_TOKEN_SECRET

Linux/macOS

export CONSUMER_KEY
export CONSUMER_SECRET
export ACCESS_TOKEN
export ACCESS_TOKEN_SECRET

Ở giai đoạn này bạn sẽ thấy ở đây rằng chúng ta sẽ sử dụng một cấu trúc (struct) để khai báo khóa, secrts và tokens.
Sau đó, chúng ta có một func để phân tích cú pháp các thông tin đăng nhập và tạo kết nối đó với API Twitter và nếu kết nối thành công, chúng ta sẽ gửi một tweet.

package main

import (
    // other imports
    "fmt"
    "log"
    "os"

    "github.com/dghubble/go-twitter/twitter"
    "github.com/dghubble/oauth1"
)

// Credentials stores all of our access/consumer tokens
// and secret keys needed for authentication against
// the twitter REST API.
type Credentials struct {
    ConsumerKey       string
    ConsumerSecret    string
    AccessToken       string
    AccessTokenSecret string
}

// getClient is a helper function that will return a twitter client
// that we can subsequently use to send tweets, or to stream new tweets
// this will take in a pointer to a Credential struct which will contain
// everything needed to authenticate and return a pointer to a twitter Client
// or an error
func getClient(creds *Credentials) (*twitter.Client, error) {
    // Pass in your consumer key (API Key) and your Consumer Secret (API Secret)
    config := oauth1.NewConfig(creds.ConsumerKey, creds.ConsumerSecret)
    // Pass in your Access Token and your Access Token Secret
    token := oauth1.NewToken(creds.AccessToken, creds.AccessTokenSecret)

    httpClient := config.Client(oauth1.NoContext, token)
    client := twitter.NewClient(httpClient)

    // Verify Credentials
    verifyParams := &twitter.AccountVerifyParams{
        SkipStatus:   twitter.Bool(true),
        IncludeEmail: twitter.Bool(true),
    }

    // we can retrieve the user and verify if the credentials
    // we have used successfully allow us to log in!
    user, _, err := client.Accounts.VerifyCredentials(verifyParams)
    if err != nil {
        return nil, err
    }

    log.Printf("User's ACCOUNT:\n%+v\n", user)
    return client, nil
}
func main() {
    fmt.Println("Go-Twitter Bot v0.01")
    creds := Credentials{
        AccessToken:       os.Getenv("ACCESS_TOKEN"),
        AccessTokenSecret: os.Getenv("ACCESS_TOKEN_SECRET"),
        ConsumerKey:       os.Getenv("CONSUMER_KEY"),
        ConsumerSecret:    os.Getenv("CONSUMER_SECRET"),
    }

    client, err := getClient(&creds)
    if err != nil {
        log.Println("Error getting Twitter Client")
        log.Println(err)
    }

    tweet, resp, err := client.Statuses.Update("A Test Tweet from the future, testing a #90DaysOfDevOps Program that tweets, tweet tweet", nil)
    if err != nil {
        log.Println(err)
    }
    log.Printf("%+v\n", resp)
    log.Printf("%+v\n", tweet)
}

Đoạn code trên hoặc là sẽ đưa ra một lỗi hoặc sẽ thành công và bạn sẽ có một tweet được gửi với nội dung như được nêu trong mã.

Kết hợp 2 thứ – Go-Twitter-bot và ứng dụng của chúng ta

Bây giờ chúng ta cần hợp nhất hai thứ này vào một file main.go. Chắc chắn sẽ có người cho rằng có cách làm tốt hơn cho việc này nhưng cách làm này có thể giúp chúng ta đạt được mục đích cuối cùng.

package main

import (
    // other imports
    "fmt"
    "log"
    "os"

    "github.com/dghubble/go-twitter/twitter"
    "github.com/dghubble/oauth1"
)

// Credentials stores all of our access/consumer tokens
// and secret keys needed for authentication against
// the twitter REST API.
type Credentials struct {
    ConsumerKey       string
    ConsumerSecret    string
    AccessToken       string
    AccessTokenSecret string
}

// getClient is a helper function that will return a twitter client
// that we can subsequently use to send tweets, or to stream new tweets
// this will take in a pointer to a Credential struct which will contain
// everything needed to authenticate and return a pointer to a twitter Client
// or an error
func getClient(creds *Credentials) (*twitter.Client, error) {
    // Pass in your consumer key (API Key) and your Consumer Secret (API Secret)
    config := oauth1.NewConfig(creds.ConsumerKey, creds.ConsumerSecret)
    // Pass in your Access Token and your Access Token Secret
    token := oauth1.NewToken(creds.AccessToken, creds.AccessTokenSecret)

    httpClient := config.Client(oauth1.NoContext, token)
    client := twitter.NewClient(httpClient)

    // Verify Credentials
    verifyParams := &twitter.AccountVerifyParams{
        SkipStatus:   twitter.Bool(true),
        IncludeEmail: twitter.Bool(true),
    }

    // we can retrieve the user and verify if the credentials
    // we have used successfully allow us to log in!
    user, _, err := client.Accounts.VerifyCredentials(verifyParams)
    if err != nil {
        return nil, err
    }

    log.Printf("User's ACCOUNT:\n%+v\n", user)
    return client, nil
}
func main() {
    creds := Credentials{
        AccessToken:       os.Getenv("ACCESS_TOKEN"),
        AccessTokenSecret: os.Getenv("ACCESS_TOKEN_SECRET"),
        ConsumerKey:       os.Getenv("CONSUMER_KEY"),
        ConsumerSecret:    os.Getenv("CONSUMER_SECRET"),
    }
    {
        const DaysTotal int = 90
        var remainingDays uint = 90
        challenge := "#90DaysOfDevOps"

        fmt.Printf("Welcome to the %v challenge.\nThis challenge consists of %v days\n", challenge, DaysTotal)

        var TwitterName string
        var DaysCompleted uint

        // asking for user input
        fmt.Println("Enter Your Twitter Handle: ")
        fmt.Scanln(&TwitterName)

        fmt.Println("How many days have you completed?: ")
        fmt.Scanln(&DaysCompleted)

        // calculate remaining days
        remainingDays = remainingDays - DaysCompleted

        //fmt.Printf("Thank you %v for taking part and completing %v days.\n", TwitterName, DaysCompleted)
        //fmt.Printf("You have %v days remaining for the %v challenge\n", remainingDays, challenge)
        // fmt.Println("Good luck")

        client, err := getClient(&creds)
        if err != nil {
            log.Println("Error getting Twitter Client, this is expected if you did not supply your Twitter API tokens")
            log.Println(err)
        }

        message := fmt.Sprintf("Hey I am %v I have been doing the %v for %v days and I have %v Days left", TwitterName, challenge, DaysCompleted, remainingDays)
        tweet, resp, err := client.Statuses.Update(message, nil)
        if err != nil {
            log.Println(err)
        }
        log.Printf("%+v\n", resp)
        log.Printf("%+v\n", tweet)
    }

}

Kết quả của việc chạy đoạn mã này sẽ là một tweet nhưng nếu bạn không cung cấp các biến môi trường của mình thì bạn có thể sẽ gặp lỗi như bên dưới.

Sau khi bạn đã khắc phục điều đó hoặc nếu bạn chọn không xác thực với Twitter thì bạn có thể sử dụng mã mà chúng ta đã hoàn thành trong ngày hôm qua. Kết quả cuối cùng sẽ giống như sau:

Tweet kết quả sẽ trông giống như sau:

Cách biên dịch cho nhiều hệ điều hành

Tiếp theo, tôi muốn đề cập đến câu hỏi, “Làm cách nào để bạn biên dịch cho nhiều Hệ điều hành?”. Điều tuyệt vời của Go là nó có thể dễ dàng biên dịch cho nhiều Hệ điều hành khác nhau. Bạn có thể nhận được danh sách đầy đủ bằng cách chạy lệnh sau:

go tool dist list

Việc sử dụng lệnh go build của chúng ta cho đến nay là rất tốt, nó sẽ sử dụng các biến môi trường GOOS và GOARCH để xác định hệ điều hành của máy chủ và bản dựng nên được xây dựng cho hệ điều hành nào. Dưới đây là một ví dụ.

GOARCH=amd64 GOOS=darwin go build -o ${BINARY_NAME}_0.1_darwin main.go
GOARCH=amd64 GOOS=linux go build -o ${BINARY_NAME}_0.1_linux main.go
GOARCH=amd64 GOOS=windows go build -o ${BINARY_NAME}_0.1_windows main.go
GOARCH=arm64 GOOS=linux go build -o ${BINARY_NAME}_0.1_linux_arm64 main.go
GOARCH=arm64 GOOS=darwin go build -o ${BINARY_NAME}_0.1_darwin_arm64 main.go

Các câu lệnh này sẽ cung cấp cho bạn các tệp nhị phân cho tất cả các nền tảng ở trên. Sau đó, bạn có thể lấy tệp này và tạo một makefile để tạo các tệp nhị phân này bất cứ khi nào bạn thêm các tính năng và chức năng mới vào mã của mình. Tôi đã bao gồm makefile

Đây là những gì tôi đã sử dụng để tạo các bản phát hành, bạn có thể tham khảo thêm tại git repository

Tài liệu tham khảo

Đây sẽ là kết thúc cho 1 ngày tìm hiểu về Ngôn ngữ lập trình trong Lộ trình học DevOps trong 12 ngày! Còn rất nhiều điều chúng ta cần tìm hiểu và tôi hy vọng bạn có thể tiếp tục thông qua các tài nguyên ở trên nhằm có thể hiểu một số khía cạnh khác của ngôn ngữ lập trình Go.

Tiếp theo, chúng ta tập trung vào Linux và một số nguyên tắc cơ bản mà tất cả chúng ta nên biết về nó.

Hẹn gặp lại các bạn vào Ngày 2: Kiến thức cơ bản về Linux

Các bài viết là bản tiếng Việt của tài liệu 90DaysOfDevOps của Micheal Cade và có qua sửa đổi, bổ sung. Tất cả đều có license [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License][cc-by-nc-sa]

Mọi thắc mắc xin hãy liên hệ
Email: [email protected]

(Nguồn: vntechies.dev)

Related Articles

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button