Learning
레슨 7 / 8·25분

실전: CLI 도구 만들기

프로젝트 개요

Go의 강점인 빠른 컴파일과 정적 바이너리 배포를 활용하여 간단한 TODO CLI 도구를 만들어 봅시다. 할 일을 추가, 목록 조회, 완료 처리할 수 있습니다.

데이터 구조 정의

go
package main

import (
    "encoding/json"
    "fmt"
    "os"
    "time"
)

type Todo struct {
    ID        int       'json:"id"'
    Title     string    'json:"title"'
    Done      bool      'json:"done"'
    CreatedAt time.Time 'json:"created_at"'
}

type TodoList struct {
    Todos    []Todo
    Filename string
}

func NewTodoList(filename string) *TodoList {
    tl := &TodoList{Filename: filename}
    tl.Load()
    return tl
}

CRUD 메서드 구현

go
func (tl *TodoList) Add(title string) {
    id := 1
    if len(tl.Todos) > 0 {
        id = tl.Todos[len(tl.Todos)-1].ID + 1
    }
    todo := Todo{
        ID:        id,
        Title:     title,
        Done:      false,
        CreatedAt: time.Now(),
    }
    tl.Todos = append(tl.Todos, todo)
    tl.Save()
    fmt.Printf("추가됨: [%d] %s\n", todo.ID, todo.Title)
}

func (tl *TodoList) List() {
    if len(tl.Todos) == 0 {
        fmt.Println("할 일이 없습니다.")
        return
    }
    for _, t := range tl.Todos {
        status := "[ ]"
        if t.Done {
            status = "[x]"
        }
        fmt.Printf("%s %d. %s\n", status, t.ID, t.Title)
    }
}

func (tl *TodoList) Complete(id int) {
    for i, t := range tl.Todos {
        if t.ID == id {
            tl.Todos[i].Done = true
            tl.Save()
            fmt.Printf("완료: %s\n", t.Title)
            return
        }
    }
    fmt.Printf("ID %d를 찾을 수 없습니다\n", id)
}

파일 저장/로드와 메인 함수

go
func (tl *TodoList) Save() {
    data, err := json.MarshalIndent(tl.Todos, "", "  ")
    if err != nil {
        fmt.Println("저장 에러:", err)
        return
    }
    os.WriteFile(tl.Filename, data, 0644)
}

func (tl *TodoList) Load() {
    data, err := os.ReadFile(tl.Filename)
    if err != nil {
        return  // 파일이 없으면 빈 목록
    }
    json.Unmarshal(data, &tl.Todos)
}

func main() {
    tl := NewTodoList("todos.json")

    if len(os.Args) < 2 {
        fmt.Println("사용법: todo [add|list|done] [인자]")
        return
    }

    switch os.Args[1] {
    case "add":
        if len(os.Args) < 3 {
            fmt.Println("사용법: todo add <제목>")
            return
        }
        tl.Add(os.Args[2])
    case "list":
        tl.List()
    case "done":
        if len(os.Args) < 3 {
            fmt.Println("사용법: todo done <ID>")
            return
        }
        var id int
        fmt.Sscanf(os.Args[2], "%d", &id)
        tl.Complete(id)
    default:
        fmt.Println("알 수 없는 명령:", os.Args[1])
    }
}
💡

go build -o todo .로 빌드하면 단일 실행 파일이 생성됩니다. Go는 크로스 컴파일도 쉽습니다: GOOS=linux go build -o todo-linux .로 Linux용 바이너리를 만들 수 있습니다.