192 lines
4.6 KiB
Markdown
192 lines
4.6 KiB
Markdown
# 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:
|
|
```go
|
|
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:
|
|
|
|
```go
|
|
// 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:
|
|
|
|
```go
|
|
// 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()`:
|
|
|
|
```go
|
|
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`:
|
|
|
|
```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
|
|
|
|
```bash
|
|
# 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 ./...
|
|
``` |