example

package
v0.0.0-...-a6b1af2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 12, 2026 License: Apache-2.0 Imports: 7 Imported by: 0

Documentation

Overview

Package example provides a demonstration of a well-structured Go module using the Uber FX framework for dependency injection. This module showcases common patterns and best practices for organizing Go code in a modular, maintainable way.

The example module is organized into several files, each with a specific responsibility:

  • config.go: Contains configuration structures for the module
  • domain.go: Defines domain entities and core business logic types
  • errors.go: Custom error definitions for the module
  • metrics.go: Prometheus metrics collection and reporting
  • models.go: Data models used by the module
  • module.go: FX module definition for dependency injection
  • repository.go: Data access layer implementation
  • service.go: Business logic and service layer implementation

This structure follows a clean architecture approach with clear separation of concerns.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrExample is a predefined error for the example module.
	//
	// This demonstrates how to create module-specific errors that can be
	// used throughout the codebase. In a real application, you might have
	// multiple error types for different error conditions.
	//
	// Usage:
	//   return fmt.Errorf("failed to process: %w", example.ErrExample)
	//
	// Checking:
	//   if errors.Is(err, example.ErrExample) {
	//       // Handle example error
	//   }
	ErrExample = errors.New("example error")
)

This file defines module-specific error types and values.

Having dedicated error types for a module provides several benefits:

  • Enables error handling specific to this module's domain
  • Allows for programmatic error type checking
  • Improves error message consistency
  • Makes debugging and troubleshooting easier

Example:

if err := processExample(); err != nil {
    if errors.Is(err, example.ErrExample) {
        // Handle specific example error
    }
    // Handle other errors
}

Functions

func Module

func Module() fx.Option

Module creates and returns an FX module for the example package.

This function defines how the example module should be wired into an application using the Uber FX dependency injection framework. It specifies all the components that make up the module and how they depend on each other.

The module includes:

  • A named logger for structured logging
  • A repository for data access (provided privately)
  • A service for business logic (provided publicly)

FX will automatically resolve dependencies and inject them where needed. For example, the Service depends on Config, Repository, Metrics, and Logger, so FX will ensure these are available when creating the Service.

Usage:

app := fx.New(
    example.Module(),
    // other modules...
)

// The Service can then be injected into other components:
fx.Invoke(func(service *example.Service) {
    // Use the service
})

Types

type Config

type Config struct {
	// Example is a configuration parameter that demonstrates how to include
	// custom configuration values in the module. This could be used for
	// feature flags, API endpoints, timeouts, or any other configurable
	// aspect of the module.
	Example string
}

Config holds the configuration for the example module.

This struct contains all the configuration parameters needed to initialize and configure the example module. Typically, these values would be loaded from environment variables, configuration files, or other configuration sources.

Example:

cfg := example.Config{
    Example: "demo-value",
}

service := example.New(cfg, repo, metrics, logger)

type Example

type Example struct {
	// In a real application, this would contain fields that represent
	// the state and properties of the domain entity.
	Value string
}

Example represents a domain entity in the example module.

This struct demonstrates the domain-driven design approach where core business concepts are modeled as domain entities. In a real application, this would contain business logic, validation, and behavior related to the concept it represents.

Domain entities are typically:

  • Rich in behavior, not just data
  • Responsible for maintaining their own integrity
  • Focused on business rules and logic

Example:

// In a real application, this might have methods like:
func (e *Example) Validate() error {
    // Validation logic
}

func (e *Example) Process() error {
    // Business logic
}

type Metrics

type Metrics struct {
	// contains filtered or unexported fields
}

Metrics handles Prometheus metrics collection for the example module.

This struct encapsulates all Prometheus metrics related to the example module. Having a dedicated metrics struct provides a clean way to organize and manage metrics, making it easier to add new metrics and maintain existing ones.

Metrics are important for:

  • Monitoring application health and performance
  • Tracking business metrics and KPIs
  • Setting up alerts and dashboards
  • Debugging and troubleshooting issues

Example:

metrics := example.NewMetrics()
metrics.IncTotal() // Increment the counter

func NewMetrics

func NewMetrics() *Metrics

NewMetrics creates and initializes a new Metrics instance.

This function serves as a constructor for the Metrics struct, initializing all the Prometheus metrics with their appropriate configuration.

The metrics defined here are:

  • example_total: A counter that tracks the total number of examples

Returns:

  • *Metrics: A pointer to the newly created Metrics instance

Example:

metrics := example.NewMetrics()
// Use metrics in your service
service := example.New(config, repo, metrics, logger)

func (*Metrics) IncTotal

func (m *Metrics) IncTotal()

IncTotal increments the total example counter.

This method should be called whenever an example is processed, created, or any other event occurs that should be tracked by the total counter.

Example:

func (s *Service) ProcessExample() error {
    // Process the example
    s.metrics.IncTotal() // Record the metric
    return nil
}

type Repository

type Repository struct {
	// contains filtered or unexported fields
}

Repository handles data access operations for the example module.

This struct represents the repository layer in a clean architecture pattern. The repository is responsible for all data access operations, abstracting the details of data storage and retrieval from the rest of the application.

Benefits of using a repository pattern:

  • Separates data access logic from business logic
  • Makes it easier to switch data sources (e.g., from SQL to NoSQL)
  • Centralizes data access operations
  • Improves testability by allowing mock repositories

In a real application, this struct would contain methods for:

  • Creating, reading, updating, and deleting (CRUD) data
  • Querying data with various filters
  • Handling transactions
  • Mapping between domain entities and data models

func NewRepository

func NewRepository() *Repository

NewRepository creates and initializes a new Repository instance.

This function serves as a constructor for the Repository struct. In a real application, it would typically accept dependencies like database connections, clients, or configuration needed to initialize the repository.

Returns:

  • *Repository: A pointer to the newly created Repository instance

Example:

repo := example.NewRepository()
// Use the repository in your service
service := example.New(config, repo, metrics, logger)

func (*Repository) Add

func (r *Repository) Add(item Example)

type Service

type Service struct {
	// contains filtered or unexported fields
}

Service implements the business logic for the example module.

This struct represents the service layer in a clean architecture pattern. The service is responsible for implementing business rules, orchestrating operations between different components, and exposing functionality to the rest of the application.

The Service depends on:

  • Config: For configuration parameters
  • Repository: For data access operations
  • Metrics: For collecting and reporting metrics
  • Logger: For structured logging

In a real application, this struct would contain methods for:

  • Business operations and workflows
  • Coordinating between repositories and other services
  • Enforcing business rules and validation
  • Handling errors and logging

func New

func New(config Config, examples *Repository, metrics *Metrics, logger *zap.Logger) *Service

New creates and initializes a new Service instance.

This function serves as a constructor for the Service struct, accepting all its dependencies as parameters. This approach, known as dependency injection, makes the code more testable and maintainable.

Parameters:

  • config: Configuration for the service
  • examples: Repository for data access
  • metrics: Metrics collector for monitoring
  • logger: Logger for structured logging

Returns:

  • *Service: A pointer to the newly created Service instance

Example:

config := example.Config{Example: "demo"}
repo := example.NewRepository()
metrics := example.NewMetrics()
logger, _ := zap.NewProduction()

service := example.New(config, repo, metrics, logger)

func (*Service) Example

func (s *Service) Example() string

Example returns the example value from the configuration.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL