Skip to content

Commit

Permalink
Condensed README
Browse files Browse the repository at this point in the history
  • Loading branch information
matzefriedrich committed Nov 28, 2024
1 parent ae943f0 commit b693978
Showing 1 changed file with 16 additions and 139 deletions.
155 changes: 16 additions & 139 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,162 +11,39 @@

## What is Parsley?

Parsley is a powerful, easy-to-use reflection-based dependency injection package that integrates seamlessly into any Go application.
Parsley is a reflection-based dependency injection (DI) package for Go that streamlines dependency management through automated lifetime management, type-safe registration, service resolution and activation, proxy generation, and method interception. It leverages reflection only at startup, ensuring runtime efficiency, and supports features like mocking and testing integration for better development workflows.

Just like the versatile green herb it's named after, Parsley enhances the flavor of your codebase by keeping your dependencies clean, organized, and easy to manage. Whether you're working on a small project or a complex system, Parsley brings the convenience of automated dependency injection to Go, inspired by the best practices from other languages. With features like automated lifetime management, proxy generation, and method interception, Parsley is the ingredient that makes your Go applications more maintainable and scalable.


### Why dependency injection for Golang?

While dependency injection (DI) is less common in Golang compared to other languages, the complexity it introduces can often be outweighed by the benefits it brings, especially in larger projects. As projects grow, the need for indirection and modularity becomes inevitable, and a DI framework like Parsley can seamlessly bridge the gap between dependency management and service activation. Parsley goes beyond resolving dependencies—it automates key aspects such as lifetime management, proxy generation, and interception, reducing boilerplate and enhancing maintainability. With these powerful features, why not let Parsley handle the heavy lifting for you?
### Why use dependency injection in Go?

Dependency injection in Go typically relies on constructor functions, which are idiomatic and foundational for creating and managing dependencies. While this approach is powerful, it can lead to boilerplate code as projects become more complex, requiring explicit instantiation and manual wiring. Addionally, more sophisticated ramp-up code is needed, if not all instances shall be created at application start. Parsley eliminates much of this repetitive code by automating the creation and wiring of dependencies, enabling developers to focus on application logic. It aims to enhance modularity and make managing dependencies easier.

## Key Features

### Type Registration

- **Constructor Functions:** Register types via constructor functions.
- **Resolve by Type:** Resolve objects by both interface and pointer types.
- **Constructor Injection:** Supported.
- **Field Injection:** ⏳ Will be supported via struct tags (in progress).
- **Setter Method Injection:** ❌ Not supported.
- **Safe Casts:** Convenience function `ResolveRequiredService[T]` to resolve and safely cast objects.

- **Lifetime Management:** Register types with different lifetimes.
- **Singleton:** Available.
- **Register Instances as Singletons:** Use `RegisterInstance[T]` (where `T` must be an interface type).
- **Scoped:** Requires a `NewScopedContext(context.Background)`. Use `RegisterScoped()`.
- **Transient:** Available for objects with a transient lifetime.

### Module & On-Demand Registrations

- **Modular Registrations:** Bundle type registrations as modules, register them via `RegisterModule` as a unit.

- **On-Demand Resolution:** Resolve objects only when needed.
- **Custom Factories:** Allow consumption of `Resolver` instead of custom factories.
- **Lazy Loading:** Inject dependencies lazily using `Lazy[T]`.
- **Factory Functions:** Register factories to create service instances dynamically at runtime.
- **Service Validation:** Validate services during startup and fail early if missing registrations or circular dependencies are found.
- **Non-Registered Types:** Resolve non-registered types using `ResolveWithOptions[T]`.
- **Override Type Registrations:** Provide custom service instances when resolving service instances.

### Multiple Registrations for the Same Interface

