Skip to content
This is my space, where experience meets the will to start over. This is my space, where experience meets the will to start over.

The first step is knowing where you want to go.

  • Home
  • Coding Hub
    • Software & Project
      • Small Biz Ops – S.B.O.
        • SmallBizOps – Day 10/90
      • CRM/ERP
      • MyTracker
      • My Budget
    • Form Zero to “WoW”
      • JavaScript from Zero (Completed)
        • 2. Remove and Edit List Items
        • 3. Separate HTML and JavaScript, Use addEventListener and Conditional Logic
        • 4. Add Dynamic CSS Classes
        • 5. Save & Restore Your List with localStorage
        • 6 – Turn Your App into a Full To-Do List
      • Python from Zero (Completed)
        • 2. Lists & Loops
        • 3. Conditional Menus
        • 4. Edit & Remove Tasks (with closing: Python vs PHP and Large Data)
        • 5 – Save to File: Make Your Tasks Survive Restarts
        • 6 — Pythin from zero – Final Project Polishing: Numbering, Formatting, and Preparing for CSV
      • Rust – From Zero to “WoW” (Completed)
        • 1 – Setup and Project Structure in Rust
        • 2 – User input: validation and error handling
        • 3 – Rust from Zero to “WoW – BMI Calculation and Conditional Logic
        • 4 –Rust – Clear, Formatted Output
        • 5 – Rust – Final Thoughts: Precision as a Form of Respect
      • Go from Zero to “WoW” (Completed)
        • 1 – Why Go Is Perfect for a Personal Expense Tracker
        • 2 – Logging Expenses and Console Input
        • 3 – Go from Zero to “WoW” – Smart Filtering & Display Logic
        • 4 – Go – Saving Data to Local Files
        • 5 – Go – Final Project – Expense Tracker in Go
      • C++ from Zero to “WoW” (Completed)
        • 1 – Why C++ for file organization?
        • 2 – C++ – File Type Detection and Classification
        • 3 – C++ – Creating & Managing Subfolders
        • 4 – C++ – Safe File Movement and User Feedback
        • 5 – C++ – Order as Mental Clarity
      • Ubuntu – From Zero to “WoW” (Completed)
        • 2 – Ubuntu – The Desktop Environment and Essential Commands
        • 3 – Ubuntu – Managing Files, Folders, and Permissions
        • 4 – Ubuntu – Installing and Updating Software with APT and Snap
        • 5 – Ubuntu – Customizing the Desktop Environment
        • 6 – Ubuntu – Network and Device Configuration
        • 7 – Ubuntu – User Management & System Security — “The Cathedral of Permissions”
        • 8 – Ubuntu – The Talking Machine: Terminal & Bash Scripting
        • 9 – Ubuntu – Ubuntu as a Server or Development Environment
        • 10 – Ubuntu – Backup, Maintenance & Troubleshooting
    • Git Hub Repository
      • Small Biz Ops – S.B.O.
      • Mini ERP – PHP & MySQL
      • CleverCRM (Java, Spring Boot)
      • FraudWatch (Python, FastAPI + scikit-learn)
      • OnboardIQ – Smart Onboarding Portal (Flask + SQLite Demo)
    • ArchPilot
      • 1-Users & Roles, End-to-End (Architecture, Database, and Cross-Framework Code)
      • 2 – Client Registry (CRM) Across Frameworks
      • 3 – Project & Budget Tracker (ERP)
      • 4 – Approval Workflow Engine Multi-step routing, status tracking, escalation paths
      • 5 – Audit Trail & Versioning
    • Small Biz Ops – S.B.O.
  • Vivere in USA
  • P4Y
  • Testi poetici
    • 1 – Sospeso
    • 2 – Il bicchiere di vetro quieto
    • 3 – Quando l’amore inciampa
    • 4 – Ma chi siete davvero?
    • 5 – Above the Thread of Day
    • 6 – The Truth That Doesn’t Exist
    • 7 – All of You, I Miss
    • 8 – The Captain and the Ocean
    • 9 – Between Light and Mist
    • 10 – Il peso delle scelte
  • Contact
  • Admin
This is my space, where experience meets the will to start over.
This is my space, where experience meets the will to start over.

The first step is knowing where you want to go.

Coding Step 12.4 Go – Saving Data to Local Files

Posted on 12 Ottobre 202512 Ottobre 2025 By Francesco

“Speed means nothing if your data disappears.”

Up to this point, our Go expense tracker can log new expenses, filter by category, and display summaries.
But a tracker that forgets everything when you close the terminal isn’t really a tracker — it’s a calculator with amnesia.

In this chapter, we’ll make it remember — by saving data locally, in a format that’s simple, reliable, and future-proof.
This is the Go way: no magic, no dependencies, just solid engineering.


4.1 The Goal

Save expenses in a way that’s:

  • Readable by both humans and programs.
  • Persistent across sessions.
  • Simple enough to extend later without breaking things.

The perfect fit? A plain CSV file — easy to read, easy to open in Excel, Google Sheets, or even Notepad.


4.2 The Go Philosophy: “Straightforward, not fragile”

