Best Practices
This guide outlines the best practices and standards that all Solverhood developers should follow to maintain code quality, consistency, and maintainability across our projects.
๐๏ธ Architecture Best Practicesโ
1. Clean Architecture Principlesโ
Layer Separationโ
// Example of clean architecture layers
project/
โโโ cmd/ // Application entry points
โโโ internal/ // Private application code
โ โโโ domain/ // Business logic and entities
โ โโโ usecase/ // Application use cases
โ โโโ repository/ // Data access interfaces
โ โโโ delivery/ // HTTP/GraphQL handlers
โโโ pkg/ // Public packages
โโโ web/ // Frontend assets
Dependency Inversionโ
// Define interfaces in domain layer
type UserRepository interface {
Create(ctx context.Context, user *User) error
GetByID(ctx context.Context, id string) (*User, error)
Update(ctx context.Context, user *User) error
Delete(ctx context.Context, id string) error
}
// Implement in infrastructure layer
type postgresUserRepository struct {
db *sql.DB
}
func (r *postgresUserRepository) Create(ctx context.Context, user *User) error {
// Implementation
}
2. Domain-Driven Design (DDD)โ
Bounded Contextsโ
// Define clear boundaries between domains
type UserDomain struct {
userRepo UserRepository
eventBus EventBus
validator Validator
}
func (d *UserDomain) CreateUser(ctx context.Context, input CreateUserInput) (*User, error) {
// Business logic within domain
if err := d.validator.Validate(input); err != nil {
return nil, err
}
user := &User{
ID: uuid.New(),
Email: input.Email,
Name: input.Name,
}
if err := d.userRepo.Create(ctx, user); err != nil {
return nil, err
}
// Publish domain event
d.eventBus.Publish(UserCreatedEvent{User: user})
return user, nil
}
๐ป Code Quality Standardsโ
1. Go Best Practicesโ
Error Handlingโ
// โ
Good: Explicit error handling
func (s *UserService) GetUser(ctx context.Context, id string) (*User, error) {
user, err := s.repo.GetByID(ctx, id)
if err != nil {
return nil, fmt.Errorf("failed to get user %s: %w", id, err)
}
if user == nil {
return nil, ErrUserNotFound
}
return user, nil
}
// โ Bad: Ignoring errors
func (s *UserService) GetUser(ctx context.Context, id string) (*User, error) {
user, _ := s.repo.GetByID(ctx, id) // Don't ignore errors!
return user, nil
}
Context Usageโ
// โ
Good: Proper context usage
func (s *UserService) GetUser(ctx context.Context, id string) (*User, error) {
// Pass context to all operations
user, err := s.repo.GetByID(ctx, id)
if err != nil {
return nil, err
}
// Use context for timeouts
ctx, cancel := context.WithTimeout(ctx, 5*time.Second)
defer cancel()
return user, nil
}
Interface Designโ
// โ
Good: Small, focused interfaces
type UserReader interface {
GetByID(ctx context.Context, id string) (*User, error)
GetByEmail(ctx context.Context, email string) (*User, error)
}
type UserWriter interface {
Create(ctx context.Context, user *User) error
Update(ctx context.Context, user *User) error
Delete(ctx context.Context, id string) error
}
type UserRepository interface {
UserReader
UserWriter
}
2. TypeScript/React Best Practicesโ
Component Designโ
// โ
Good: Functional components with proper typing
interface UserCardProps {
user: User;
onEdit?: (user: User) => void;
onDelete?: (userId: string) => void;
}
export const UserCard: React.FC<UserCardProps> = ({ user, onEdit, onDelete }) => {
const handleEdit = useCallback(() => {
onEdit?.(user);
}, [user, onEdit]);
const handleDelete = useCallback(() => {
onDelete?.(user.id);
}, [user.id, onDelete]);
return (
<div className='user-card'>
<h3>{user.name}</h3>
<p>{user.email}</p>
<div className='actions'>
<button onClick={handleEdit}>Edit</button>
<button onClick={handleDelete}>Delete</button>
</div>
</div>
);
};
Custom Hooksโ
// โ
Good: Reusable custom hooks
export const useUser = (userId: string) => {
const [user, setUser] = useState<User | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);
useEffect(() => {
const fetchUser = async () => {
try {
setLoading(true);
const userData = await getUser(userId);
setUser(userData);
} catch (err) {
setError(err as Error);
} finally {
setLoading(false);
}
};
fetchUser();
}, [userId]);
return { user, loading, error };
};
State Managementโ
// โ
Good: Zustand store example
interface UserStore {
users: User[];
loading: boolean;
error: string | null;
fetchUsers: () => Promise<void>;
addUser: (user: User) => void;
updateUser: (id: string, updates: Partial<User>) => void;
deleteUser: (id: string) => void;
}
export const useUserStore = create<UserStore>((set, get) => ({
users: [],
loading: false,
error: null,
fetchUsers: async () => {
set({ loading: true, error: null });
try {
const users = await api.getUsers();
set({ users, loading: false });
} catch (error) {
set({ error: error.message, loading: false });
}
},
addUser: (user) => {
set((state) => ({ users: [...state.users, user] }));
},
updateUser: (id, updates) => {
set((state) => ({
users: state.users.map((user) => (user.id === id ? { ...user, ...updates } : user)),
}));
},
deleteUser: (id) => {
set((state) => ({
users: state.users.filter((user) => user.id !== id),
}));
},
}));
๐ Security Best Practicesโ
1. Authentication & Authorizationโ
JWT Token Handlingโ
// โ
Good: Secure JWT implementation
type Claims struct {
UserID string `json:"user_id"`
Role string `json:"role"`
jwt.RegisteredClaims
}
func GenerateToken(user *User, secret string) (string, error) {
claims := Claims{
UserID: user.ID,
Role: user.Role,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
IssuedAt: jwt.NewNumericDate(time.Now()),
NotBefore: jwt.NewNumericDate(time.Now()),
},
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(secret))
}
Input Validationโ
// โ
Good: Comprehensive input validation
type CreateUserInput struct {
Email string `json:"email" validate:"required,email"`
Name string `json:"name" validate:"required,min=2,max=100"`
Password string `json:"password" validate:"required,min=8"`
}
func (s *UserService) CreateUser(ctx context.Context, input CreateUserInput) (*User, error) {
// Validate input
if err := s.validator.Struct(input); err != nil {
return nil, fmt.Errorf("validation failed: %w", err)
}
// Sanitize input
input.Name = strings.TrimSpace(input.Name)
input.Email = strings.ToLower(strings.TrimSpace(input.Email))
// Hash password
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
if err != nil {
return nil, fmt.Errorf("failed to hash password: %w", err)
}
user := &User{
ID: uuid.New().String(),
Email: input.Email,
Name: input.Name,
Password: string(hashedPassword),
}
return user, nil
}
2. SQL Injection Preventionโ
// โ
Good: Use parameterized queries
func (r *postgresUserRepository) GetByEmail(ctx context.Context, email string) (*User, error) {
query := `SELECT id, email, name, created_at FROM users WHERE email = $1`
var user User
err := r.db.QueryRowContext(ctx, query, email).Scan(
&user.ID,
&user.Email,
&user.Name,
&user.CreatedAt,
)
if err != nil {
return nil, err
}
return &user, nil
}
// โ Bad: String concatenation (vulnerable to SQL injection)
func (r *postgresUserRepository) GetByEmail(ctx context.Context, email string) (*User, error) {
query := fmt.Sprintf("SELECT * FROM users WHERE email = '%s'", email) // DANGEROUS!
// ...
}
๐งช Testing Best Practicesโ
1. Unit Testingโ
Go Testingโ
// โ
Good: Comprehensive unit tests
func TestUserService_CreateUser(t *testing.T) {
tests := []struct {
name string
input CreateUserInput
want *User
wantErr bool
}{
{
name: "valid user",
input: CreateUserInput{
Email: "test@example.com",
Name: "Test User",
Password: "password123",
},
wantErr: false,
},
{
name: "invalid email",
input: CreateUserInput{
Email: "invalid-email",
Name: "Test User",
Password: "password123",
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Setup
mockRepo := &MockUserRepository{}
mockValidator := &MockValidator{}
service := NewUserService(mockRepo, mockValidator)
// Execute
got, err := service.CreateUser(context.Background(), tt.input)
// Assert
if (err != nil) != tt.wantErr {
t.Errorf("CreateUser() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && got == nil {
t.Error("CreateUser() returned nil user when no error expected")
}
})
}
}
React Testingโ
// โ
Good: React component testing
import { render, screen, fireEvent } from '@testing-library/react';
import { UserCard } from './UserCard';
describe('UserCard', () => {
const mockUser = {
id: '1',
name: 'John Doe',
email: 'john@example.com',
};
it('renders user information correctly', () => {
render(<UserCard user={mockUser} />);
expect(screen.getByText('John Doe')).toBeInTheDocument();
expect(screen.getByText('john@example.com')).toBeInTheDocument();
});
it('calls onEdit when edit button is clicked', () => {
const mockOnEdit = jest.fn();
render(<UserCard user={mockUser} onEdit={mockOnEdit} />);
fireEvent.click(screen.getByText('Edit'));
expect(mockOnEdit).toHaveBeenCalledWith(mockUser);
});
it('calls onDelete when delete button is clicked', () => {
const mockOnDelete = jest.fn();
render(<UserCard user={mockUser} onDelete={mockOnDelete} />);
fireEvent.click(screen.getByText('Delete'));
expect(mockOnDelete).toHaveBeenCalledWith('1');
});
});
2. Integration Testingโ
// โ
Good: Integration test with test database
func TestUserService_Integration(t *testing.T) {
// Setup test database
db, cleanup := setupTestDB(t)
defer cleanup()
// Setup service with real dependencies
repo := NewPostgresUserRepository(db)
validator := NewValidator()
service := NewUserService(repo, validator)
// Test complete flow
input := CreateUserInput{
Email: "test@example.com",
Name: "Test User",
Password: "password123",
}
user, err := service.CreateUser(context.Background(), input)
require.NoError(t, err)
require.NotNil(t, user)
// Verify user was saved
savedUser, err := service.GetUser(context.Background(), user.ID)
require.NoError(t, err)
require.Equal(t, user.ID, savedUser.ID)
require.Equal(t, input.Email, savedUser.Email)
}
๐ Performance Best Practicesโ
1. Database Optimizationโ
Query Optimizationโ
-- โ
Good: Optimized queries with proper indexes
CREATE INDEX idx_users_email ON users(email);
CREATE INDEX idx_users_created_at ON users(created_at);
CREATE INDEX idx_users_role_created_at ON users(role, created_at);
-- Use EXPLAIN to analyze query performance
EXPLAIN ANALYZE SELECT * FROM users WHERE email = 'test@example.com';
Connection Poolingโ
// โ
Good: Proper connection pooling
func NewDatabase(connStr string) (*sql.DB, error) {
db, err := sql.Open("postgres", connStr)
if err != nil {
return nil, err
}
// Configure connection pool
db.SetMaxOpenConns(25)
db.SetMaxIdleConns(5)
db.SetConnMaxLifetime(5 * time.Minute)
return db, nil
}
2. Caching Strategyโ
// โ
Good: Multi-layer caching
type CachedUserService struct {
userService UserService
cache Cache
}
func (s *CachedUserService) GetUser(ctx context.Context, id string) (*User, error) {
// Check cache first
if user, found := s.cache.Get(id); found {
return user.(*User), nil
}
// Fetch from service
user, err := s.userService.GetUser(ctx, id)
if err != nil {
return nil, err
}
// Cache for 5 minutes
s.cache.Set(id, user, 5*time.Minute)
return user, nil
}
๐ Git Best Practicesโ
1. Commit Messagesโ
# โ
Good: Conventional commit format
feat: add user authentication system
fix: resolve database connection timeout
docs: update API documentation
style: format code according to style guide
refactor: extract user validation logic
test: add unit tests for user service
chore: update dependencies
# โ Bad: Unclear commit messages
fix stuff
update
wip
2. Branch Strategyโ
# โ
Good: Feature branch workflow
git checkout -b feature/user-authentication
git checkout -b bugfix/fix-login-issue
git checkout -b hotfix/security-patch
# Commit and push
git add .
git commit -m "feat: implement user authentication"
git push origin feature/user-authentication
3. Pull Request Guidelinesโ
- Clear title: Describe the change concisely
- Detailed description: Explain what, why, and how
- Screenshots: For UI changes
- Tests: Include relevant tests
- Review checklist: Self-review before requesting review
๐ Documentation Best Practicesโ
1. Code Documentationโ
// โ
Good: Comprehensive code documentation
// UserService handles user-related business logic including creation,
// retrieval, updates, and deletion of user accounts.
type UserService struct {
repo UserRepository
validator Validator
eventBus EventBus
}
// CreateUser creates a new user account with the provided information.
// It validates the input, hashes the password, and publishes a UserCreated event.
//
// Parameters:
// - ctx: Context for request cancellation and timeouts
// - input: User creation data including email, name, and password
//
// Returns:
// - *User: The created user object
// - error: Any error that occurred during creation
func (s *UserService) CreateUser(ctx context.Context, input CreateUserInput) (*User, error) {
// Implementation
}
2. API Documentationโ
/**
* Creates a new user account
* @param input - User creation data
* @returns Promise resolving to the created user
* @throws {ValidationError} When input validation fails
* @throws {ConflictError} When email already exists
*/
export const createUser = async (input: CreateUserInput): Promise<User> => {
const response = await fetch('/api/users', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(input),
});
if (!response.ok) {
throw new Error(`Failed to create user: ${response.statusText}`);
}
return response.json();
};
๐ Deployment Best Practicesโ
1. Environment Configurationโ
# โ
Good: Environment-specific configuration
# docker-compose.yml
version: '3.8'
services:
app:
build: .
environment:
- NODE_ENV=production
- DATABASE_URL=${DATABASE_URL}
- REDIS_URL=${REDIS_URL}
env_file:
- .env.production
2. Health Checksโ
// โ
Good: Health check endpoint
func (s *Server) healthCheck(w http.ResponseWriter, r *http.Request) {
health := map[string]interface{}{
"status": "healthy",
"timestamp": time.Now().UTC(),
"version": s.version,
}
// Check database connectivity
if err := s.db.PingContext(r.Context()); err != nil {
health["status"] = "unhealthy"
health["database"] = "disconnected"
w.WriteHeader(http.StatusServiceUnavailable)
}
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(health)
}
These best practices ensure code quality, maintainability, and consistency across all Solverhood projects. Remember to review and update these practices regularly as our technology stack evolves.