eq2go/MODERNIZE.md
2025-08-07 12:47:52 -05:00

4.6 KiB

Package Modernization Instructions

Goal

Transform legacy packages to use generic MasterList pattern with simplified database operations.

Steps

1. Implement Generic MasterList Base

Create internal/common/master_list.go with generic collection management:

type MasterList[K comparable, V Identifiable[K]] struct {
    items map[K]V
    mutex sync.RWMutex
}

2. Consolidate Package Structure

Remove:

  • Legacy wrapper functions (LoadAll, SaveAll, etc.)
  • Duplicate database files (database.go, database_legacy.go)
  • README.md (use doc.go instead)
  • Separate "active_record.go" files

Consolidate into:

  • {type}.go - Main type with embedded database operations
  • types.go - Supporting types only (no main type)
  • master.go - MasterList using generic base
  • player.go - Player-specific logic (if applicable)
  • doc.go - Primary documentation
  • {type}_test.go - Focused tests

3. Refactor Main Type

Transform the main type to include database operations:

// Before: Separate type and database operations
type Achievement struct {
    ID    uint32
    Title string
}

func LoadAchievement(db *database.Database, id uint32) (*Achievement, error)
func SaveAchievement(db *database.Database, a *Achievement) error

// After: Embedded database operations
type Achievement struct {
    ID    uint32
    Title string
    
    db    *database.Database
    isNew bool
}

func New(db *database.Database) *Achievement
func Load(db *database.Database, id uint32) (*Achievement, error)
func (a *Achievement) Save() error
func (a *Achievement) Delete() error
func (a *Achievement) Reload() error

4. Update MasterList

Replace manual implementation with generic base:

// Before: Manual thread-safety
type MasterList struct {
    items map[uint32]*Achievement
    mutex sync.RWMutex
}

func (m *MasterList) AddAchievement(a *Achievement) bool {
    m.mutex.Lock()
    defer m.mutex.Unlock()
    // manual implementation
}

// After: Generic base
type MasterList struct {
    *common.MasterList[uint32, *Achievement]
}

func NewMasterList() *MasterList {
    return &MasterList{
        MasterList: common.NewMasterList[uint32, *Achievement](),
    }
}

func (m *MasterList) AddAchievement(a *Achievement) bool {
    return m.MasterList.Add(a)
}

5. Implement Identifiable Interface

Ensure main type implements GetID():

func (a *Achievement) GetID() uint32 {
    return a.AchievementID  // or appropriate ID field
}

6. Simplify API

Remove:

  • Legacy type variants (Achievement vs AchievementRecord)
  • Conversion methods (ToLegacy, FromLegacy)
  • Duplicate CRUD operations
  • Complex wrapper functions

Keep:

  • Single type definition
  • Direct database methods on type
  • Domain-specific extensions only

7. Update Documentation

Create concise doc.go:

// Package achievements provides [brief description].
//
// Basic Usage:
//
//	achievement := achievements.New(db)
//	achievement.Title = "Dragon Slayer"
//	achievement.Save()
//
//	loaded, _ := achievements.Load(db, 1001)
//	loaded.Delete()
//
// Master List:
//
//	masterList := achievements.NewMasterList()
//	masterList.Add(achievement)
package achievements

8. Testing

Create focused tests:

  • Test core type operations (New, Save, Load, Delete)
  • Test MasterList basic operations
  • Remove legacy compatibility tests
  • Keep tests simple and direct

Key Principles

  1. Single Source of Truth: One type definition, not multiple variants
  2. Embedded Operations: Database methods on the type itself
  3. Generic Base: Use common.MasterList for thread-safety
  4. No Legacy Baggage: Remove all "Legacy" types and converters
  5. Documentation in Code: Use doc.go, not README.md

Migration Checklist

  • Create/verify generic MasterList in common package
  • Identify main type and supporting types
  • Consolidate database operations into main type
  • Add db field and methods to main type
  • Replace manual MasterList with generic base
  • Implement GetID() for Identifiable interface
  • Remove all legacy types and converters
  • Update doc.go with concise examples
  • Simplify tests to cover core functionality
  • Run go fmt and go test

Expected Results

  • 80% less code in most packages
  • Single type instead of multiple variants
  • Thread-safe operations via generic base
  • Consistent API across all packages
  • Better maintainability with less duplication

Example Commands

# Remove legacy files
rm README.md database_legacy.go active_record.go

# Rename if needed
mv active_record.go achievement.go

# Test the changes
go fmt ./...
go test ./...
go build ./...