Go was built for production systems.
That means everything — even file handling — follows one principle: do one thing well, and make it predictable.

With Go’s standard os and encoding/csv packages, you can handle all your data storage needs with just a few clean functions.
No external libraries, no YAML confusion, no broken JSON schemas.


4.3 The Data Structure

It all starts with something that’s both clear and expandable:

type Expense struct {
    Date     string  // esempio: "2025-10-12"
    Category string  // esempio: "Food", "Transport"
    Amount   float64 // esempio: 12.50
    Note     string  // esempio: "Lunch with friend"
}

Minimal, yet self-explanatory.
This is where the “Zero to WoW” mindset begins — a few lines that already feel intentional.


4.4 Version 1 – Full Save (overwrite)

The simplest reliable approach: write all expenses to the file each time you save.

import (
    "encoding/csv"
    "fmt"
    "os"
    "strconv"
)

func SaveExpenses(filename string, expenses []Expense) error {
    file, err := os.Create(filename)
    if err != nil {
        return fmt.Errorf("cannot create file: %v", err)
    }
    defer file.Close()

    writer := csv.NewWriter(file)
    defer writer.Flush()

    // Scriviamo l’intestazione per chiarezza
    writer.Write([]string{"Date", "Category", "Amount", "Note"})

    for _, e := range expenses {
        record := []string{
            e.Date,
            e.Category,
            strconv.FormatFloat(e.Amount, 'f', 2, 64),
            e.Note,
        }
        if err := writer.Write(record); err != nil {
            return fmt.Errorf("cannot write record: %v", err)
        }
    }

    fmt.Printf("💾 %d expenses saved to %s\n", len(expenses), filename)
    return nil
}

Output:
💾 5 expenses saved to expenses.csv

Generated File (expenses.csv):

Date,Category,Amount,Note
2025-10-10,Food,12.50,Lunch with friend
2025-10-10,Transport,3.00,Bus ticket
2025-10-11,Groceries,45.80,Weekly shopping
2025-10-11,Health,15.00,Pharmacy
2025-10-12,Entertainment,9.99,Streaming service

Readable. Portable. Reliable.
The kind of simplicity that quietly earns trust.


4.5 Version 2 – Incremental Save (append)

Sometimes, we just want to add a new expense without rewriting the entire file.
With Go, that’s a one-line change.

