Bonnes pratiques¶
Architecture¶
1. Domain isolation
Le domaine ne doit jamais importer d'autres packages:
// ❌ BAD - Domain importing adapter
package user
import "mon-projet/internal/adapters/repository" // NO!
// :material-check-circle: GOOD - Domain only imports interfaces
package user
import "mon-projet/internal/interfaces"
2. Single Responsibility Principle
Chaque composant a une seule responsabilité:
- Handlers: Parse + validate + call service
- Services: Business logic uniquement
- Repositories: Data access uniquement
3. Dependency Injection
Toujours via fx.Provide, pas de variables globales:
// ❌ BAD - Global variable
var db *gorm.DB
// :material-check-circle: GOOD - Injection
type UserService struct {
db *gorm.DB
}
func NewUserService(db *gorm.DB) *UserService {
return &UserService{db: db}
}
Code style¶
1. gofmt
Toujours formater:
Ou configurer l'IDE pour formater à la sauvegarde.
2. golangci-lint
Respecter les règles:
3. Documentation GoDoc
Pour les exports publics:
// UserService handles user-related business logic.
// It provides methods for user registration, authentication, and CRUD operations.
type UserService struct {
repo interfaces.UserRepository
logger zerolog.Logger
}
// Register creates a new user with the provided email and password.
// The password is automatically hashed before storage.
// Returns an error if the email already exists or if validation fails.
func (s *UserService) Register(ctx context.Context, email, password string) (*User, error) {
// ...
}
4. Error handling explicite
Toujours gérer les erreurs, ne pas utiliser panic:
// ❌ BAD
user := getUserByID(id) // What if error?
// :material-check-circle: GOOD
user, err := getUserByID(id)
if err != nil {
return nil, fmt.Errorf("failed to get user: %w", err)
}
Naming conventions¶
Interfaces:
- Suffixe -er ou -Service
- Exemples: UserRepository, AuthService, Logger
Repositories:
- Suffixe -Repository
- Exemples: UserRepository, ProductRepository
Handlers:
- Suffixe -Handler
- Exemples: AuthHandler, UserHandler
Constructeurs:
- Préfixe New
- Exemples: NewUserService, NewAuthHandler
Méthodes privées:
- lowerCamelCase
- Exemples: hashPassword, validateEmail
Error handling patterns¶
Wrap errors avec contexte:
// :material-check-circle: GOOD
if err != nil {
return fmt.Errorf("failed to create user %s: %w", email, err)
}
Domain errors pour logique métier:
Ne pas gérer les HTTP status dans le service:
// ❌ BAD - Service returning HTTP status
func (s *UserService) GetByID(id uint) (int, *User, error) {
return 404, nil, errors.New("not found")
}
// :material-check-circle: GOOD - Service returning domain error
func (s *UserService) GetByID(id uint) (*User, error) {
return nil, domain.NewNotFoundError("User not found", "USER_NOT_FOUND", nil)
}
Testing best practices¶
1. Coverage > 80%
2. Tests table-driven
tests := []struct {
name string
input string
want string
wantErr bool
}{
{"valid", "test", "TEST", false},
{"empty", "", "", true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ToUpper(tt.input)
if tt.wantErr {
assert.Error(t, err)
} else {
assert.Equal(t, tt.want, got)
}
})
}
3. Noms descriptifs
4. Setup/teardown avec t.Cleanup()
func TestSomething(t *testing.T) {
db := setupTestDB(t)
t.Cleanup(func() {
db.Exec("DELETE FROM users")
db.Close()
})
// Test code
}
Performance¶
1. GORM - Éviter N+1 queries
// ❌ N+1 problem
for _, user := range users {
db.Model(&user).Association("Posts").Find(&posts)
}
// :material-check-circle: Single query with Preload
db.Preload("Posts").Find(&users)
2. Context - Toujours passer context.Context
func (s *UserService) GetByID(ctx context.Context, id uint) (*User, error) {
return s.repo.FindByID(ctx, id)
}
3. Database indexes
4. Connection pooling
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
Sécurité recap¶
- [ ] Valider toutes les entrées utilisateur
- [ ] Jamais logger de passwords ou tokens
- [ ] Rate limiting sur endpoints publics
- [ ] HTTPS en production
- [ ] JWT secret fort (32+ caractères)
- [ ] Bcrypt pour passwords
- [ ] Mettre à jour les dépendances régulièrement
Conclusion¶
Ce guide couvre tous les aspects du développement avec les projets générés par create-go-starter. Pour aller plus loin:
- Exemples de code: Tous les patterns sont dans le code généré
- Tests: Regardez les fichiers
*_test.gopour des exemples - Documentation officielle:
- Fiber
- GORM
- fx
- zerolog
Bon développement! rocket_launch
Si vous rencontrez des problèmes ou avez des questions, consultez: - Issues GitHub - Discussions GitHub
Navigation¶
Previous: Monitoring
Index: Guide Index