# Code Organization Best Practices ## Project Structure ### Standard Go Project Layout ``` cv-website/ ├── cmd/ # Main applications │ └── server/ │ └── main.go # Application entry point │ ├── internal/ # Private application code │ ├── config/ # Configuration │ ├── handlers/ # HTTP handlers │ ├── middleware/ # HTTP middleware │ ├── models/ # Data models │ │ ├── cv/ # CV data structures │ │ └── ui/ # UI data structures │ ├── pdf/ # PDF generation │ ├── routes/ # Route setup │ └── templates/ # Template management │ ├── data/ # Static data files │ ├── cv-en.json │ ├── cv-es.json │ ├── ui-en.json │ └── ui-es.json │ ├── templates/ # HTML templates │ ├── index.html │ └── partials/ │ ├── header.html │ └── footer.html │ ├── static/ # Static assets │ ├── css/ │ ├── js/ │ └── images/ │ ├── tests/ # Test files │ └── integration/ │ ├── _go-learning/ # Educational documentation │ ├── diagrams/ │ ├── patterns/ │ ├── refactorings/ │ └── best-practices/ │ ├── go.mod # Go module definition ├── go.sum # Dependency checksums ├── Makefile # Build automation └── README.md # Project documentation ``` ## Package Organization Principles ### 1. Use `internal/` for Private Code ```go // ✅ GOOD: Private to this module internal/handlers/cv.go // ❌ BAD: Can be imported by other modules handlers/cv.go ``` **Why**: `internal/` prevents external packages from importing your code, enforcing API boundaries. ### 2. Group by Feature, Not Layer ```go // ✅ GOOD: Grouped by domain internal/ ├── handlers/ │ ├── cv.go │ ├── cv_pages.go │ ├── cv_htmx.go │ ├── cv_pdf.go │ ├── cv_helpers.go │ ├── types.go │ └── errors.go // ❌ BAD: Grouped by type internal/ ├── controllers/ ├── services/ ├── repositories/ └── dtos/ ``` **Why**: Feature-based organization makes code easier to navigate and refactor. ### 3. Separate Command from Library ```go // ✅ GOOD: Separate main package cmd/server/main.go # Entry point, wiring internal/handlers/ # Business logic // ❌ BAD: Everything in main package main.go handlers.go middleware.go ``` **Why**: Keeps `main` package small and focused on wiring, makes code reusable and testable. ## File Naming Conventions ### 1. Descriptive, Lowercase, Underscore-Separated ```go // ✅ GOOD cv_pages.go cv_htmx.go cv_helpers.go cv_pages_test.go // ❌ BAD cvPages.go // camelCase cv-pages.go // hyphen (not idiomatic) cvpages.go // too short, unclear ``` ### 2. Test Files Mirror Source Files ```go // Source files cv_pages.go cv_htmx.go // Test files cv_pages_test.go cv_htmx_test.go ``` ### 3. Group Related Functionality ```go // Related to CV handler cv.go // Constructor, shared state cv_pages.go // Page handlers cv_htmx.go // HTMX handlers cv_pdf.go // PDF export cv_helpers.go // Helper functions // Shared types and errors types.go // Request/response types errors.go // Error handling ``` ## Package Naming ### 1. Short, Concise, Lowercase ```go // ✅ GOOD package handlers package middleware package pdf // ❌ BAD package cvHandlers // Don't repeat package name package cv_handlers // No underscore package HTTPHandlers // No capitals ``` ### 2. No `common`, `util`, `base` ```go // ❌ BAD: Generic names package util package common package helpers // ✅ GOOD: Descriptive names package validation package templates package pdf ``` ### 3. Singular Names ```go // ✅ GOOD package handler // Even if multiple handlers package model // ❌ BAD package handlers // Plural (exception: when package name would conflict) package models ``` ## Code Organization Within Files ### 1. Logical Ordering ```go // ✅ GOOD: Logical flow package handlers // 1. Imports import ( "fmt" "net/http" ) // 2. Package-level constants/variables const MaxRetries = 3 // 3. Types type CVHandler struct { tmpl *templates.Manager } // 4. Constructor func NewCVHandler(tmpl *templates.Manager) *CVHandler { return &CVHandler{tmpl: tmpl} } // 5. Public methods (alphabetical or logical order) func (h *CVHandler) Home(w http.ResponseWriter, r *http.Request) { // ... } // 6. Private methods (alphabetical or logical order) func (h *CVHandler) prepareTemplateData(lang string) (map[string]interface{}, error) { // ... } // 7. Helper functions func validateLanguage(lang string) error { // ... } ``` ### 2. Group Related Code ```go // ✅ GOOD: Related functions grouped func (h *CVHandler) ToggleCVLength(w http.ResponseWriter, r *http.Request) { // ... } func (h *CVHandler) ToggleCVIcons(w http.ResponseWriter, r *http.Request) { // ... } func (h *CVHandler) ToggleCVTheme(w http.ResponseWriter, r *http.Request) { // ... } ``` ### 3. Separate Public and Private ```go // Public API func (h *CVHandler) Home(w http.ResponseWriter, r *http.Request) func (h *CVHandler) CVContent(w http.ResponseWriter, r *http.Request) // Private helpers (lowercase) func (h *CVHandler) prepareTemplateData(lang string) func (h *CVHandler) handleError(w http.ResponseWriter, r *http.Request, err error) ``` ## Import Organization ### 1. Group Imports ```go import ( // 1. Standard library "context" "fmt" "net/http" // 2. External packages "github.com/chromedp/chromedp" // 3. Internal packages "project/internal/middleware" "project/internal/models/cv" ) ``` ### 2. Use Blank Imports Sparingly ```go // ✅ GOOD: Document why import ( _ "github.com/lib/pq" // PostgreSQL driver ) // ❌ BAD: No comment import ( _ "github.com/lib/pq" ) ``` ## Avoiding Circular Dependencies ### Problem ```go // package a import "project/internal/b" // package b import "project/internal/a" // Compilation error: import cycle ``` ### Solution 1: Extract Interface ```go // package common type ServiceA interface { DoA() } // package a import "project/internal/common" func NewA(b common.ServiceB) *A { // Use interface } // package b // No import of package a ``` ### Solution 2: Create Third Package ```go // Before: a ↔ b (circular) // After: a → shared ← b // // shared/ contains types used by both ``` ## When to Split a File ### Signs a File is Too Large 1. **More than 500 lines** 2. **Multiple unrelated responsibilities** 3. **Difficult to navigate** 4. **Many scroll actions to find code** ### How to Split ```go // Before: cv.go (1000+ lines) // - Constructor // - Page handlers // - HTMX handlers // - PDF handler // - Helper functions // After: Split by responsibility cv.go // Constructor, shared state cv_pages.go // Page handlers (Home, CVContent) cv_htmx.go // HTMX handlers (4 toggles) cv_pdf.go // PDF export cv_helpers.go // Helper functions ``` ## Documentation ### 1. Package Documentation ```go // Package handlers provides HTTP request handlers for the CV website. // // Handlers are organized by resource: // - CVHandler: CV page rendering and HTMX updates // - HealthHandler: Health check endpoint // // All handlers follow the http.HandlerFunc signature and use // dependency injection for testability. package handlers ``` ### 2. Exported Function Documentation ```go // NewCVHandler creates a new CV handler with the given dependencies. // // The template manager is used for rendering HTML responses. // The host parameter is used to construct absolute URLs for SEO. // // Example: // // tmpl, _ := templates.NewManager(config) // handler := handlers.NewCVHandler(tmpl, "example.com") func NewCVHandler(tmpl *templates.Manager, host string) *CVHandler { return &CVHandler{ tmpl: tmpl, host: host, } } ``` ### 3. Complex Logic Documentation ```go // prepareTemplateData loads and processes all data needed for template rendering. // // The process involves: // 1. Load CV and UI data from JSON files // 2. Calculate experience durations // 3. Split skills into columns for display // 4. Build template data map with SEO metadata func (h *CVHandler) prepareTemplateData(lang string) (map[string]interface{}, error) { // ... } ``` ## Best Practices Checklist ### Package Structure - [ ] Use `internal/` for private code - [ ] Group by feature, not layer - [ ] Separate `cmd/` from library code - [ ] Avoid circular dependencies ### File Organization - [ ] Descriptive, lowercase names - [ ] Test files mirror source files - [ ] Related functionality grouped - [ ] Files < 500 lines ### Code Structure - [ ] Logical ordering (imports → types → constructor → methods) - [ ] Public before private - [ ] Related code grouped - [ ] Proper documentation ### Naming - [ ] Short package names (no `util`, `common`) - [ ] Clear, descriptive file names - [ ] Consistent naming across project - [ ] No redundant prefixes ## Anti-Patterns ### ❌ Flat Structure ```go // BAD: Everything in root main.go handlers.go middleware.go models.go utils.go helpers.go ``` ### ❌ Over-Nesting ```go // BAD: Too many levels internal/ └── domain/ └── services/ └── cv/ └── handlers/ └── http/ └── v1/ └── endpoints/ └── cv.go ``` ### ❌ God Packages ```go // BAD: One package does everything package app // 5000 lines of code handling everything ``` ## Real-World Example This project follows these principles: ``` ✅ Clear package boundaries ✅ Feature-based organization (handlers, models, middleware) ✅ Test files mirror source files ✅ No circular dependencies ✅ Appropriate use of internal/ ✅ Well-documented public API ✅ Logical file naming and organization ``` ## Further Reading - [Go Project Layout](https://github.com/golang-standards/project-layout) - [Package Organization](https://go.dev/blog/package-names) - [Code Review Comments](https://github.com/golang/go/wiki/CodeReviewComments)