func AppendExpense(filename string, e Expense) error {
    // Se il file non esiste, lo creiamo
    fileExists := true
    if _, err := os.Stat(filename); os.IsNotExist(err) {
        fileExists = false
    }

    file, err := os.OpenFile(filename, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
    if err != nil {
        return fmt.Errorf("cannot open file: %v", err)
    }
    defer file.Close()

    writer := csv.NewWriter(file)
    defer writer.Flush()

    // Se è un nuovo file, scriviamo anche l’intestazione
    if !fileExists {
        writer.Write([]string{"Date", "Category", "Amount", "Note"})
    }

    record := []string{
        e.Date,
        e.Category,
        strconv.FormatFloat(e.Amount, 'f', 2, 64),
        e.Note,
    }

    if err := writer.Write(record); err != nil {
        return fmt.Errorf("cannot write record: %v", err)
    }

    fmt.Printf("➕ Added expense: %s (%s $%.2f)\n", e.Note, e.Category, e.Amount)
    return nil
}

Output:
➕ Added expense: Coffee (Food $2.50)

In Go, simplicity isn’t a limitation — it’s a survival skill.
Each function is small, pure, and easy to reason about.


4.6 Version 3 – Automatic Backup (because data deserves respect)

Before saving, let’s add a safety net: a quick backup of the existing file.

import "io"

func BackupFile(original string) error {
    backup := original + ".bak"
    in, err := os.Open(original)
    if err != nil {
        if os.IsNotExist(err) {
            return nil // Nessun file da copiare
        }
        return err
    }
    defer in.Close()

    out, err := os.Create(backup)
    if err != nil {
        return err
    }
    defer out.Close()

    if _, err := io.Copy(out, in); err != nil {
        return err
    }

    fmt.Println("🧩 Backup created:", backup)
    return nil
}

Then use it like this:

BackupFile("expenses.csv")
SaveExpenses("expenses.csv", expenses)

Output:

🧩 Backup created: expenses.csv.bak
💾 6 expenses saved to expenses.csv

A single extra function turns a “toy project” into something you’d actually trust.


4.7 Version 4 – Loading Data Back

Saving is only half of persistence.
Now we need to read everything back — exactly as it was.

func LoadExpenses(filename string) ([]Expense, error) {
    file, err := os.Open(filename)
    if err != nil {
        if os.IsNotExist(err) {
            fmt.Println("🆕 No existing data found — starting fresh.")
            return []Expense{}, nil
        }
        return nil, fmt.Errorf("cannot open file: %v", err)
    }
    defer file.Close()

    reader := csv.NewReader(file)
    records, err := reader.ReadAll()
    if err != nil {
        return nil, fmt.Errorf("cannot read file: %v", err)
    }

    var expenses []Expense
    for i, record := range records {
        if i == 0 { continue } // skip header
        amount, _ := strconv.ParseFloat(record[2], 64)
        expenses = append(expenses, Expense{
            Date:     record[0],
            Category: record[1],
            Amount:   amount,
            Note:     record[3],
        })
    }

    fmt.Printf("📂 Loaded %d expenses from file.\n", len(expenses))
    return expenses, nil
}

Output:
📂 Loaded 17 expenses from file.

4.8 Version 5 – JSON Option (interoperable and elegant)

CSV is universal, but sometimes JSON makes integration easier — for example, syncing with a web service later.
Go makes the switch effortless.

import (
    "encoding/json"
)

func SaveExpensesJSON(filename string, expenses []Expense) error {
    data, err := json.MarshalIndent(expenses, "", "  ")
    if err != nil {
        return err
    }
    return os.WriteFile(filename, data, 0644)
}

func LoadExpensesJSON(filename string) ([]Expense, error) {
    data, err := os.ReadFile(filename)
    if err != nil {
        if os.IsNotExist(err) {
            return []Expense{}, nil
        }
        return nil, err
    }

    var expenses []Expense
    if err := json.Unmarshal(data, &expenses); err != nil {
        return nil, err
    }

    fmt.Printf("📘 JSON loaded: %d records.\n", len(expenses))
    return expenses, nil
}

Example expenses.Jason 
[
  {
    "Date": "2025-10-10",
    "Category": "Food",
    "Amount": 12.50,
    "Note": "Lunch with friend"
  },
  {
    "Date": "2025-10-12",
    "Category": "Health",
    "Amount": 15.00,
    "Note": "Pharmacy"
  }
]

Readable. Shareable. Extendable.


4.9 The “WoW” Moment

Nothing flashy — just a small program that now remembers.
It quietly earns trust through reliability.

The wow doesn’t come from fancy frameworks or cloud APIs,
but from the feeling that your data is safe, your tool is honest, and your code makes sense.

Elegance isn’t about adding things — it’s about keeping only what’s essential.

This is the heart of From Zero to WoW:
real tools, built thoughtfully, that make life just a bit better.

Post Views: 263

Condividi:

  • Condividi su Facebook (Si apre in una nuova finestra) Facebook
  • Condividi su X (Si apre in una nuova finestra) X
Coding Form Zero to "WoW" Go

Navigazione articoli

Previous post
Next post

Francesco

My name is Francesco Boschi, originally from Italy and currently based in the United States. For over twenty years, I’ve worked as a manager and consultant across diverse sectors — from education and cultural institutions to the food industry — developing skills in operational management, strategic consulting, and complex problem-solving. In recent years, I’ve combined this experience with a strong passion for software development, creating custom tools designed to simplify workflows and meet real business needs.

Relocating to the U.S. marks the beginning of a new chapter: a personal and professional decision driven by the desire to be close to my son and to embrace new challenges in a different environment. Today, my goal is to turn my experience into meaningful solutions, blending strategic vision with technical expertise to help people and organizations work more effectively.

I enjoy moving between different worlds, adapting tools and approaches to people and contexts. I bring leadership, flexibility, attention to detail, analytical thinking, and a strong problem-solving mindset — along with a deep curiosity to learn and grow. Above all, I believe in sharing: I’m always eager to offer my experience to support the growth of others.

Related Posts

Coding

Coding – Step 2 – 🔐 Access Project Section

Posted on 6 Giugno 202526 Luglio 2025

In this section of the website, I share practical code examples that help highlight the differences between common web development technologies and structures. Each example is crafted to be clear, educational, and replicable, so anyone can understand the logic and experiment with the source code directly. 📌 Starting with a…

Condividi:

  • Condividi su Facebook (Si apre in una nuova finestra) Facebook
  • Condividi su X (Si apre in una nuova finestra) X
Read More
Coding

Coding – Step 11.3 – Rust from Zero to “WoW – BMI Calculation and Conditional Logic

Posted on 7 Ottobre 20257 Ottobre 2025

Learn how to calculate and interpret the Body Mass Index (BMI) using Rust. In this lesson, you’ll master input validation, conditional logic (if/else, match), and error handling with Result, while building a practical CLI program step by step.

Condividi:

  • Condividi su Facebook (Si apre in una nuova finestra) Facebook
  • Condividi su X (Si apre in una nuova finestra) X
Read More
C++

Coding – Step 13 – C++ from Zero to “WoW”

Posted on 5 Settembre 202527 Settembre 2025

A smart console-based file organizer written in C++ that scans folders and sorts files by type. Ideal for decluttering your desktop and restoring digital order — fast, efficient, and surprisingly elegant.

Condividi:

  • Condividi su Facebook (Si apre in una nuova finestra) Facebook
  • Condividi su X (Si apre in una nuova finestra) X
Read More

Iscriviti alla nostra Newsletter

🤞 Let's keep in touch

We do not send spam! Read our Privacy policy for more information.

Controlla la tua casella di posta o la cartella spam per confermare la tua iscrizione

Cerca nel sito

©2026 This is my space, where experience meets the will to start over. | WordPress Theme by SuperbThemes