- **Named Services:** Register and resolve multiple services for the same interface, via `func(key string) T`.
- **Service Lists:** Resolve services as a list. Enable list dependencies via `RegisterList`.
- **Type Registration**: Supports constructor functions, lifetime management (singleton, scoped, transient), and safe casts.
- **Modular and Lazy Loading**: Register types as modules, resolve dependencies on-demand, and inject lazily with `Lazy[T]`.
- **Registration Validation**: Ensures early detection of missing registrations or circular dependencies.
- **Advanced Registrations**: Register multiple implementations for the same interface using named services or lists.
- **Proxy and Mock Support**: Generate extensible proxy types and configurable mocks to streamline testing workflows.

### Proxy Type Support

- **Proxies as Drop-in Replacements:** Generate proxy types that can be used in place of target services.
- **Extensible Proxies:** Proxies are extensible with `MethodInterceptor` services.

### Configurable Mocks

- **Generate Mocks:** Generate configurable mocks via `//go:parsley-cli generate mocks` to boost automated testing.
For a complete overview of features and capabilities, refer to the [Parsley documentation](https://matzefriedrich.github.io/parsley-docs/).


## Usage

Getting started with Parsley is as simple as adding it to your project and letting it take care of your dependencies. Here’s how you can use Parsley to wire up a small example application.

### Install Parsley

First, add Parsley to your project:
Add Parsley to your project:

````sh
```sh
go get github.com/matzefriedrich/parsley
````
```

For more advanced features, you can install the `parsley-cli` utility:
For advanced features like proxy generation or mock creation, install the `parsley-cli` utility:

````sh
```sh
go install github.com/matzefriedrich/parsley/cmd/parsley-cli
````

### Creating a Parsley-powered "Hello-World" application

Imagine you're building a service that greets users and logs those greetings. Instead of manually wiring everything together, Parsley can handle the setup. Start by defining the interfaces for your services:

````go
// Greeter defines a service that greets users.
type Greeter interface {
SayHello(name string) string
}

// Logger defines a service that logs messages.
type Logger interface {
Log(message string)
}
````

Now, create the implementations for these interfaces:

````go
type greeterServiceImpl struct {
logger LoggerService
}

func (g *greeterServiceImpl) SayHello(name string) string {
greeting := "Hello, " + name + "!"
g.logger.Log("Generated greeting: " + greeting)
return greeting
}

type loggerServiceImpl struct{}

func (l *loggerServiceImpl) Log(message string) {
fmt.Println("Log:", message)
}
````

To wire everything together, define constructor functions:

````go
func NewGreetService(logger LoggerService) GreetService {
return &greetServiceImpl{logger: logger}
}

func NewLoggerService() LoggerService {
return &loggerServiceImpl{}
}
````

With Parsley, registering these services and resolving them is straightforward:

````go
func main() {
registry := registration.NewServiceRegistry()

// Register services with their lifetimes
registration.RegisterSingleton(registry, NewLoggerService)
registration.RegisterScoped(registry, NewGreetService)

// Create a resolver
resolver := resolving.NewResolver(registry)

// Resolve and use the Greeter service instance
scope := resolving.NewScopedContext(context.Background())
greeter, _ := resolving.ResolveRequiredService[Greeter](resolver, scope)

// Use the service
fmt.Println(greeter.SayHello("World"))
}
````

When you run this application, you’ll see that Parsley automatically handles the dependencies for you:

````sh
Log: Generated greeting: Hello, World!
Hello, World!
````

### What Just Happened?

In this example, you defined two services, `Greeter` and `Logger`. You then registered these services with Parsley, specifying that `Logger` should have a singleton lifetime while `Greeter` should be scoped. Parsley injected a `Logger` instance into the `Greeter` instance during creation, ensuring everything was wired up correctly.

By using Parsley, you avoid the hassle of manual dependency wiring, keeping your code clean and focused on business logic. But that is not all - there are more features to explore: head over to the official docs at https://matzefriedrich.github.io/parsley-docs/ to find more usage examples.

```

---
---

Copyright 2024 - Matthias Friedrich

0 comments on commit b693978

Please sign in to comment.