Dingo Dream

https://lets-go.alexedwards.net/

I was about to give up the idea of writing a web application in Go because I could not find an application framework like Spring or Django that helps with common stuff like

  • App Configuration
  • Authentication
  • Session Cookies
  • Form Validation
  • Flash Messages.
  • Optimistic Locking
  • Internationalization

But then a perplexity research presented this book to me with an even better approach then an application framework

The author develops the necessary helpers and infra code on his own with the standard library in a very pragmatic and easy to follow way. Only very few 3rd party libraries are used.

So in the end you have your application framework living inside your project. You understand the code and you can easily modify it. this is so much better than a big and complex framework like Spring that is never modified in practice and becomes a real pain when the "magic" is not working as exspected.

Application Architecture

graph TB
    subgraph Infrastructure ["Infrastructure"]
        DB["<br/>Database Connection<br/>sql.DB"] 
        EFS["<br/>Embedded FileSystem<br/>ui.Files"]
        LOG["<br/>Logger<br/>slog.Logger"]
    end
    
    subgraph DataAccessLayer ["Data Access Layer"]
        SM["<br/>SnippetModel<br/>models.SnippetModel"] --> DB
        UM["<br/>UserModel<br/>models.UserModel"] --> DB
        STORE["<br/>Session Store<br/>mysqlstore.Store"] --> DB
    end
    
    subgraph ApplicationLayer ["Application Layer"]
        CFG["<br/>Config<br/>main.config"]
        SESS["<br/>SessionManager<br/>scs.SessionManager"] --> STORE
        TC["<br/>Template Cache<br/>template.Template"]
        FD["<br/>Form Decoder<br/>form.Decoder"]
        VAL["<br/>Validator<br/>validator.Validator"]
        APP["<br/>Application with HTTP Handlers<br/>main.application"]
        APP --> SM
        APP --> UM
        APP --> SESS
        APP --> TC
        APP --> FD
        APP -.-> VAL
        APP --> CFG
    end
    
    subgraph TransportLayer ["Transport Layer"]
        SERVER["<br/>HTTP Server<br/>http.Server"] --> APP
        MW["<br/>Middleware Chain<br/>alice.Chain"] --> SESS
        MW --> APP
    end
    
    subgraph Legend ["Legend"]
        STDLIB["<br/>stdlib"] ~~~ CUSTOM["<br/>custom"] ~~~ THIRDPARTY["<br/>3rd party"]
    end
    
    
    %% Color Legend:
    %% Green: Internal Application Components
    %% Blue: Go Standard Library Components  
    %% Gray: External Library Components (3rd party dependencies)
    %% Gray: Internal Domain/Data Components
    
    style APP fill:#2e7d32,stroke:#1b5e20,stroke-width:3px,color:#ffffff
    style DB fill:#1976d2,stroke:#0d47a1,stroke-width:2px,color:#ffffff
    style SERVER fill:#1976d2,stroke:#0d47a1,stroke-width:2px,color:#ffffff
    style LOG fill:#1976d2,stroke:#0d47a1,stroke-width:2px,color:#ffffff
    style EFS fill:#2e7d32,stroke:#1b5e20,stroke-width:2px,color:#ffffff
    style SESS fill:#4d4d4d,stroke:#666666,stroke-width:2px,color:#ffffff
    style TC fill:#2e7d32,stroke:#1b5e20,stroke-width:2px,color:#ffffff
    style SM fill:#2e7d32,stroke:#1b5e20,stroke-width:2px,color:#ffffff
    style UM fill:#2e7d32,stroke:#1b5e20,stroke-width:2px,color:#ffffff
    style STORE fill:#4d4d4d,stroke:#666666,stroke-width:2px,color:#ffffff
    style VAL fill:#2e7d32,stroke:#1b5e20,stroke-width:2px,color:#ffffff
    style FD fill:#4d4d4d,stroke:#666666,stroke-width:2px,color:#ffffff
    style CFG fill:#2e7d32,stroke:#1b5e20,stroke-width:2px,color:#ffffff
    style MW fill:#4d4d4d,stroke:#666666,stroke-width:2px,color:#ffffff
    style STDLIB fill:#1976d2,stroke:#0d47a1,stroke-width:2px,color:#ffffff
    style CUSTOM fill:#2e7d32,stroke:#1b5e20,stroke-width:2px,color:#ffffff
    style THIRDPARTY fill:#4d4d4d,stroke:#666666,stroke-width:2px,color:#ffffff
    
    %% Subgraph styling with light yellow background and black text
    style Infrastructure fill:#fff7d9,stroke:#333,stroke-width:2px,color:#000000
    style DataAccessLayer fill:#fff7d9,stroke:#333,stroke-width:2px,color:#000000
    style ApplicationLayer fill:#fff7d9,stroke:#333,stroke-width:2px,color:#000000
    style TransportLayer fill:#fff7d9,stroke:#333,stroke-width:2px,color:#000000
    style Legend fill:#fff7d9,stroke:#333,stroke-width:2px,color:#000000

Also I am very happy with the Approach of writing SQL instead of using an ORM that generates the queries which I have some sometimes seen to have unintended and very negative consequences.

Optimistic Locking is introduced in the successor book: https://lets-go-further.alexedwards.net/

Internationalization is discussed here: https://www.alexedwards.net/blog/i18n-managing-translations