DEV Community

Sadia Ijaz
Sadia Ijaz

Posted on

Building a CLI Task Tracker with Go: My Learning Journey

Learning a new programming language is an opportunity to make mistakes, learn from them, and grow as a developer. Recently, I took on the challenge of learning Go (Golang) by building my first project: a CLI Task Tracker suggested by roadmap.sh.

This article highlights the mistakes I made, how I resolved them, and the valuable lessons I learned along the way.

Why Go and a CLI Task Tracker?

When learning Go, I wanted to work on a project that would be practical yet simple enough to grasp the basics. The CLI Task Tracker idea came from roadmap.sh, which suggested it as a beginner-friendly project.

I started learning Go through Hitesh Choudhary’s YouTube tutorials, which gave me a good foundation. Wanting to dive deeper, I turned to FreeCodeCamp’s resources, but they felt overwhelming and less beginner-friendly for my skill level at that time. Frustrated, I decided to tackle Go on my own and started working on the task tracker project. This hands-on approach forced me to learn through trial and error, confronting challenges head-on.

**

What is a CLI?

**
Before starting this project, I didn’t even know what a CLI (Command Line Interface) was. My experience was limited to GUIs (Graphical User Interfaces). During my research, I discovered that a CLI allows users to interact with their computer using text commands, offering a lightweight yet powerful way to execute tasks.

Initially, I found the idea of using a CLI intimidating. However, as I learned about its structure and experimented with basic commands, it started to feel much simpler. Understanding the power of CLIs gave me the confidence to move forward with the project.

**

Building the Task Tracker: Mistakes and Learning Moments

**
1. Using fmt.Scanln for Input
One of my first mistakes was using fmt.Scanln to gather user input. While it works for basic tasks, it’s not the right approach for building a CLI application, as it’s not designed for parsing multiple arguments or handling command-line commands efficiently.
Here’s an example of my early code:

fmt.Println("Enter Your First Name: ")
var first string
fmt.Scanln(&first)
fmt.Println("Enter Your Last Name: ")
var last string
fmt.Scanln(&last)
fmt.Println("Hello " + first + " " + last)

This approach is fine for learning input handling but completely unsuitable for a CLI tool. I soon realized that I needed to parse arguments passed via the command line rather than relying on runtime input.

2. Misusing the Deprecated ioutil Package
Another significant mistake was attempting to use the ioutil package for file operations. While researching Go’s standard library, I came across examples using ioutil, only to later discover that it had been deprecated. This meant I was using outdated and discouraged practices.
For example, I initially tried this:

data, err := ioutil.ReadFile("tasks.txt")
if err != nil {
fmt.Println("Error reading file:", err)
}
fmt.Println(string(data))

The correct approach was to switch to the newer os and io packages, which provide better functionality and are actively maintained. I replaced the above code with:

file, err := os.Open("tasks.txt")
if err != nil {
fmt.Println("Error opening file:", err)
return
}
defer file.Close()
data, err := io.ReadAll(file)
if err != nil {
fmt.Println("Error reading file:", err)
}
fmt.Println(string(data))

This mistake taught me the importance of checking documentation for updates before using a library or package.

. Sticking to os.Args Instead of Libraries

I decided to stick to Go’s standard library and used os.Args for parsing command-line arguments. While this approach works, it can become messy and hard to maintain as the application grows.

Here’s an example of how I used os.Args:

if len(os.Args) < 2 {
fmt.Println("Usage: task-cli <command> [arguments]")
return
}
command := os.Args[1]
switch command {
case "add":
fmt.Println("Adding a task…")
case "delete":
fmt.Println("Deleting a task…")
default:
fmt.Println("Unknown command:", command)
}

How I Sought Help

There were many times when I got stuck. To move forward, I turned to several resources:

Stack Overflow: I found answers to specific problems, such as parsing command-line arguments or handling file storage.

ChatGPT: I used AI to clarify concepts and find examples that were beginner-friendly.

Documentation: Reading the official Go documentation was invaluable, especially when I discovered that ioutil was deprecated and learned about alternatives like os and io.

This combination of resources helped me push through challenges and continue building my project.

Learning from Others
After completing my version of the task tracker, I decided to explore how other developers approached similar projects. I found that some solutions were similar to mine. However, others used more advanced tools like the cmd package, which provides a structured way to manage CLI commands.

Image description

While I don’t fully understand cmd yet, seeing its use has motivated me to learn more about Go's ecosystem and explore advanced techniques in future projects.

I chose not to use libraries like cobra or flag, which would have provided a more structured way to handle commands and arguments. While this was a deliberate decision to focus on learning Go's basics, I now realize how much easier those libraries would have made the development process.

**

Project Repo

**
GitHub: task-tracker-cli

**

Key Learnings

**

Mistakes Are Part of Learning: My mistakes, whether it was using fmt.Scanln or relying on ioutil, were valuable lessons. Each one helped me understand the right tools and practices for building robust CLI applications.
Stay Updated on Libraries and Best Practices: The ioutil package being deprecated was a wake-up call to always check the latest documentation and follow best practices to avoid outdated methods.
Start with the Basics Before Exploring Libraries: While I didn’t use advanced libraries like cobra, understanding the basics of os.Args and Go's standard library gave me a solid foundation. Now, I feel ready to explore these libraries in future projects.
Experiment and Compare Solutions: Looking at how others solved similar problems introduced me to tools and techniques I hadn’t considered. For example, I learned about flag and cobra through other developers' implementations, which motivated me to explore them.

Conclusion

Building a CLI Task Tracker in Go was an eye-opening experience. It was far from perfect, but it taught me the importance of starting small, making mistakes, and learning from them.

If you’re new to Go or CLI tools, my advice is simple: don’t be afraid to experiment, even if it means making a few mistakes. Each misstep is a chance to learn and improve. As for me, I’m excited to explore more of Go’s ecosystem and build on this foundation.

Connect with Me:
If you’d like to see more of my projects or share your feedback, feel free to connect with me:
GitHub: github.com/girldocode
Twitter: x.com/girldocode

Top comments (1)

Collapse
 
awaisalwaisy profile image
Alwaisy al-waisy

Interesting start.

The pain point in golang is folder structure. Once you mastered it, then no need to worry about in small to big project.

So you already on new venture for year 2025. Best