Welcome back to my journey of learning Golang! In this post, I will share my experience creating a Slackbot using Golang. As someone who has been exploring Golang for a few days now, I was excited to take on this new challenge and see what I could create.
I've always been interested in chatbots, I have created a whatsapp and telegram chatbot using Python, so I thought it would be interesting to build one with Golang. The main function of this Slackbot will be calculating age from year-of-birth (yob) and uploading files to slack channel.
You can find the source code in my Github for the uploading bot here and for the calculating age here. I make it different project because I want to use different package extension fro slackbot.
So for the uploading file slackbot, I use the package github.com/slack-go/slack, while for the calculating age, I use github.com/shomali11/slacker.
The Difference
From what I read, slack-go/slack is a fully-featured and comprehensive Slack API client library for Go, designed to handle all aspects of interacting with the Slack API. It offers a variety of features, including sending messages, managing channels and users, and responding to events.
On the other hand, shomali11/slacker is a simpler and more lightweight library for building Slack bots, which provides a basic framework for handling commands and generating responses. It is a good choice for simple Slack bot projects that require only basic functionality.
Both libraries have their own strengths and weaknesses, and the choice between them largely depends on the specific needs of the project. Slack-go/slack is a more powerful and comprehensive library that is suitable for larger projects or more complex interactions with the Slack API, while shomali11/slacker is a simpler and more lightweight option for smaller, simpler projects.
If you open the documentation or repository of shomali11/slacker, you might notice that it is actually built on top of the slack-go/slack. So I think it is a wrapper library that aims to provide a simpler and more intuitive interface for interacting with the Slack API.
Environtment Variable
Just like other project with programming language, Golang can also have environment variable. It can be set and retrieve with the standard package "os" like below code.
os.Setenv("SLACK_BOT_TOKEN", "your_bot_toke")
api := slack.New(os.Getenv("SLACK_BOT_TOKEN"))
The purpose of the environment variable is to share the same configuration across the project, and make it easy to develop or make change, since we just need to change the value of environment variable and it will takes effect on the entire project.
It can also to separate the configuration or important information that we dont want anyone to see it. We can make the ".env" file to store all the configuration, we just need an extra package to export the key and value from that file to our code, and it is github.com/joho/godotenv.
You just need to write the configuration format just like on NodeJS or Python project on the ".env" file, and load it with godotenv. Below is the example code on how to do it
.env file
SLACK_BOT_TOKEN=your_bot_token
main.go file
// load .env file
err := godotenv.Load(".env")
if err != nil {
log.Fatalf("Error loading .env file")
}
os.Getenv(key)
Goroutine
In Go programming language, a Goroutine is a lightweight thread of execution that runs concurrently with other Goroutines within the same address space. It's similar to a thread, but the difference is that Goroutines are more efficient and have a smaller memory footprint. Goroutines are managed by the Go runtime and can be created easily using the go keyword followed by a function call.
Goroutines allow for efficient concurrency in Go programs and can be used to perform multiple tasks simultaneously, making them a powerful tool for building high-performance systems. Below is the example on this project
go printCommandEvents(bot.CommandEvents())
This will creates a new Goroutine to execute the printCommandEvents() function, while the main Goroutine can continue running other code concurrently.
If you familiar with C#, this is similiar to how Coroutine work (hence the similiar name)
Context
A context in Go is a way to pass information between functions or processes. It can include things like deadlines, authentication information, or cancellation signals. It helps with managing and coordinating work across different parts of a program, especially when it comes to things like timeouts and error handling.
By using context, you can ensure that different parts of your program are all working together effectively and efficiently. Below is the example that I use in my project.
// Create a new context
ctx, cancel := context.WithCancel(context.Background())
// Defer a cancel function to ensure that the context is closed when the function returns
defer cancel()
// Pass the context to the Listen function
err := bot.Listen(ctx)
if err != nil {
log.Fatal(err)
}
In this example, I create a new context using context.Background() as the parent context. We also create a cancel function using context.WithCancel() which will be used to cancel the context later. We then pass this context to the Listen function. Finally, we use defer to ensure that the cancel function is called when the function returns, which will cancel the context and any child contexts that were created from it.
The defer keyword in Go schedules a function call to be executed at the end of the current function's scope, which in this case is the main() function. So, when the main() function completes its execution, the defer cancel() statement will be executed, and the cancel function will be called to stop the bot.Listen() function and any other operations that are running within the context.
Using context in this way ensures that we can cleanly cancel any ongoing operations when the context is closed.
Sure, here's another example to better understanding:
Let's say you have a function that reads data from a database and returns it as a slice of structs. Now, imagine this function takes a long time to run because it's querying a large dataset or because the database is slow. If you want to be able to cancel this function's execution in case the user decides to stop the operation or if there's an error, you can use the context package.
// Create a context with a 5 second timeout
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
// Call the function with the context
data, err := getData(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(data)
In this example, if the getData function takes longer than 5 seconds to complete, the ctx.Done() channel will be closed and the function will return an error.
Conclusion
In conclusion, learning how to create a Slackbot using Golang has been an exciting journey for me. I've learned about Goroutines and the importance of using Context to manage the lifecycle of a program.
There is also and always something that I didnt expain here that I learn, like what is and how channels work in Golang.
I hope that by sharing my experience, I've inspired you to dive deeper into the world of Golang and explore the endless possibilities it offers. Don't be afraid to experiment and make mistakes, as that is the best way to learn and grow as a developer.
Thank you for joining me on this journey, and I can't wait to see what I'll learn and create in the future!