Repository: beatlabs/patron
Pull request #581 (2022-10-17 16:51:24)

Imp/462 functional options pattern
<!--
Thanks for taking precious time for making a PR.

Before creating a pull request, please make sure:
- Your PR solves one problem for which an issue exist and a solution has been discussed
- You have read the guide for contributing
  - See https://github.com/beatlabs/patron/blob/master/README.md#how-to-contribute
- You signed all your commits (otherwise we won't be able to merge the PR)
  - See https://github.com/beatlabs/patron/blob/master/SIGNYOURWORK.md
- You added unit tests for the new functionality
- You mention in the PR description which issue it is addressing, e.g. "Resolves #123"
-->

## Which problem is this PR solving?

This PR addresses the issue https://github.com/beatlabs/patron/issues/462 .

<!-- REQUIRED -->

This PR changes the non deprecated builder/factory patterns in to `functional options` pattern. The following components have been altered to support the change.

-  Component: gRPC
-  Service, main

`NOTE` : This is a `breaking` change that affects the library consumers.

<!-- REQUIRED -->


mantzas: > If I understand correctly since we are introducing breaking changes in how components and Patron as a service are instantiated, I believe we should update the `BREAKING.md` file, mentioning the change and how one could migrate to the new states of instantiation.
> 
> @mantzas @pkritiotis WDYT?

Definitely, good catch!!!

Patch:
diff --git a/BREAKING.md b/BREAKING.md
index 3148b2e61..55cbb8d96 100644
--- a/BREAKING.md
+++ b/BREAKING.md
@@ -1,5 +1,174 @@
 # Breaking Changes Migration Guide
 
+## v.0.74.0
+
+### Instantiation of patron service
+
+The instantiation and initialisation of the patron main service has been moved from `builder pattern` to `functional options pattern`.
+The optional configuration parameters used for the builder in previous versions can now be passed as Options to the service constructor.
+Check the [examples directory](./examples) for complete examples of detailed usage.
+
+Types, github.com/beatlabs/patron.Builder and  github.com/beatlabs/patron.Option discontinued.
+
+#### Creating a patron instance with components
+
+##### v0.73.0 and before
+```go
+svc, err := patron.New(name, version)
+if err != nil {
+    log.Fatalf("failed to create patron service due to : %s", err)
+}
+
+ctx := context.Background()
+err = svc.WithComponents(ampq,grpc).Run(ctx)
+if err != nil {
+    log.Fatalf("failed to run service %s", err)
+}
+```
+
+##### v0.74.0
+```go
+svc, err := patron.New(name, version, patron.WithComponents(amqp,grpc))
+if err != nil {
+    log.Fatalf("failed to create patron service due to : %s", err)
+}
+
+ctx := context.Background()
+err = svc.Run(ctx)
+if err != nil {
+    log.Fatalf("failed to run service %s", err)
+}
+
+```
+#### Creating a patron instance with SIGHUP handler option
+
+##### v0.73.0 and before
+```go
+svc, err := patron.New(name, version)
+if err != nil {
+    log.Fatalf("failed to create patron service due to : %s", err)
+}
+
+ctx := context.Background()
+err = svc.WithSIGHUP(sighup).Run(ctx)
+if err != nil {
+    log.Fatalf("failed to run service %s", err)
+}
+```
+
+##### v0.74.0
+```go
+svc, err := patron.New(name, version, patron.WithSIGHUP(sighup))
+if err != nil {
+    log.Fatalf("failed to create patron service due to : %s", err)
+}
+
+ctx := context.Background()
+err = svc.Run(ctx)
+if err != nil {
+    log.Fatalf("failed to run service %s", err)
+}
+
+```
+
+#### Creating a patron instance with a custom HTTP Router
+
+##### v0.73.0 and before
+```go
+svc, err := patron.New(name, version)
+if err != nil {
+    log.Fatalf("failed to create patron service due to : %s", err)
+}
+
+ctx := context.Background()
+err = svc.WithRouter(router).Run(ctx)
+if err != nil {
+    log.Fatalf("failed to run service %s", err)
+}
+```
+
+##### v0.74.0
+```go
+svc, err := patron.New(name, version, patron.WithRouter(router))
+if err != nil {
+    log.Fatalf("failed to create patron service due to : %s", err)
+}
+
+ctx := context.Background()
+err = svc.Run(ctx)
+if err != nil {
+    log.Fatalf("failed to run service %s", err)
+}
+
+```
+
+### Instantiation of v2 GRPC Component
+
+The instantiation and initialisation of the GRPC component has been moved from `builder pattern` to `functional options pattern`.
+The configuration parameters used for the builder in previous versions can now be passed as Options to the component constructor.
+
+##### v0.73.0 and before
+```go
+package main
+
+import (
+	patrongrpc "github.com/beatlabs/patron/component/grpc"
+	"google.golang.org/grpc"
+	"log"
+	"time"
+)
+
+func main(){
+	port := 5000
+	builder,err := grpc.WithOptions(grpc.ConnectionTimeout(1*time.Second)).WithReflection().New(port)
+	if err != nil{
+		log.Fatalf("failed to create new grpc builder due: %s",err)
+	}
+
+	comp,err := builder.Create()
+	if err != nil{
+		log.Fatalf("failed to create grpc component due: %s",err)
+	}
+}
+```
+
+##### v0.74.0
+```go
+package main
+
+import (
+	patrongrpc "github.com/beatlabs/patron/component/grpc"
+	"log"
+	"google.golang.org/grpc"
+	"time"
+)
+
+func main(){
+	port := 5000
+	comp,err := patrongrpc.New(port, patrongrpc.WithServerOptions(grpc.ConnectionTimeout(1*time.Second)),patrongrpc.WithReflection())
+	if err != nil{
+		log.Fatalf("failed to create new grpc component due: %s",err)
+	}
+}
+```
+
+#### Changes to method Signatures
+
+In package `github.com/beatlabs/patron/component/http/v2/router/httprouter`,
+
+- `func EnableAppNameHeaders(name, version string) OptionFunc` renamed to `func WithAppNameHeaders(name, version string) OptionFunc`
+
+- `func EnableExpVarProfiling() OptionFunc` renamed to `func WithExpVarProfiling() OptionFunc`
+
+All names of other option functions for `components/clients` prefixed by `With`
+
+i.e.
+
+considering package `github.com/beatlabs/patron/client/ampq/v2`
+
+option function `func Config(cfg amqp.Config) OptionFunc` is renamed to `func Config(cfg amqp.Config) OptionFunc`
+
+
 ## v0.73.0
 
 ### Migrating from `aws-sdk-go` v1 to v2
@@ -72,4 +241,4 @@ func createSQSAPI(endpoint string) (*sqs.Client, error) {
 }
 ```
 
-> A more detailed documentation on migrating can be found [here](https://aws.github.io/aws-sdk-go-v2/docs/migrating).
+> A more detailed documentation on migrating can be found [here](https://aws.github.io/aws-sdk-go-v2/docs/migrating).
\ No newline at end of file
diff --git a/client/amqp/option.go b/client/amqp/option.go
index b74129cd8..5c29a92d2 100644
--- a/client/amqp/option.go
+++ b/client/amqp/option.go
@@ -11,8 +11,8 @@ import (
 // OptionFunc definition for configuring the publisher in a functional way.
 type OptionFunc func(*TracedPublisher) error
 
-// Timeout option for adjusting the timeout of the connection.
-func Timeout(timeout time.Duration) OptionFunc {
+// WithTimeout option for adjusting the timeout of the connection.
+func WithTimeout(timeout time.Duration) OptionFunc {
 	return func(tp *TracedPublisher) error {
 		if timeout <= 0 {
 			return errors.New("timeout must be positive")
diff --git a/client/amqp/v2/option.go b/client/amqp/v2/option.go
index ca9fe2bdd..a1e4a3f3f 100644
--- a/client/amqp/v2/option.go
+++ b/client/amqp/v2/option.go
@@ -7,8 +7,8 @@ import (
 // OptionFunc definition for configuring the publisher in a functional way.
 type OptionFunc func(*Publisher) error
 
-// Config option for providing dial configuration.
-func Config(cfg amqp.Config) OptionFunc {
+// WithConfig option for providing dial configuration.
+func WithConfig(cfg amqp.Config) OptionFunc {
 	return func(p *Publisher) error {
 		p.cfg = &cfg
 		return nil
diff --git a/client/http/option.go b/client/http/option.go
index 7f74c9a33..3a50afbc7 100644
--- a/client/http/option.go
+++ b/client/http/option.go
@@ -13,8 +13,8 @@ import (
 // OptionFunc definition for configuring the client in a functional way.
 type OptionFunc func(*TracedClient) error
 
-// Timeout option for adjusting the timeout of the connection.
-func Timeout(timeout time.Duration) OptionFunc {
+// WithTimeout option for adjusting the timeout of the connection.
+func WithTimeout(timeout time.Duration) OptionFunc {
 	return func(tc *TracedClient) error {
 		if timeout <= 0 {
 			return errors.New("timeout must be positive")
@@ -24,8 +24,8 @@ func Timeout(timeout time.Duration) OptionFunc {
 	}
 }
 
-// CircuitBreaker option for setting up a circuit breaker.
-func CircuitBreaker(name string, set circuitbreaker.Setting) OptionFunc {
+// WithCircuitBreaker option for setting up a circuit breaker.
+func WithCircuitBreaker(name string, set circuitbreaker.Setting) OptionFunc {
 	return func(tc *TracedClient) error {
 		cb, err := circuitbreaker.New(name, set)
 		if err != nil {
@@ -36,8 +36,8 @@ func CircuitBreaker(name string, set circuitbreaker.Setting) OptionFunc {
 	}
 }
 
-// Transport option for setting the Transport for the client.
-func Transport(rt http.RoundTripper) OptionFunc {
+// WithTransport option for setting the WithTransport for the client.
+func WithTransport(rt http.RoundTripper) OptionFunc {
 	return func(tc *TracedClient) error {
 		if rt == nil {
 			return errors.New("transport must be supplied")
@@ -47,8 +47,8 @@ func Transport(rt http.RoundTripper) OptionFunc {
 	}
 }
 
-// CheckRedirect option for setting the CheckRedirect for the client.
-func CheckRedirect(cr func(req *http.Request, via []*http.Request) error) OptionFunc {
+// WithCheckRedirect option for setting the WithCheckRedirect for the client.
+func WithCheckRedirect(cr func(req *http.Request, via []*http.Request) error) OptionFunc {
 	return func(tc *TracedClient) error {
 		if cr == nil {
 			return errors.New("check redirect must be supplied")
diff --git a/component/amqp/option.go b/component/amqp/option.go
index f7d7bf5aa..2231b6432 100644
--- a/component/amqp/option.go
+++ b/component/amqp/option.go
@@ -10,9 +10,9 @@ import (
 // OptionFunc definition for configuring the component in a functional way.
 type OptionFunc func(*Component) error
 
-// Batching option for setting up batching.
+// WithBatching option for setting up batching.
 // Allowed values for count is > 1 and timeout > 0.
-func Batching(count uint, timeout time.Duration) OptionFunc {
+func WithBatching(count uint, timeout time.Duration) OptionFunc {
 	return func(c *Component) error {
 		if count == 0 || count == 1 {
 			return errors.New("count should be larger than 1 message")
@@ -27,8 +27,8 @@ func Batching(count uint, timeout time.Duration) OptionFunc {
 	}
 }
 
-// Retry option for setting up retries.
-func Retry(count uint, delay time.Duration) OptionFunc {
+// WithRetry option for setting up retries.
+func WithRetry(count uint, delay time.Duration) OptionFunc {
 	return func(c *Component) error {
 		c.retryCfg.count = count
 		c.retryCfg.delay = delay
@@ -36,16 +36,16 @@ func Retry(count uint, delay time.Duration) OptionFunc {
 	}
 }
 
-// Config option for setting AMQP configuration.
-func Config(cfg amqp.Config) OptionFunc {
+// WithConfig option for setting AMQP configuration.
+func WithConfig(cfg amqp.Config) OptionFunc {
 	return func(c *Component) error {
 		c.cfg = cfg
 		return nil
 	}
 }
 
-// StatsInterval option for setting the interval to retrieve statistics.
-func StatsInterval(interval time.Duration) OptionFunc {
+// WithStatsInterval option for setting the interval to retrieve statistics.
+func WithStatsInterval(interval time.Duration) OptionFunc {
 	return func(c *Component) error {
 		if interval <= 0 {
 			return errors.New("stats interval should be a positive number")
@@ -55,8 +55,8 @@ func StatsInterval(interval time.Duration) OptionFunc {
 	}
 }
 
-// Requeue option for adjusting the requeue policy of a message.
-func Requeue(requeue bool) OptionFunc {
+// WithRequeue option for adjusting the requeue policy of a message.
+func WithRequeue(requeue bool) OptionFunc {
 	return func(c *Component) error {
 		c.queueCfg.requeue = requeue
 		return nil
diff --git a/component/async/amqp/option.go b/component/async/amqp/option.go
index ca5c1e875..ac03a1531 100644
--- a/component/async/amqp/option.go
+++ b/component/async/amqp/option.go
@@ -11,8 +11,8 @@ import (
 // OptionFunc definition for configuring the consumer in a functional way.
 type OptionFunc func(*consumer) error
 
-// Buffer option for adjusting the incoming messages buffer.
-func Buffer(buf int) OptionFunc {
+// WithBuffer option for adjusting the incoming messages buffer.
+func WithBuffer(buf int) OptionFunc {
 	return func(c *consumer) error {
 		if buf < 0 {
 			return errors.New("buffer must greater or equal than 0")
@@ -22,8 +22,8 @@ func Buffer(buf int) OptionFunc {
 	}
 }
 
-// Timeout option for adjusting the timeout of the connection.
-func Timeout(timeout time.Duration) OptionFunc {
+// WithTimeout option for adjusting the timeout of the connection.
+func WithTimeout(timeout time.Duration) OptionFunc {
 	return func(c *consumer) error {
 		c.cfg = amqp.Config{
 			Dial: func(network, addr string) (net.Conn, error) {
@@ -34,16 +34,16 @@ func Timeout(timeout time.Duration) OptionFunc {
 	}
 }
 
-// Requeue option for adjusting the requeue policy of a message.
-func Requeue(requeue bool) OptionFunc {
+// WithRequeue option for adjusting the requeue policy of a message.
+func WithRequeue(requeue bool) OptionFunc {
 	return func(c *consumer) error {
 		c.requeue = requeue
 		return nil
 	}
 }
 
-// Bindings option for providing custom exchange-queue bindings.
-func Bindings(bindings ...string) OptionFunc {
+// WithBindings option for providing custom exchange-queue bindings.
+func WithBindings(bindings ...string) OptionFunc {
 	return func(c *consumer) error {
 		if len(bindings) == 0 {
 			return errors.New("provided bindings cannot be empty")
diff --git a/component/async/kafka/option.go b/component/async/kafka/option.go
index 59f48e8b3..cd6af5a07 100644
--- a/component/async/kafka/option.go
+++ b/component/async/kafka/option.go
@@ -13,8 +13,8 @@ import (
 // OptionFunc definition for configuring the consumer in a functional way.
 type OptionFunc func(*ConsumerConfig) error
 
-// Version for setting the Kafka version.
-func Version(version string) OptionFunc {
+// WithVersion for setting the Kafka version.
+func WithVersion(version string) OptionFunc {
 	return func(c *ConsumerConfig) error {
 		if version == "" {
 			return errors.New("versions has to be provided")
@@ -29,8 +29,8 @@ func Version(version string) OptionFunc {
 	}
 }
 
-// Buffer for adjusting the incoming messages buffer.
-func Buffer(buf int) OptionFunc {
+// WithBuffer for adjusting the incoming messages buffer.
+func WithBuffer(buf int) OptionFunc {
 	return func(c *ConsumerConfig) error {
 		if buf < 0 {
 			return errors.New("buffer must greater or equal than 0")
@@ -40,40 +40,40 @@ func Buffer(buf int) OptionFunc {
 	}
 }
 
-// Timeout for adjusting the timeout of the connection.
-func Timeout(timeout time.Duration) OptionFunc {
+// WithTimeout for adjusting the timeout of the connection.
+func WithTimeout(timeout time.Duration) OptionFunc {
 	return func(c *ConsumerConfig) error {
 		c.SaramaConfig.Net.DialTimeout = timeout
 		return nil
 	}
 }
 
-// Start for adjusting the starting offset.
-func Start(offset int64) OptionFunc {
+// WithStart for adjusting the starting offset.
+func WithStart(offset int64) OptionFunc {
 	return func(c *ConsumerConfig) error {
 		c.SaramaConfig.Consumer.Offsets.Initial = offset
 		return nil
 	}
 }
 
-// StartFromOldest for adjusting the starting offset to oldest.
-func StartFromOldest() OptionFunc {
+// WithStartFromOldest for adjusting the starting offset to oldest.
+func WithStartFromOldest() OptionFunc {
 	return func(c *ConsumerConfig) error {
 		c.SaramaConfig.Consumer.Offsets.Initial = sarama.OffsetOldest
 		return nil
 	}
 }
 
-// StartFromNewest for adjusting the starting offset to newest.
-func StartFromNewest() OptionFunc {
+// WithStartFromNewest for adjusting the starting offset to newest.
+func WithStartFromNewest() OptionFunc {
 	return func(c *ConsumerConfig) error {
 		c.SaramaConfig.Consumer.Offsets.Initial = sarama.OffsetNewest
 		return nil
 	}
 }
 
-// Decoder for injecting a specific decoder implementation.
-func Decoder(dec encoding.DecodeRawFunc) OptionFunc {
+// WithDecoder for injecting a specific decoder implementation.
+func WithDecoder(dec encoding.DecodeRawFunc) OptionFunc {
 	return func(c *ConsumerConfig) error {
 		if dec == nil {
 			return errors.New("decoder is nil")
@@ -83,8 +83,8 @@ func Decoder(dec encoding.DecodeRawFunc) OptionFunc {
 	}
 }
 
-// DecoderJSON for injecting json decoder.
-func DecoderJSON() OptionFunc {
+// WithDecoderJSON for injecting json decoder.
+func WithDecoderJSON() OptionFunc {
 	return func(c *ConsumerConfig) error {
 		c.DecoderFunc = json.DecodeRaw
 		return nil
diff --git a/component/grpc/component.go b/component/grpc/component.go
index 92cccbd6b..b194d1757 100644
--- a/component/grpc/component.go
+++ b/component/grpc/component.go
@@ -6,7 +6,6 @@ import (
 	"fmt"
 	"net"
 
-	"github.com/beatlabs/patron/errors"
 	"github.com/beatlabs/patron/log"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/reflection"
@@ -14,8 +13,38 @@ import (
 
 // Component of a gRPC service.
 type Component struct {
-	port int
-	srv  *grpc.Server
+	port             int
+	serverOptions    []grpc.ServerOption
+	enableReflection bool
+	srv              *grpc.Server
+}
+
+func New(port int, options ...OptionFunction) (*Component, error) {
+	c := new(Component)
+	if port <= 0 || port > 65535 {
+		return nil, fmt.Errorf("port is invalid: %d", port)
+	}
+	c.port = port
+
+	var err error
+
+	for _, optionFunc := range options {
+		err = optionFunc(c)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	c.serverOptions = append(c.serverOptions, grpc.UnaryInterceptor(observableUnaryInterceptor),
+		grpc.StreamInterceptor(observableStreamInterceptor))
+	srv := grpc.NewServer(c.serverOptions...)
+
+	if c.enableReflection {
+		reflection.Register(srv)
+	}
+	c.srv = srv
+
+	return c, nil
 }
 
 // Server returns the gRPC sever.
@@ -38,62 +67,3 @@ func (c *Component) Run(ctx context.Context) error {
 	log.Debugf("gRPC component listening on port %d", c.port)
 	return c.srv.Serve(lis)
 }
-
-// Builder pattern for our gRPC service.
-type Builder struct {
-	port             int
-	serverOptions    []grpc.ServerOption
-	enableReflection bool
-	errors           []error
-}
-
-// New builder.
-func New(port int) *Builder {
-	b := &Builder{}
-	if port <= 0 || port > 65535 {
-		b.errors = append(b.errors, fmt.Errorf("port is invalid: %d", port))
-		return b
-	}
-	b.port = port
-	return b
-}
-
-// WithOptions allows gRPC server options to be set.
-func (b *Builder) WithOptions(oo ...grpc.ServerOption) *Builder {
-	if len(b.errors) != 0 {
-		return b
-	}
-	b.serverOptions = append(b.serverOptions, oo...)
-	return b
-}
-
-// WithReflection opt-in for gRPC reflection.
-// Reflection could be considered a security risk if services are exposed to public internet.
-func (b *Builder) WithReflection() *Builder {
-	if len(b.errors) != 0 {
-		return b
-	}
-	b.enableReflection = true
-	return b
-}
-
-// Create the gRPC component.
-func (b *Builder) Create() (*Component, error) {
-	if len(b.errors) != 0 {
-		return nil, errors.Aggregate(b.errors...)
-	}
-
-	b.serverOptions = append(b.serverOptions, grpc.UnaryInterceptor(observableUnaryInterceptor),
-		grpc.StreamInterceptor(observableStreamInterceptor))
-
-	srv := grpc.NewServer(b.serverOptions...)
-
-	if b.enableReflection {
-		reflection.Register(srv)
-	}
-
-	return &Component{
-		port: b.port,
-		srv:  srv,
-	}, nil
-}
diff --git a/component/grpc/options.go b/component/grpc/options.go
new file mode 100644
index 000000000..97230d044
--- /dev/null
+++ b/component/grpc/options.go
@@ -0,0 +1,30 @@
+package grpc
+
+import (
+	"errors"
+
+	"google.golang.org/grpc"
+)
+
+type OptionFunction func(*Component) error
+
+// WithServerOptions allows gRPC server options to be set.
+func WithServerOptions(options ...grpc.ServerOption) OptionFunction {
+	return func(component *Component) error {
+		if len(options) == 0 {
+			return errors.New("no grpc options provided")
+		}
+
+		component.serverOptions = options
+		return nil
+	}
+}
+
+// WithReflection opt-in for gRPC reflection.
+// WithReflection could be considered a security risk if services are exposed to public internet.
+func WithReflection() OptionFunction {
+	return func(component *Component) error {
+		component.enableReflection = true
+		return nil
+	}
+}
diff --git a/component/http/component.go b/component/http/component.go
index a3a42e5ab..a9b6479e3 100644
--- a/component/http/component.go
+++ b/component/http/component.go
@@ -192,7 +192,7 @@ func (cb *Builder) WithMiddlewares(mm ...middleware.Func) *Builder {
 	return cb
 }
 
-// WithReadTimeout sets the Read Timeout for the HTTP component.
+// WithReadTimeout sets the Read WithTimeout for the HTTP component.
 func (cb *Builder) WithReadTimeout(rt time.Duration) *Builder {
 	if rt <= 0*time.Second {
 		cb.errors = append(cb.errors, errors.New("negative or zero read timeout provided"))
diff --git a/component/http/v2/component_option.go b/component/http/v2/component_option.go
index 5f58529cd..07f7d9d5f 100644
--- a/component/http/v2/component_option.go
+++ b/component/http/v2/component_option.go
@@ -8,8 +8,8 @@ import (
 // OptionFunc definition for configuring the component in a functional way.
 type OptionFunc func(*Component) error
 
-// TLS functional option.
-func TLS(cert, key string) OptionFunc {
+// WithTLS functional option.
+func WithTLS(cert, key string) OptionFunc {
 	return func(cmp *Component) error {
 		if cert == "" || key == "" {
 			return errors.New("cert file or key file was empty")
@@ -21,8 +21,8 @@ func TLS(cert, key string) OptionFunc {
 	}
 }
 
-// ReadTimeout functional option.
-func ReadTimeout(rt time.Duration) OptionFunc {
+// WithReadTimeout functional option.
+func WithReadTimeout(rt time.Duration) OptionFunc {
 	return func(cmp *Component) error {
 		if rt <= 0*time.Second {
 			return errors.New("negative or zero read timeout provided")
@@ -32,8 +32,8 @@ func ReadTimeout(rt time.Duration) OptionFunc {
 	}
 }
 
-// WriteTimeout functional option.
-func WriteTimeout(wt time.Duration) OptionFunc {
+// WithWriteTimeout functional option.
+func WithWriteTimeout(wt time.Duration) OptionFunc {
 	return func(cmp *Component) error {
 		if wt <= 0*time.Second {
 			return errors.New("negative or zero write timeout provided")
@@ -43,8 +43,8 @@ func WriteTimeout(wt time.Duration) OptionFunc {
 	}
 }
 
-// HandlerTimeout functional option.
-func HandlerTimeout(wt time.Duration) OptionFunc {
+// WithHandlerTimeout functional option.
+func WithHandlerTimeout(wt time.Duration) OptionFunc {
 	return func(cmp *Component) error {
 		if wt <= 0*time.Second {
 			return errors.New("negative or zero handler timeout provided")
@@ -54,8 +54,8 @@ func HandlerTimeout(wt time.Duration) OptionFunc {
 	}
 }
 
-// ShutdownGracePeriod functional option.
-func ShutdownGracePeriod(gp time.Duration) OptionFunc {
+// WithShutdownGracePeriod functional option.
+func WithShutdownGracePeriod(gp time.Duration) OptionFunc {
 	return func(cmp *Component) error {
 		if gp <= 0*time.Second {
 			return errors.New("negative or zero shutdown grace period timeout provided")
@@ -65,8 +65,8 @@ func ShutdownGracePeriod(gp time.Duration) OptionFunc {
 	}
 }
 
-// Port functional option.
-func Port(port int) OptionFunc {
+// WithPort functional option.
+func WithPort(port int) OptionFunc {
 	return func(cmp *Component) error {
 		if port <= 0 || port > 65535 {
 			return errors.New("invalid HTTP Port provided")
diff --git a/component/http/v2/route_option.go b/component/http/v2/route_option.go
index c803b6f49..0733dd29a 100644
--- a/component/http/v2/route_option.go
+++ b/component/http/v2/route_option.go
@@ -12,16 +12,16 @@ import (
 	"golang.org/x/time/rate"
 )
 
-// RateLimiting option for setting a route rate limiter.
-func RateLimiting(limit float64, burst int) RouteOptionFunc {
+// WithRateLimiting option for setting a route rate limiter.
+func WithRateLimiting(limit float64, burst int) RouteOptionFunc {
 	return func(r *Route) error {
 		r.middlewares = append(r.middlewares, patronhttp.NewRateLimiting(rate.NewLimiter(rate.Limit(limit), burst)))
 		return nil
 	}
 }
 
-// Middlewares option for setting the route optionFuncs.
-func Middlewares(mm ...patronhttp.Func) RouteOptionFunc {
+// WithMiddlewares option for setting the route optionFuncs.
+func WithMiddlewares(mm ...patronhttp.Func) RouteOptionFunc {
 	return func(r *Route) error {
 		if len(mm) == 0 {
 			return errors.New("middlewares are empty")
@@ -31,8 +31,8 @@ func Middlewares(mm ...patronhttp.Func) RouteOptionFunc {
 	}
 }
 
-// Auth option for setting the route auth.
-func Auth(auth auth.Authenticator) RouteOptionFunc {
+// WithAuth option for setting the route auth.
+func WithAuth(auth auth.Authenticator) RouteOptionFunc {
 	return func(r *Route) error {
 		if auth == nil {
 			return errors.New("authenticator is nil")
@@ -42,8 +42,8 @@ func Auth(auth auth.Authenticator) RouteOptionFunc {
 	}
 }
 
-// Cache option for setting the route cache.
-func Cache(cache cache.TTLCache, ageBounds httpcache.Age) RouteOptionFunc {
+// WithCache option for setting the route cache.
+func WithCache(cache cache.TTLCache, ageBounds httpcache.Age) RouteOptionFunc {
 	return func(r *Route) error {
 		if r.method != http.MethodGet {
 			return errors.New("cannot apply cache to a route with any method other than GET")
diff --git a/component/http/v2/router/httprouter/router_option.go b/component/http/v2/router/httprouter/router_option.go
index 08c580e8a..b5af81671 100644
--- a/component/http/v2/router/httprouter/router_option.go
+++ b/component/http/v2/router/httprouter/router_option.go
@@ -7,8 +7,8 @@ import (
 	v2 "github.com/beatlabs/patron/component/http/v2"
 )
 
-// Routes option for providing routes to the router.
-func Routes(routes ...*v2.Route) OptionFunc {
+// WithRoutes option for providing routes to the router.
+func WithRoutes(routes ...*v2.Route) OptionFunc {
 	return func(cfg *Config) error {
 		if len(routes) == 0 {
 			return errors.New("routes are empty")
@@ -18,8 +18,8 @@ func Routes(routes ...*v2.Route) OptionFunc {
 	}
 }
 
-// AliveCheck option for the router.
-func AliveCheck(acf v2.LivenessCheckFunc) OptionFunc {
+// WithAliveCheck option for the router.
+func WithAliveCheck(acf v2.LivenessCheckFunc) OptionFunc {
 	return func(cfg *Config) error {
 		if acf == nil {
 			return errors.New("alive check function is nil")
@@ -29,8 +29,8 @@ func AliveCheck(acf v2.LivenessCheckFunc) OptionFunc {
 	}
 }
 
-// ReadyCheck option for the router.
-func ReadyCheck(rcf v2.ReadyCheckFunc) OptionFunc {
+// WithReadyCheck option for the router.
+func WithReadyCheck(rcf v2.ReadyCheckFunc) OptionFunc {
 	return func(cfg *Config) error {
 		if rcf == nil {
 			return errors.New("ready check function is nil")
@@ -40,16 +40,20 @@ func ReadyCheck(rcf v2.ReadyCheckFunc) OptionFunc {
 	}
 }
 
-// DeflateLevel option for the compression middleware.
-func DeflateLevel(level int) OptionFunc {
+// WithDeflateLevel option for the compression middleware.
+func WithDeflateLevel(level int) OptionFunc {
 	return func(cfg *Config) error {
+		if level < -2 || level > 9 {
+			return errors.New("provided deflate level value not in the [-2, 9] range")
+		}
+
 		cfg.deflateLevel = level
 		return nil
 	}
 }
 
-// Middlewares option for middlewares.
-func Middlewares(mm ...middleware.Func) OptionFunc {
+// WithMiddlewares option for middlewares.
+func WithMiddlewares(mm ...middleware.Func) OptionFunc {
 	return func(cfg *Config) error {
 		if len(mm) == 0 {
 			return errors.New("middlewares are empty")
@@ -59,16 +63,16 @@ func Middlewares(mm ...middleware.Func) OptionFunc {
 	}
 }
 
-// EnableExpVarProfiling option for enabling expVar in profiling endpoints.
-func EnableExpVarProfiling() OptionFunc {
+// WithExpVarProfiling option for enabling expVar in profiling endpoints.
+func WithExpVarProfiling() OptionFunc {
 	return func(cfg *Config) error {
 		cfg.enableProfilingExpVar = true
 		return nil
 	}
 }
 
-// EnableAppNameHeaders option for adding name and version header to the response.
-func EnableAppNameHeaders(name, version string) OptionFunc {
+// WithAppNameHeaders option for adding name and version header to the response.
+func WithAppNameHeaders(name, version string) OptionFunc {
 	return func(cfg *Config) error {
 		if name == "" {
 			return errors.New("app name was not provided")
diff --git a/component/kafka/group/option.go b/component/kafka/group/option.go
index addbd7608..37f1f3406 100644
--- a/component/kafka/group/option.go
+++ b/component/kafka/group/option.go
@@ -13,12 +13,12 @@ import (
 // OptionFunc definition for configuring the component in a functional way.
 type OptionFunc func(*Component) error
 
-// FailureStrategy sets the strategy to follow for the component when it encounters an error.
-// The kafka.ExitStrategy will fail the component, if there are Retries > 0 then the component will reconnect and retry
+// WithFailureStrategy sets the strategy to follow for the component when it encounters an error.
+// The kafka.ExitStrategy will fail the component, if there are retries > 0 then the component will reconnect and retry
 // the failed message.
 // The kafka.SkipStrategy will skip the message on failure. If a client wants to retry a message before failing then
 // this needs to be handled in the kafka.BatchProcessorFunc.
-func FailureStrategy(fs kafka.FailStrategy) OptionFunc {
+func WithFailureStrategy(fs kafka.FailStrategy) OptionFunc {
 	return func(c *Component) error {
 		if fs > kafka.SkipStrategy || fs < kafka.ExitStrategy {
 			return errors.New("invalid failure strategy provided")
@@ -28,8 +28,8 @@ func FailureStrategy(fs kafka.FailStrategy) OptionFunc {
 	}
 }
 
-// CheckTopic checks whether the component-configured topics exist in the broker.
-func CheckTopic() OptionFunc {
+// WithCheckTopic checks whether the component-configured topics exist in the broker.
+func WithCheckTopic() OptionFunc {
 	return func(c *Component) error {
 		saramaConf := sarama.NewConfig()
 		client, err := sarama.NewClient(c.brokers, saramaConf)
@@ -56,20 +56,20 @@ func CheckTopic() OptionFunc {
 	}
 }
 
-// Retries sets the number of time a component should retry in case of an error.
+// WithRetries sets the number of time a component should retry in case of an error.
 // These retries are depleted in these cases:
 // * when there are temporary connection issues
 // * a message batch fails to be processed through the user-defined processing function and the failure strategy is set to kafka.ExitStrategy
 // * any other reason for which the component needs to reconnect.
-func Retries(count uint) OptionFunc {
+func WithRetries(count uint) OptionFunc {
 	return func(c *Component) error {
 		c.retries = count
 		return nil
 	}
 }
 
-// RetryWait sets the wait period for the component retry.
-func RetryWait(interval time.Duration) OptionFunc {
+// WithRetryWait sets the wait period for the component retry.
+func WithRetryWait(interval time.Duration) OptionFunc {
 	return func(c *Component) error {
 		if interval <= 0 {
 			return errors.New("retry wait time should be a positive number")
@@ -79,8 +79,8 @@ func RetryWait(interval time.Duration) OptionFunc {
 	}
 }
 
-// BatchSize sets the message batch size the component should process at once.
-func BatchSize(size uint) OptionFunc {
+// WithBatchSize sets the message batch size the component should process at once.
+func WithBatchSize(size uint) OptionFunc {
 	return func(c *Component) error {
 		if size == 0 {
 			return errors.New("zero batch size provided")
@@ -90,9 +90,9 @@ func BatchSize(size uint) OptionFunc {
 	}
 }
 
-// BatchTimeout sets the message batch timeout. If the desired batch size is not reached and if the timeout elapses
+// WithBatchTimeout sets the message batch timeout. If the desired batch size is not reached and if the timeout elapses
 // without new messages coming in, the messages in the buffer would get processed as a batch.
-func BatchTimeout(timeout time.Duration) OptionFunc {
+func WithBatchTimeout(timeout time.Duration) OptionFunc {
 	return func(c *Component) error {
 		if timeout < 0 {
 			return errors.New("batch timeout should greater than or equal to zero")
@@ -102,19 +102,19 @@ func BatchTimeout(timeout time.Duration) OptionFunc {
 	}
 }
 
-// BatchMessageDeduplication enables the deduplication of messages based on the message's key.
+// WithBatchMessageDeduplication enables the deduplication of messages based on the message's key.
 // This implementation does not do additional sorting, but instead relies on the ordering guarantees that Kafka gives
 // within partitions of a topic. Don't use this functionality if you've changed your producer's partition hashing
 // behaviour to a nondeterministic way.
-func BatchMessageDeduplication() OptionFunc {
+func WithBatchMessageDeduplication() OptionFunc {
 	return func(c *Component) error {
 		c.batchMessageDeduplication = true
 		return nil
 	}
 }
 
-// CommitSync instructs the consumer to commit offsets in a blocking operation after processing every batch of messages.
-func CommitSync() OptionFunc {
+// WithCommitSync instructs the consumer to commit offsets in a blocking operation after processing every batch of messages.
+func WithCommitSync() OptionFunc {
 	return func(c *Component) error {
 		if c.saramaConfig != nil && c.saramaConfig.Consumer.Offsets.AutoCommit.Enable {
 			// redundant commits warning
@@ -125,8 +125,8 @@ func CommitSync() OptionFunc {
 	}
 }
 
-// NewSessionCallback adds a callback when a new consumer group session is created (e.g., rebalancing).
-func NewSessionCallback(sessionCallback func(sarama.ConsumerGroupSession) error) OptionFunc {
+// WithNewSessionCallback adds a callback when a new consumer group session is created (e.g., rebalancing).
+func WithNewSessionCallback(sessionCallback func(sarama.ConsumerGroupSession) error) OptionFunc {
 	return func(c *Component) error {
 		if sessionCallback == nil {
 			return errors.New("nil session callback")
diff --git a/component/sqs/option.go b/component/sqs/option.go
index 0941740e2..a488d7e96 100644
--- a/component/sqs/option.go
+++ b/component/sqs/option.go
@@ -11,11 +11,11 @@ const twelveHoursInSeconds = 43200
 // OptionFunc definition for configuring the component in a functional way.
 type OptionFunc func(*Component) error
 
-// MaxMessages option for setting the max number of messages fetched.
+// WithMaxMessages option for setting the max number of messages fetched.
 // Allowed values are between 1 and 10.
 // If messages can be processed very quickly, maxing out this value is fine, otherwise having a high value is risky as it might trigger the visibility timeout.
 // Having a value too small isn't recommended either, as it increases the number of SQS API requests, thus AWS costs.
-func MaxMessages(maxMessages int32) OptionFunc {
+func WithMaxMessages(maxMessages int32) OptionFunc {
 	return func(c *Component) error {
 		if maxMessages <= 0 || maxMessages > 10 {
 			return errors.New("max messages should be between 1 and 10")
@@ -25,9 +25,9 @@ func MaxMessages(maxMessages int32) OptionFunc {
 	}
 }
 
-// PollWaitSeconds sets the wait time for the long polling mechanism in seconds.
+// WithPollWaitSeconds sets the wait time for the long polling mechanism in seconds.
 // Allowed values are between 0 and 20. 0 enables short polling.
-func PollWaitSeconds(pollWaitSeconds int32) OptionFunc {
+func WithPollWaitSeconds(pollWaitSeconds int32) OptionFunc {
 	return func(c *Component) error {
 		if pollWaitSeconds < 0 || pollWaitSeconds > 20 {
 			return errors.New("poll wait seconds should be between 0 and 20")
@@ -37,11 +37,11 @@ func PollWaitSeconds(pollWaitSeconds int32) OptionFunc {
 	}
 }
 
-// VisibilityTimeout sets the time a message is invisible after it has been requested.
+// WithVisibilityTimeout sets the time a message is invisible after it has been requested.
 // This is a built-in resiliency mechanism so that, should the consumer fail to acknowledge the message within such timeout,
 // it will become visible again and thus available for retries.
 // Allowed values are between 0 and 12 hours in seconds.
-func VisibilityTimeout(visibilityTimeout int32) OptionFunc {
+func WithVisibilityTimeout(visibilityTimeout int32) OptionFunc {
 	return func(c *Component) error {
 		if visibilityTimeout < 0 || visibilityTimeout > twelveHoursInSeconds {
 			return fmt.Errorf("visibility timeout should be between 0 and %d seconds", twelveHoursInSeconds)
@@ -51,8 +51,8 @@ func VisibilityTimeout(visibilityTimeout int32) OptionFunc {
 	}
 }
 
-// QueueStatsInterval sets the interval at which we retrieve AWS SQS stats.
-func QueueStatsInterval(interval time.Duration) OptionFunc {
+// WithQueueStatsInterval sets the interval at which we retrieve AWS SQS stats.
+func WithQueueStatsInterval(interval time.Duration) OptionFunc {
 	return func(c *Component) error {
 		if interval == 0 {
 			return errors.New("sqsAPI stats interval should be a positive value")
@@ -62,16 +62,16 @@ func QueueStatsInterval(interval time.Duration) OptionFunc {
 	}
 }
 
-// Retries sets the error retries of the component.
-func Retries(count uint) OptionFunc {
+// WithRetries sets the error retries of the component.
+func WithRetries(count uint) OptionFunc {
 	return func(c *Component) error {
 		c.retry.count = count
 		return nil
 	}
 }
 
-// RetryWait sets the wait period for the component retry.
-func RetryWait(interval time.Duration) OptionFunc {
+// WithRetryWait sets the wait period for the component retry.
+func WithRetryWait(interval time.Duration) OptionFunc {
 	return func(c *Component) error {
 		if interval <= 0 {
 			return errors.New("retry wait time should be a positive number")
@@ -81,8 +81,8 @@ func RetryWait(interval time.Duration) OptionFunc {
 	}
 }
 
-// QueueOwner sets the AWS queue owner ID for an SQS queue.
-func QueueOwner(queueOwner string) OptionFunc {
+// WithQueueOwner sets the AWS queue owner ID for an SQS queue.
+func WithQueueOwner(queueOwner string) OptionFunc {
 	return func(c *Component) error {
 		if queueOwner == "" {
 			return errors.New("queue owner should not be empty")
diff --git a/doc.go b/doc.go
index b8764f8e3..9fb070c35 100644
--- a/doc.go
+++ b/doc.go
@@ -6,16 +6,16 @@ Patron is a framework for creating microservices.
 Patron is french for template or pattern, but it means also boss which we found out later (no pun intended).
 
 The entry point of the framework is the Service.
-The Service uses Components to handle the processing of sync and async requests.
-The Service can set up as many Components it wants, even multiple HTTP components provided the port does not collide.
+The Service uses WithComponents to handle the processing of sync and async requests.
+The Service can set up as many components as it wants, even multiple HTTP components provided the port does not collide.
 The Service starts by default an HTTP component which hosts the debug, alive, ready and metric endpoints.
 Any other endpoints will be added to the default HTTP Component as Routes.
-The service set's up by default logging with zerolog, tracing and metrics with jaeger and prometheus.
+The Service set's up by default logging with zerolog, tracing and metrics with jaeger and prometheus.
 
 Patron provides abstractions for the following functionality of the framework:
 
-  - service, which orchestrates everything
-  - components and processors, which provide an abstraction of adding processing functionality to the service
+  - Service, which orchestrates everything
+  - components and processors, which provide an abstraction of adding processing functionality to the Service
   - asynchronous message processing (RabbitMQ, Kafka)
   - synchronous processing (HTTP)
   - metrics and tracing
diff --git a/examples/amqp/main.go b/examples/amqp/main.go
index 5d48661e9..543072bd0 100644
--- a/examples/amqp/main.go
+++ b/examples/amqp/main.go
@@ -95,11 +95,6 @@ func main() {
 	name := "amqp"
 	version := "1.0.0"
 
-	service, err := patron.New(name, version, patron.TextLogger())
-	if err != nil {
-		log.Fatalf("failed to set up service: %v", err)
-	}
-
 	// Programmatically create an empty SQS queue for the sake of the example
 	sqsAPI, err := createSQSAPI(awsSQSEndpoint)
 	if err != nil {
@@ -145,8 +140,13 @@ func main() {
 		log.Fatalf("failed to create processor %v", err)
 	}
 
+	service, err := patron.New(name, version, patron.WithTextLogger(), patron.WithComponents(amqpCmp.cmp))
+	if err != nil {
+		log.Fatalf("failed to set up service: %v", err)
+	}
+
 	ctx := context.Background()
-	err = service.WithComponents(amqpCmp.cmp).Run(ctx)
+	err = service.Run(ctx)
 	if err != nil {
 		log.Fatalf("failed to create and run service %v", err)
 	}
@@ -252,7 +252,8 @@ type amqpComponent struct {
 }
 
 func newAmqpComponent(url, queue, snsTopicArn string, snsPub patronsns.Publisher, sqsPub patronsqscli.Publisher,
-	sqsQueueURL string) (*amqpComponent, error) {
+	sqsQueueURL string,
+) (*amqpComponent, error) {
 	amqpCmp := amqpComponent{
 		snsTopicArn: snsTopicArn,
 		snsPub:      snsPub,
@@ -260,7 +261,7 @@ func newAmqpComponent(url, queue, snsTopicArn string, snsPub patronsns.Publisher
 		sqsQueueURL: sqsQueueURL,
 	}
 
-	cmp, err := patronamqp.New(url, queue, amqpCmp.Process, patronamqp.Retry(10, 1*time.Second))
+	cmp, err := patronamqp.New(url, queue, amqpCmp.Process, patronamqp.WithRetry(10, 1*time.Second))
 	if err != nil {
 		return nil, err
 	}
diff --git a/examples/client-decompression/main.go b/examples/client-decompression/main.go
index 130437e78..bc40e711e 100644
--- a/examples/client-decompression/main.go
+++ b/examples/client-decompression/main.go
@@ -38,7 +38,7 @@ func main() {
 		log.Fatalf("failed to create and run service %v", err)
 	}
 
-	cl, err := clienthttp.New(clienthttp.Timeout(1 * time.Second))
+	cl, err := clienthttp.New(clienthttp.WithTimeout(1 * time.Second))
 
 	noCompReq, err := http.NewRequest("GET", "http://localhost:50000/hello", nil)
 	rsp1, err := cl.Do(noCompReq)
diff --git a/examples/compression-middleware/main.go b/examples/compression-middleware/main.go
index 413219bf8..8647048e6 100644
--- a/examples/compression-middleware/main.go
+++ b/examples/compression-middleware/main.go
@@ -44,9 +44,6 @@ func main() {
 	name := "compression-middleware"
 	version := "1.0.0"
 
-	service, err := patron.New(name, version)
-	handle(err)
-
 	var routes v2.Routes
 	routes.Append(v2.NewGetRoute("/foo", rnd))
 	routes.Append(v2.NewGetRoute("/bar", rnd))
@@ -56,13 +53,16 @@ func main() {
 		log.Fatalf("failed to create routes: %v", err)
 	}
 
-	router, err := httprouter.New(httprouter.Routes(rr...))
+	router, err := httprouter.New(httprouter.WithRoutes(rr...))
 	if err != nil {
 		log.Fatalf("failed to create http router: %v", err)
 	}
 
+	service, err := patron.New(name, version, patron.WithRouter(router))
+	handle(err)
+
 	ctx := context.Background()
-	err = service.WithRouter(router).Run(ctx)
+	err = service.Run(ctx)
 	handle(err)
 }
 
diff --git a/examples/grpc/main.go b/examples/grpc/main.go
index 41b8aa85b..706aa523a 100644
--- a/examples/grpc/main.go
+++ b/examples/grpc/main.go
@@ -40,20 +40,20 @@ func main() {
 	name := "grpc"
 	version := "1.0.0"
 
-	service, err := patron.New(name, version, patron.TextLogger())
-	if err != nil {
-		log.Fatalf("failed to set up service: %v", err)
-	}
-
-	cmp, err := grpc.New(50006).Create()
+	cmp, err := grpc.New(50006)
 	if err != nil {
 		log.Fatalf("failed to create gRPC component: %v", err)
 	}
 
 	examples.RegisterGreeterServer(cmp.Server(), &greeterServer{})
 
+	service, err := patron.New(name, version, patron.WithTextLogger(), patron.WithComponents(cmp))
+	if err != nil {
+		log.Fatalf("failed to set up service: %v", err)
+	}
+
 	ctx := context.Background()
-	err = service.WithComponents(cmp).Run(ctx)
+	err = service.Run(ctx)
 	if err != nil {
 		log.Fatalf("failed to create and run service: %v", err)
 	}
diff --git a/examples/http-cache/main.go b/examples/http-cache/main.go
index 86ec735ce..bd5a82b95 100644
--- a/examples/http-cache/main.go
+++ b/examples/http-cache/main.go
@@ -34,11 +34,6 @@ func main() {
 	name := "http-cache"
 	version := "1.0.0"
 
-	service, err := patron.New(name, version, patron.TextLogger())
-	if err != nil {
-		log.Fatalf("failed to set up service: %v", err)
-	}
-
 	ctx := context.Background()
 
 	cache, err := redis.New(ctx, redis.Options{})
@@ -47,7 +42,7 @@ func main() {
 	}
 
 	var routes v2.Routes
-	routes.Append(v2.NewGetRoute("/", handler, v2.Cache(cache, httpcache.Age{
+	routes.Append(v2.NewGetRoute("/", handler, v2.WithCache(cache, httpcache.Age{
 		// we won't allow to override the cache more than once per 15 seconds
 		Min: 15 * time.Second,
 		// by default, we might send stale response for up to 1 minute
@@ -58,7 +53,7 @@ func main() {
 		log.Fatalf("failed to create routes: %v", err)
 	}
 
-	router, err := httprouter.New(httprouter.Routes(rr...))
+	router, err := httprouter.New(httprouter.WithRoutes(rr...))
 	if err != nil {
 		log.Fatalf("failed to create http router: %v", err)
 	}
@@ -68,7 +63,12 @@ func main() {
 		os.Exit(0)
 	}
 
-	err = service.WithRouter(router).WithSIGHUP(sig).Run(ctx)
+	service, err := patron.New(name, version, patron.WithTextLogger(), patron.WithRouter(router), patron.WithSIGHUP(sig))
+	if err != nil {
+		log.Fatalf("failed to set up service: %v", err)
+	}
+
+	err = service.Run(ctx)
 	if err != nil {
 		log.Fatalf("failed to create and run service %v", err)
 	}
diff --git a/examples/http-sec/main.go b/examples/http-sec/main.go
index 812f8a5be..91dbfe9f3 100644
--- a/examples/http-sec/main.go
+++ b/examples/http-sec/main.go
@@ -46,11 +46,6 @@ func main() {
 	name := "http-sec"
 	version := "1.0.0"
 
-	service, err := patron.New(name, version, patron.LogFields(map[string]interface{}{"env": "staging"}))
-	if err != nil {
-		log.Fatalf("failed to set up service: %v", err)
-	}
-
 	asyncComp, err := newAsyncKafkaProducer(kafkaBroker, kafkaTopic, true)
 	if err != nil {
 		log.Fatalf("failed to create processor %v", err)
@@ -62,19 +57,24 @@ func main() {
 	}
 
 	var routes v2.Routes
-	routes.Append(v2.NewGetRoute("/", asyncComp.forwardToKafkaHandler, v2.Auth(auth)))
+	routes.Append(v2.NewGetRoute("/", asyncComp.forwardToKafkaHandler, v2.WithAuth(auth)))
 	rr, err := routes.Result()
 	if err != nil {
 		log.Fatalf("failed to create routes: %v", err)
 	}
 
-	router, err := httprouter.New(httprouter.Routes(rr...), httprouter.EnableAppNameHeaders(name, version))
+	router, err := httprouter.New(httprouter.WithRoutes(rr...), httprouter.WithAppNameHeaders(name, version))
 	if err != nil {
 		log.Fatalf("failed to create http router: %v", err)
 	}
 
+	service, err := patron.New(name, version, patron.WithLogFields(map[string]interface{}{"env": "staging"}), patron.WithRouter(router))
+	if err != nil {
+		log.Fatalf("failed to set up service: %v", err)
+	}
+
 	ctx := context.Background()
-	err = service.WithRouter(router).Run(ctx)
+	err = service.Run(ctx)
 	if err != nil {
 		log.Fatalf("failed to create and run service %v", err)
 	}
@@ -123,7 +123,7 @@ func (hc *kafkaProducer) forwardToKafkaHandler(rw http.ResponseWriter, r *http.R
 		_, _ = rw.Write([]byte(fmt.Sprintf("failed to create request for www.google.com: %v", err)))
 		return
 	}
-	cl, err := clienthttp.New(clienthttp.Timeout(5 * time.Second))
+	cl, err := clienthttp.New(clienthttp.WithTimeout(5 * time.Second))
 	if err != nil {
 		rw.WriteHeader(http.StatusInternalServerError)
 		return
diff --git a/examples/http/main.go b/examples/http/main.go
index dbe2949d9..585595f69 100644
--- a/examples/http/main.go
+++ b/examples/http/main.go
@@ -61,11 +61,6 @@ func main() {
 
 	logger := std.New(os.Stderr, log.DebugLevel, map[string]interface{}{"env": "staging"})
 
-	service, err := patron.New(name, version, patron.Logger(logger))
-	if err != nil {
-		log.Fatalf("failed to set up service: %v", err)
-	}
-
 	// Set up a simple CORS middleware
 	corsMiddleware := func(h http.Handler) http.Handler {
 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
@@ -78,7 +73,7 @@ func main() {
 	}
 
 	var routes patronhttp.Routes
-	routes.Append(patronhttp.NewGetRoute("/api", getHandler, patronhttp.RateLimiting(50, 50)))
+	routes.Append(patronhttp.NewGetRoute("/api", getHandler, patronhttp.WithRateLimiting(50, 50)))
 	routes.Append(patronhttp.NewPostRoute("/api", httpHandler))
 	routes.Append(httprouter.NewFileServerRoute("/frontend/*path", assetsFolder, assetsFolder+"/index.html"))
 	rr, err := routes.Result()
@@ -86,7 +81,7 @@ func main() {
 		log.Fatalf("failed to create routes: %v", err)
 	}
 
-	router, err := httprouter.New(httprouter.Middlewares(corsMiddleware), httprouter.Routes(rr...))
+	router, err := httprouter.New(httprouter.WithMiddlewares(corsMiddleware), httprouter.WithRoutes(rr...))
 	if err != nil {
 		log.Fatalf("failed to create http router: %v", err)
 	}
@@ -96,8 +91,13 @@ func main() {
 		os.Exit(0)
 	}
 
+	service, err := patron.New(name, version, patron.WithLogger(logger), patron.WithRouter(router), patron.WithSIGHUP(sig))
+	if err != nil {
+		log.Fatalf("failed to set up service: %v", err)
+	}
+
 	ctx := context.Background()
-	err = service.WithRouter(router).WithSIGHUP(sig).Run(ctx)
+	err = service.Run(ctx)
 	if err != nil {
 		log.Fatalf("failed to create and run service %v", err)
 	}
@@ -151,7 +151,7 @@ func httpHandler(rw http.ResponseWriter, r *http.Request) {
 	httpRequest.Header.Add("Content-Type", protobuf.Type)
 	httpRequest.Header.Add("Accept", protobuf.Type)
 	httpRequest.Header.Add("Authorization", "Apikey 123456")
-	cl, err := patronhttpclient.New(patronhttpclient.Timeout(5 * time.Second))
+	cl, err := patronhttpclient.New(patronhttpclient.WithTimeout(5 * time.Second))
 	if err != nil {
 		patronhttpjson.WriteResponse(rw, http.StatusInternalServerError, newHttpError(fmt.Sprintf("failed execute request: %v", err)))
 		return
@@ -172,7 +172,7 @@ func DoIntervalRequest() (string, error) {
 	if err != nil {
 		return "", fmt.Errorf("failed create route request: %w", err)
 	}
-	cl, err := patronhttpclient.New(patronhttpclient.Timeout(5 * time.Second))
+	cl, err := patronhttpclient.New(patronhttpclient.WithTimeout(5 * time.Second))
 	if err != nil {
 		return "", fmt.Errorf("could not create http client: %w", err)
 	}
diff --git a/examples/kafka-legacy/main.go b/examples/kafka-legacy/main.go
index 92a39757f..e99eeb156 100644
--- a/examples/kafka-legacy/main.go
+++ b/examples/kafka-legacy/main.go
@@ -46,11 +46,6 @@ func main() {
 	name := "kafka"
 	version := "1.0.0"
 
-	service, err := patron.New(name, version, patron.TextLogger())
-	if err != nil {
-		log.Fatalf("failed to set up service: %v", err)
-	}
-
 	pub, err := patronamqp.New(amqpURL)
 	if err != nil {
 		log.Fatalf("failed to create AMQP publisher processor %v", err)
@@ -66,8 +61,13 @@ func main() {
 		log.Fatalf("failed to create processor %v", err)
 	}
 
+	service, err := patron.New(name, version, patron.WithTextLogger(), patron.WithComponents(kafkaCmp.cmp))
+	if err != nil {
+		log.Fatalf("failed to set up service: %v", err)
+	}
+
 	ctx := context.Background()
-	err = service.WithComponents(kafkaCmp.cmp).Run(ctx)
+	err = service.Run(ctx)
 	if err != nil {
 		log.Fatalf("failed to create and run service %v", err)
 	}
@@ -88,7 +88,7 @@ func newKafkaComponent(name, broker, topic, groupID string, publisher *patronamq
 		return nil, err
 	}
 
-	cf, err := group.New(name, groupID, []string{topic}, []string{broker}, saramaCfg, kafka.Decoder(json.DecodeRaw))
+	cf, err := group.New(name, groupID, []string{topic}, []string{broker}, saramaCfg, kafka.WithDecoder(json.DecodeRaw))
 	if err != nil {
 		return nil, err
 	}
diff --git a/examples/kafka/main.go b/examples/kafka/main.go
index 6a921010c..12f017946 100644
--- a/examples/kafka/main.go
+++ b/examples/kafka/main.go
@@ -45,11 +45,6 @@ func main() {
 	name := "kafka"
 	version := "1.0.0"
 
-	service, err := patron.New(name, version, patron.TextLogger())
-	if err != nil {
-		log.Fatalf("failed to set up service: %v", err)
-	}
-
 	pub, err := patronamqp.New(amqpURL)
 	if err != nil {
 		log.Fatalf("failed to create AMQP publisher processor %v", err)
@@ -65,8 +60,13 @@ func main() {
 		log.Fatalf("failed to create processor %v", err)
 	}
 
+	service, err := patron.New(name, version, patron.WithTextLogger(), patron.WithComponents(kafkaCmp.cmp))
+	if err != nil {
+		log.Fatalf("failed to set up service: %v", err)
+	}
+
 	ctx := context.Background()
-	err = service.WithComponents(kafkaCmp.cmp).Run(ctx)
+	err = service.Run(ctx)
 	if err != nil {
 		log.Fatalf("failed to create and run service %v", err)
 	}
@@ -96,8 +96,8 @@ func newKafkaComponent(name, broker, topic, groupID string, publisher *patronamq
 	saramaCfg.Version = sarama.V2_6_0_0
 
 	cmp, err := group.New(name, groupID, []string{broker}, []string{topic}, kafkaCmp.Process, saramaCfg,
-		group.FailureStrategy(kafka.SkipStrategy), group.BatchSize(1), group.BatchTimeout(1*time.Second),
-		group.Retries(10), group.RetryWait(3*time.Second), group.CommitSync())
+		group.WithFailureStrategy(kafka.SkipStrategy), group.WithBatchSize(1), group.WithBatchTimeout(1*time.Second),
+		group.WithRetries(10), group.WithRetryWait(3*time.Second), group.WithCommitSync())
 	if err != nil {
 		return nil, err
 	}
diff --git a/examples/sqs/main.go b/examples/sqs/main.go
index dcf62307d..a4d0a53e9 100644
--- a/examples/sqs/main.go
+++ b/examples/sqs/main.go
@@ -47,11 +47,6 @@ func main() {
 	version := "1.0.0"
 	ctx := context.Background()
 
-	service, err := patron.New(name, version)
-	if err != nil {
-		log.Fatalf("failed to set up service: %v", err)
-	}
-
 	cc, err := patrongrpc.Dial("localhost:50006", grpc.WithTransportCredentials(insecure.NewCredentials()))
 	if err != nil {
 		log.Fatalf("failed to dial grpc connection: %v", err)
@@ -72,7 +67,12 @@ func main() {
 		log.Fatalf("failed to create sqs component: %v", err)
 	}
 
-	err = service.WithComponents(sqsCmp.cmp).Run(ctx)
+	service, err := patron.New(name, version, patron.WithComponents(sqsCmp.cmp))
+	if err != nil {
+		log.Fatalf("failed to set up service: %v", err)
+	}
+
+	err = service.Run(ctx)
 	if err != nil {
 		log.Fatalf("failed to create and run service: %v", err)
 	}
@@ -88,7 +88,7 @@ func createSQSComponent(api *sqs.Client, greeter examples.GreeterClient) (*sqsCo
 		greeter: greeter,
 	}
 
-	cmp, err := patronsqs.New("sqs-cmp", awsSQSQueue, api, sqsCmp.Process, patronsqs.PollWaitSeconds(5))
+	cmp, err := patronsqs.New("sqs-cmp", awsSQSQueue, api, sqsCmp.Process, patronsqs.WithPollWaitSeconds(5))
 	if err != nil {
 		return nil, err
 	}
diff --git a/options.go b/options.go
new file mode 100644
index 000000000..99f136b14
--- /dev/null
+++ b/options.go
@@ -0,0 +1,87 @@
+package patron
+
+import (
+	"errors"
+	"net/http"
+	"os"
+
+	"github.com/beatlabs/patron/log"
+	"github.com/beatlabs/patron/log/std"
+)
+
+type OptionFunc func(svc *Service) error
+
+// WithRouter replaces the default v1 HTTP component with a new component v2 based on http.Handler.
+func WithRouter(handler http.Handler) OptionFunc {
+	return func(svc *Service) error {
+		if handler == nil {
+			return errors.New("provided router is nil")
+		}
+
+		log.Debug("router will be used with the v2 HTTP component")
+		svc.httpRouter = handler
+
+		return nil
+	}
+}
+
+// WithComponents adds custom components to the Patron Service.
+func WithComponents(cc ...Component) OptionFunc {
+	return func(svc *Service) error {
+		if len(cc) == 0 {
+			return errors.New("provided components slice was empty")
+		}
+
+		log.Debug("setting components")
+		svc.cps = append(svc.cps, cc...)
+
+		return nil
+	}
+}
+
+// WithSIGHUP adds a custom handler for handling WithSIGHUP.
+func WithSIGHUP(handler func()) OptionFunc {
+	return func(svc *Service) error {
+		if handler == nil {
+			return errors.New("provided WithSIGHUP handler was nil")
+		}
+
+		log.Debug("setting WithSIGHUP handler func")
+		svc.sighupHandler = handler
+
+		return nil
+	}
+}
+
+// WithLogFields options to pass in additional log fields.
+func WithLogFields(fields map[string]interface{}) OptionFunc {
+	return func(svc *Service) error {
+		for k, v := range fields {
+			if k == srv || k == ver || k == host {
+				// don't override
+				continue
+			}
+			svc.config.fields[k] = v
+		}
+
+		return nil
+	}
+}
+
+// WithLogger to pass in custom logger.
+func WithLogger(logger log.Logger) OptionFunc {
+	return func(svc *Service) error {
+		svc.config.logger = logger
+
+		return nil
+	}
+}
+
+// WithTextLogger to use Go's standard logger.
+func WithTextLogger() OptionFunc {
+	return func(svc *Service) error {
+		svc.config.logger = std.New(os.Stderr, getLogLevel(), svc.config.fields)
+
+		return nil
+	}
+}
diff --git a/service.go b/service.go
index 85bd34999..55817b914 100644
--- a/service.go
+++ b/service.go
@@ -13,12 +13,11 @@ import (
 	"syscall"
 	"time"
 
-	patronhttp "github.com/beatlabs/patron/component/http"
-	"github.com/beatlabs/patron/component/http/middleware"
+	"github.com/beatlabs/patron/component/http/v2/router/httprouter"
+
 	v2 "github.com/beatlabs/patron/component/http/v2"
 	patronErrors "github.com/beatlabs/patron/errors"
 	"github.com/beatlabs/patron/log"
-	"github.com/beatlabs/patron/log/std"
 	patronzerolog "github.com/beatlabs/patron/log/zerolog"
 	"github.com/beatlabs/patron/trace"
 	"github.com/uber/jaeger-client-go"
@@ -30,31 +29,29 @@ const (
 	host = "host"
 )
 
-// Component interface for implementing service components.
+// Component interface for implementing Service components.
 type Component interface {
 	Run(ctx context.Context) error
 }
 
-// service is responsible for managing and setting up everything.
-// The service will start by default an HTTP component in order to host management endpoint.
-type service struct {
+// Service is responsible for managing and setting up everything.
+// The Service will start by default an HTTP component in order to host management endpoint.
+type Service struct {
 	name              string
+	version           string
 	cps               []Component
-	routesBuilder     *patronhttp.RoutesBuilder
-	middlewares       []middleware.Func
-	acf               patronhttp.AliveCheckFunc
-	rcf               patronhttp.ReadyCheckFunc
 	termSig           chan os.Signal
 	sighupHandler     func()
 	uncompressedPaths []string
 	httpRouter        http.Handler
+	config            config
 }
 
-func (s *service) setupOSSignal() {
+func (s *Service) setupOSSignal() {
 	signal.Notify(s.termSig, os.Interrupt, syscall.SIGTERM, syscall.SIGHUP)
 }
 
-func (s *service) run(ctx context.Context) error {
+func (s *Service) Run(ctx context.Context) error {
 	defer func() {
 		err := trace.Close()
 		if err != nil {
@@ -72,7 +69,7 @@ func (s *service) run(ctx context.Context) error {
 		}(cp)
 	}
 
-	log.FromContext(ctx).Infof("service %s started", s.name)
+	log.FromContext(ctx).Infof("Service %s started", s.name)
 	ee := make([]error, 0, len(s.cps))
 	ee = append(ee, s.waitTermination(chErr))
 	cnl()
@@ -86,7 +83,7 @@ func (s *service) run(ctx context.Context) error {
 	return patronErrors.Aggregate(ee...)
 }
 
-func (s *service) createHTTPComponent() (Component, error) {
+func (s *Service) createHTTPComponent() (Component, error) {
 	var err error
 	portVal := int64(50000)
 	port, ok := os.LookupEnv("PATRON_HTTP_DEFAULT_PORT")
@@ -98,23 +95,31 @@ func (s *service) createHTTPComponent() (Component, error) {
 	}
 	log.Debugf("creating default HTTP component at port %d", portVal)
 
-	readTimeout, err := getHTTPReadTimeout()
+	deflateLevel, err := getHTTPDeflateLevel()
 	if err != nil {
 		return nil, err
 	}
 
-	writeTimeout, err := getHTTPWriteTimeout()
+	readTimeout, err := getHTTPReadTimeout()
 	if err != nil {
 		return nil, err
 	}
 
-	deflateLevel, err := getHTTPDeflateLevel()
+	writeTimeout, err := getHTTPWriteTimeout()
 	if err != nil {
 		return nil, err
 	}
 
 	if s.httpRouter == nil {
-		return s.createHTTPv1(int(portVal), readTimeout, writeTimeout, deflateLevel)
+		routerOptions := make([]httprouter.OptionFunc, 0)
+		if deflateLevel != nil {
+			routerOptions = append(routerOptions, httprouter.WithDeflateLevel(*deflateLevel))
+		}
+
+		s.httpRouter, err = httprouter.New(routerOptions...)
+		if err != nil {
+			return nil, err
+		}
 	}
 
 	return s.createHTTPv2(int(portVal), readTimeout, writeTimeout)
@@ -156,64 +161,21 @@ func getHTTPDeflateLevel() (*int, error) {
 	return &deflateLevelInt, nil
 }
 
-func (s *service) createHTTPv1(port int, readTimeout, writeTimeout *time.Duration, deflateLevel *int) (Component, error) {
-	b := patronhttp.NewBuilder().WithPort(port)
+func (s *Service) createHTTPv2(port int, readTimeout, writeTimeout *time.Duration) (Component, error) {
+	oo := []v2.OptionFunc{v2.WithPort(port)}
 
 	if readTimeout != nil {
-		b.WithReadTimeout(*readTimeout)
+		oo = append(oo, v2.WithReadTimeout(*readTimeout))
 	}
 
 	if writeTimeout != nil {
-		b.WithWriteTimeout(*writeTimeout)
-	}
-
-	if deflateLevel != nil {
-		b.WithDeflateLevel(*deflateLevel)
-	}
-
-	if s.acf != nil {
-		b.WithAliveCheckFunc(s.acf)
-	}
-
-	if s.rcf != nil {
-		b.WithReadyCheckFunc(s.rcf)
-	}
-
-	if s.routesBuilder != nil {
-		b.WithRoutesBuilder(s.routesBuilder)
-	}
-
-	if s.middlewares != nil && len(s.middlewares) > 0 {
-		b.WithMiddlewares(s.middlewares...)
-	}
-
-	if s.uncompressedPaths != nil {
-		b.WithUncompressedPaths(s.uncompressedPaths...)
-	}
-
-	cp, err := b.Create()
-	if err != nil {
-		return nil, fmt.Errorf("failed to create default HTTP component: %w", err)
-	}
-
-	return cp, nil
-}
-
-func (s *service) createHTTPv2(port int, readTimeout, writeTimeout *time.Duration) (Component, error) {
-	oo := []v2.OptionFunc{v2.Port(port)}
-
-	if readTimeout != nil {
-		oo = append(oo, v2.ReadTimeout(*readTimeout))
-	}
-
-	if writeTimeout != nil {
-		oo = append(oo, v2.WriteTimeout(*writeTimeout))
+		oo = append(oo, v2.WithWriteTimeout(*writeTimeout))
 	}
 
 	return v2.New(s.httpRouter, oo...)
 }
 
-func (s *service) waitTermination(chErr <-chan error) error {
+func (s *Service) waitTermination(chErr <-chan error) error {
 	for {
 		select {
 		case sig := <-s.termSig:
@@ -235,94 +197,12 @@ func (s *service) waitTermination(chErr <-chan error) error {
 	}
 }
 
-// Builder gathers all required properties to
-// construct a Patron service.
-type Builder struct {
-	errors            []error
-	name              string
-	version           string
-	cps               []Component
-	routesBuilder     *patronhttp.RoutesBuilder
-	middlewares       []middleware.Func
-	acf               patronhttp.AliveCheckFunc
-	rcf               patronhttp.ReadyCheckFunc
-	termSig           chan os.Signal
-	sighupHandler     func()
-	uncompressedPaths []string
-	httpRouter        http.Handler
-}
-
-// Config for setting up the builder.
-type Config struct {
+// config for setting up the builder.
+type config struct {
 	fields map[string]interface{}
 	logger log.Logger
 }
 
-// Option for providing function configuration.
-type Option func(*Config)
-
-// LogFields options to pass in additional log fields.
-func LogFields(fields map[string]interface{}) Option {
-	return func(cfg *Config) {
-		for k, v := range fields {
-			if k == srv || k == ver || k == host {
-				// don't override
-				continue
-			}
-			cfg.fields[k] = v
-		}
-	}
-}
-
-// Logger to pass in custom logger.
-func Logger(logger log.Logger) Option {
-	return func(cfg *Config) {
-		cfg.logger = logger
-	}
-}
-
-// TextLogger to use Go's standard logger.
-func TextLogger() Option {
-	return func(cfg *Config) {
-		cfg.logger = std.New(os.Stderr, getLogLevel(), cfg.fields)
-	}
-}
-
-// New creates a builder with functional options.
-func New(name, version string, options ...Option) (*Builder, error) {
-	if name == "" {
-		return nil, errors.New("name is required")
-	}
-	if version == "" {
-		version = "dev"
-	}
-
-	// default config with structured logger and default fields.
-	cfg := Config{
-		logger: patronzerolog.New(os.Stderr, getLogLevel(), nil),
-		fields: defaultLogFields(name, version),
-	}
-
-	for _, option := range options {
-		option(&cfg)
-	}
-
-	err := setupLogging(cfg.fields, cfg.logger)
-	if err != nil {
-		return nil, err
-	}
-
-	return &Builder{
-		errors:        make([]error, 0),
-		name:          name,
-		version:       version,
-		acf:           patronhttp.DefaultAliveCheck,
-		rcf:           patronhttp.DefaultReadyCheck,
-		termSig:       make(chan os.Signal, 1),
-		sighupHandler: func() { log.Debug("SIGHUP received: nothing setup") },
-	}, nil
-}
-
 func getLogLevel() log.Level {
 	lvl, ok := os.LookupEnv("PATRON_LOG_LEVEL")
 	if !ok {
@@ -390,141 +270,54 @@ func setupJaegerTracing(name, version string) error {
 	return trace.Setup(name, version, agent, tp, prmVal, buckets)
 }
 
-// WithRoutesBuilder adds routes builder to the default HTTP component.
-//
-// Deprecated: Please use the new v2 package.
-// This package is frozen and no new functionality will be added.
-func (b *Builder) WithRoutesBuilder(rb *patronhttp.RoutesBuilder) *Builder {
-	if rb == nil {
-		b.errors = append(b.errors, errors.New("routes builder is nil"))
-	} else {
-		log.Debug("setting routes builder")
-		b.routesBuilder = rb
-	}
-
-	return b
-}
-
-// WithMiddlewares adds generic middlewares to the default HTTP component.
-//
-// Deprecated: Please use the new v2 package.
-// This package is frozen and no new functionality will be added.
-func (b *Builder) WithMiddlewares(mm ...middleware.Func) *Builder {
-	if len(mm) == 0 {
-		b.errors = append(b.errors, errors.New("provided middlewares slice was empty"))
-	} else {
-		log.Debug("setting middlewares")
-		b.middlewares = append(b.middlewares, mm...)
-	}
-
-	return b
-}
-
-// WithAliveCheck overrides the default liveness check of the default HTTP component.
-//
-// Deprecated: Please use the new v2 package.
-// This package is frozen and no new functionality will be added.
-func (b *Builder) WithAliveCheck(acf patronhttp.AliveCheckFunc) *Builder {
-	if acf == nil {
-		b.errors = append(b.errors, errors.New("alive check func provided was nil"))
-	} else {
-		log.Debug("setting alive check func")
-		b.acf = acf
+func New(name, version string, options ...OptionFunc) (*Service, error) {
+	if name == "" {
+		return nil, errors.New("name is required")
 	}
-
-	return b
-}
-
-// WithReadyCheck overrides the default readiness check of the default HTTP component.
-//
-// Deprecated: Please use the new v2 package.
-// This package is frozen and no new functionality will be added.
-func (b *Builder) WithReadyCheck(rcf patronhttp.ReadyCheckFunc) *Builder {
-	if rcf == nil {
-		b.errors = append(b.errors, errors.New("ready check func provided was nil"))
-	} else {
-		log.Debug("setting ready check func")
-		b.rcf = rcf
+	if version == "" {
+		version = "dev"
 	}
 
-	return b
-}
-
-// WithComponents adds custom components to the Patron service.
-func (b *Builder) WithComponents(cc ...Component) *Builder {
-	if len(cc) == 0 {
-		b.errors = append(b.errors, errors.New("provided components slice was empty"))
-	} else {
-		log.Debug("setting components")
-		b.cps = append(b.cps, cc...)
+	// default config with structured logger and default fields.
+	cfg := config{
+		logger: patronzerolog.New(os.Stderr, getLogLevel(), nil),
+		fields: defaultLogFields(name, version),
 	}
 
-	return b
-}
-
-// WithSIGHUP adds a custom handler for handling SIGHUP.
-func (b *Builder) WithSIGHUP(handler func()) *Builder {
-	if handler == nil {
-		b.errors = append(b.errors, errors.New("provided SIGHUP handler was nil"))
-	} else {
-		log.Debug("setting SIGHUP handler func")
-		b.sighupHandler = handler
+	s := &Service{
+		name:    name,
+		version: version,
+		termSig: make(chan os.Signal, 1),
+		sighupHandler: func() {
+			log.Debug("WithSIGHUP received: nothing setup")
+		},
+		config: cfg,
+		cps:    make([]Component, 0),
 	}
 
-	return b
-}
-
-// WithUncompressedPaths defines a list of paths which the compre ssion middleware will skip.
-//
-// Deprecated: Please use the new v2 package.
-// This package is frozen and no new functionality will be added.
-func (b *Builder) WithUncompressedPaths(p ...string) *Builder {
-	if len(p) == 0 {
-		b.errors = append(b.errors, errors.New("provided uncompressed paths slice was empty"))
-	} else {
-		log.Debug("setting paths which for which compression will be skipped")
-		b.uncompressedPaths = p
+	var err error
+	err = setupJaegerTracing(name, version)
+	if err != nil {
+		return nil, err
 	}
 
-	return b
-}
-
-// WithRouter replaces the default v1 HTTP component with a new component v2 based on http.Handler.
-func (b *Builder) WithRouter(handler http.Handler) *Builder {
-	if handler == nil {
-		b.errors = append(b.errors, errors.New("provided router is nil"))
-	} else {
-		b.httpRouter = handler
-		log.Debug("router will be used with the v2 HTTP component")
+	optionErrors := make([]error, 0)
+	for _, option := range options {
+		err = option(s)
+		if err != nil {
+			optionErrors = append(optionErrors, err)
+		}
 	}
 
-	return b
-}
-
-// Build constructs the Patron service by applying the gathered properties.
-func (b *Builder) build() (*service, error) {
-	if len(b.errors) > 0 {
-		return nil, patronErrors.Aggregate(b.errors...)
+	if len(optionErrors) > 0 {
+		return nil, patronErrors.Aggregate(optionErrors...)
 	}
 
-	err := setupJaegerTracing(b.name, b.version)
+	err = setupLogging(cfg.fields, cfg.logger)
 	if err != nil {
 		return nil, err
 	}
 
-	s := service{
-		name:              b.name,
-		cps:               b.cps,
-		routesBuilder:     b.routesBuilder,
-		middlewares:       b.middlewares,
-		acf:               b.acf,
-		rcf:               b.rcf,
-		termSig:           b.termSig,
-		sighupHandler:     b.sighupHandler,
-		uncompressedPaths: b.uncompressedPaths,
-		httpRouter:        b.httpRouter,
-	}
-
 	httpCp, err := s.createHTTPComponent()
 	if err != nil {
 		return nil, err
@@ -532,17 +325,6 @@ func (b *Builder) build() (*service, error) {
 
 	s.cps = append(s.cps, httpCp)
 	s.setupOSSignal()
-	return &s, nil
-}
-
-// Run starts up all service components and monitors for errors.
-// If a component returns an error the service is responsible for shutting down
-// all components and terminate itself.
-func (b *Builder) Run(ctx context.Context) error {
-	s, err := b.build()
-	if err != nil {
-		return err
-	}
 
-	return s.run(ctx)
+	return s, nil
 }


Test patch:
diff --git a/client/amqp/amqp_test.go b/client/amqp/amqp_test.go
index 53208185c..3b3ea5a90 100644
--- a/client/amqp/amqp_test.go
+++ b/client/amqp/amqp_test.go
@@ -46,7 +46,7 @@ func TestNewPublisher(t *testing.T) {
 	}{
 		{name: "fail, missing url", args: args{}, wantErr: true},
 		{name: "fail, missing exchange", args: args{url: "url"}, wantErr: true},
-		{name: "fail, missing exchange", args: args{url: "url", exc: "exc", opt: Timeout(0)}, wantErr: true},
+		{name: "fail, missing exchange", args: args{url: "url", exc: "exc", opt: WithTimeout(0)}, wantErr: true},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/client/amqp/option_test.go b/client/amqp/option_test.go
index 8b88679b3..79b1a4db4 100644
--- a/client/amqp/option_test.go
+++ b/client/amqp/option_test.go
@@ -22,7 +22,7 @@ func TestTimeout(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			p := TracedPublisher{cfg: defaultCfg}
-			err := Timeout(tt.args.timeout)(&p)
+			err := WithTimeout(tt.args.timeout)(&p)
 			if tt.wantErr {
 				assert.Error(t, err)
 			} else {
diff --git a/client/amqp/v2/option_test.go b/client/amqp/v2/option_test.go
index b98160b70..f28dfee11 100644
--- a/client/amqp/v2/option_test.go
+++ b/client/amqp/v2/option_test.go
@@ -13,6 +13,6 @@ func TestTimeout(t *testing.T) {
 	}
 
 	p := Publisher{}
-	assert.NoError(t, Config(cfg)(&p))
+	assert.NoError(t, WithConfig(cfg)(&p))
 	assert.Equal(t, cfg, *p.cfg)
 }
diff --git a/client/http/http_test.go b/client/http/http_test.go
index 8f88f4933..2157311eb 100644
--- a/client/http/http_test.go
+++ b/client/http/http_test.go
@@ -32,9 +32,9 @@ func TestTracedClient_Do(t *testing.T) {
 	opentracing.SetGlobalTracer(mtr)
 	c, err := New()
 	assert.NoError(t, err)
-	cb, err := New(CircuitBreaker("test", circuitbreaker.Setting{}))
+	cb, err := New(WithCircuitBreaker("test", circuitbreaker.Setting{}))
 	assert.NoError(t, err)
-	ct, err := New(Transport(&http.Transport{}))
+	ct, err := New(WithTransport(&http.Transport{}))
 	assert.NoError(t, err)
 	req, err := http.NewRequest("GET", ts.URL, nil)
 	assert.NoError(t, err)
@@ -89,7 +89,7 @@ func TestTracedClient_Do_Redirect(t *testing.T) {
 		http.Redirect(w, r, "https://google.com", http.StatusSeeOther)
 	}))
 	defer ts.Close()
-	c, err := New(CheckRedirect(func(req *http.Request, via []*http.Request) error {
+	c, err := New(WithCheckRedirect(func(req *http.Request, via []*http.Request) error {
 		return errors.New("stop redirects")
 	}))
 	assert.NoError(t, err)
@@ -113,15 +113,15 @@ func TestNew(t *testing.T) {
 		wantErr bool
 	}{
 		{name: "success", args: args{oo: []OptionFunc{
-			Timeout(time.Second),
-			CircuitBreaker("test", circuitbreaker.Setting{}),
-			Transport(&http.Transport{}),
-			CheckRedirect(func(req *http.Request, via []*http.Request) error { return nil }),
+			WithTimeout(time.Second),
+			WithCircuitBreaker("test", circuitbreaker.Setting{}),
+			WithTransport(&http.Transport{}),
+			WithCheckRedirect(func(req *http.Request, via []*http.Request) error { return nil }),
 		}}, wantErr: false},
-		{name: "failure, invalid timeout", args: args{oo: []OptionFunc{Timeout(0 * time.Second)}}, wantErr: true},
-		{name: "failure, invalid circuit breaker", args: args{[]OptionFunc{CircuitBreaker("", circuitbreaker.Setting{})}}, wantErr: true},
-		{name: "failure, invalid transport", args: args{[]OptionFunc{Transport(nil)}}, wantErr: true},
-		{name: "failure, invalid check redirect", args: args{[]OptionFunc{CheckRedirect(nil)}}, wantErr: true},
+		{name: "failure, invalid timeout", args: args{oo: []OptionFunc{WithTimeout(0 * time.Second)}}, wantErr: true},
+		{name: "failure, invalid circuit breaker", args: args{[]OptionFunc{WithCircuitBreaker("", circuitbreaker.Setting{})}}, wantErr: true},
+		{name: "failure, invalid transport", args: args{[]OptionFunc{WithTransport(nil)}}, wantErr: true},
+		{name: "failure, invalid check redirect", args: args{[]OptionFunc{WithCheckRedirect(nil)}}, wantErr: true},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/client/http/option_test.go b/client/http/option_test.go
index 0cad87b7a..5f58aa169 100644
--- a/client/http/option_test.go
+++ b/client/http/option_test.go
@@ -12,7 +12,7 @@ import (
 
 func TestTransport(t *testing.T) {
 	transport := &http.Transport{}
-	client, err := New(Transport(transport))
+	client, err := New(WithTransport(transport))
 
 	assert.NoError(t, err)
 	assert.NotNil(t, client)
@@ -20,14 +20,14 @@ func TestTransport(t *testing.T) {
 }
 
 func TestTransport_Nil(t *testing.T) {
-	client, err := New(Transport(nil))
+	client, err := New(WithTransport(nil))
 
 	assert.Nil(t, client)
 	assert.Error(t, err, "transport must be supplied")
 }
 
 func TestCheckRedirect_Nil(t *testing.T) {
-	client, err := New(CheckRedirect(nil))
+	client, err := New(WithCheckRedirect(nil))
 
 	assert.Nil(t, client)
 	assert.Error(t, err, "check redirect must be supplied")
@@ -38,7 +38,7 @@ func TestCheckRedirect(t *testing.T) {
 		return nil
 	}
 
-	client, err := New(CheckRedirect(cr))
+	client, err := New(WithCheckRedirect(cr))
 	assert.NoError(t, err)
 	assert.NotNil(t, client)
 
diff --git a/component/amqp/component_test.go b/component/amqp/component_test.go
index f190ef9cf..a3f60782c 100644
--- a/component/amqp/component_test.go
+++ b/component/amqp/component_test.go
@@ -29,7 +29,7 @@ func TestNew(t *testing.T) {
 				url:   "url",
 				queue: "queue",
 				proc:  proc,
-				oo:    []OptionFunc{Batching(5, 5*time.Millisecond)},
+				oo:    []OptionFunc{WithBatching(5, 5*time.Millisecond)},
 			},
 		},
 		"missing url": {
@@ -37,7 +37,7 @@ func TestNew(t *testing.T) {
 				url:   "",
 				queue: "queue",
 				proc:  proc,
-				oo:    []OptionFunc{Batching(5, 5*time.Millisecond)},
+				oo:    []OptionFunc{WithBatching(5, 5*time.Millisecond)},
 			},
 			expectedErr: "url is empty",
 		},
@@ -46,7 +46,7 @@ func TestNew(t *testing.T) {
 				url:   "url",
 				queue: "",
 				proc:  proc,
-				oo:    []OptionFunc{Batching(5, 5*time.Millisecond)},
+				oo:    []OptionFunc{WithBatching(5, 5*time.Millisecond)},
 			},
 			expectedErr: "queue is empty",
 		},
@@ -55,7 +55,7 @@ func TestNew(t *testing.T) {
 				url:   "url",
 				queue: "queue",
 				proc:  nil,
-				oo:    []OptionFunc{Batching(5, 5*time.Millisecond)},
+				oo:    []OptionFunc{WithBatching(5, 5*time.Millisecond)},
 			},
 			expectedErr: "process function is nil",
 		},
@@ -64,7 +64,7 @@ func TestNew(t *testing.T) {
 				url:   "url",
 				queue: "queue",
 				proc:  proc,
-				oo:    []OptionFunc{Batching(0, 5*time.Millisecond)},
+				oo:    []OptionFunc{WithBatching(0, 5*time.Millisecond)},
 			},
 			expectedErr: "count should be larger than 1 message",
 		},
diff --git a/component/amqp/integration_test.go b/component/amqp/integration_test.go
index adb792965..aa8f41dcf 100644
--- a/component/amqp/integration_test.go
+++ b/component/amqp/integration_test.go
@@ -60,7 +60,7 @@ func TestRun(t *testing.T) {
 		}
 	}
 
-	cmp, err := New(endpoint, rabbitMQQueue, procFunc, StatsInterval(10*time.Millisecond))
+	cmp, err := New(endpoint, rabbitMQQueue, procFunc, WithStatsInterval(10*time.Millisecond))
 	require.NoError(t, err)
 
 	chDone := make(chan struct{})
diff --git a/component/amqp/option_test.go b/component/amqp/option_test.go
index b3c2e80a9..372192e6f 100644
--- a/component/amqp/option_test.go
+++ b/component/amqp/option_test.go
@@ -11,7 +11,7 @@ import (
 func TestAMQPConfig(t *testing.T) {
 	cfg := amqp.Config{Locale: "123"}
 	c := &Component{}
-	assert.NoError(t, Config(cfg)(c))
+	assert.NoError(t, WithConfig(cfg)(c))
 	assert.Equal(t, cfg, c.cfg)
 }
 
@@ -34,7 +34,7 @@ func TestBatching(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := Batching(tt.args.count, tt.args.timeout)(c)
+			err := WithBatching(tt.args.count, tt.args.timeout)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -50,14 +50,14 @@ func TestRetry(t *testing.T) {
 	retryCount := uint(5)
 	retryDelay := 2 * time.Second
 	c := &Component{}
-	assert.NoError(t, Retry(retryCount, retryDelay)(c))
+	assert.NoError(t, WithRetry(retryCount, retryDelay)(c))
 	assert.Equal(t, retryCount, c.retryCfg.count)
 	assert.Equal(t, retryDelay, c.retryCfg.delay)
 }
 
 func TestRequeue(t *testing.T) {
 	c := &Component{}
-	assert.NoError(t, Requeue(false)(c))
+	assert.NoError(t, WithRequeue(false)(c))
 	assert.False(t, c.queueCfg.requeue)
 }
 
@@ -78,7 +78,7 @@ func TestStatsInterval(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := StatsInterval(tt.args.interval)(c)
+			err := WithStatsInterval(tt.args.interval)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
diff --git a/component/async/amqp/amqp_test.go b/component/async/amqp/amqp_test.go
index a4753df01..e1e1709b2 100644
--- a/component/async/amqp/amqp_test.go
+++ b/component/async/amqp/amqp_test.go
@@ -87,9 +87,9 @@ func TestNew(t *testing.T) {
 		args    args
 		wantErr bool
 	}{
-		{"success", args{url: "amqp://guest:guest@localhost:5672/", queue: "q", exchange: *validExch, opt: Buffer(100)}, false},
-		{"fail, invalid url", args{url: "", queue: "q", exchange: *validExch, opt: Buffer(100)}, true},
-		{"fail, invalid queue name", args{url: "url", queue: "", exchange: *validExch, opt: Buffer(100)}, true},
+		{"success", args{url: "amqp://guest:guest@localhost:5672/", queue: "q", exchange: *validExch, opt: WithBuffer(100)}, false},
+		{"fail, invalid url", args{url: "", queue: "q", exchange: *validExch, opt: WithBuffer(100)}, true},
+		{"fail, invalid queue name", args{url: "url", queue: "", exchange: *validExch, opt: WithBuffer(100)}, true},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
@@ -115,7 +115,7 @@ func TestFactory_Create(t *testing.T) {
 		wantErr bool
 	}{
 		{name: "success", wantErr: false},
-		{name: "invalid option", fields: fields{oo: []OptionFunc{Buffer(-10)}}, wantErr: true},
+		{name: "invalid option", fields: fields{oo: []OptionFunc{WithBuffer(-10)}}, wantErr: true},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/component/async/amqp/option_test.go b/component/async/amqp/option_test.go
index fb6aceb0b..cacbd1520 100644
--- a/component/async/amqp/option_test.go
+++ b/component/async/amqp/option_test.go
@@ -22,7 +22,7 @@ func TestBuffer(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			c := consumer{}
-			err := Buffer(tt.args.buf)(&c)
+			err := WithBuffer(tt.args.buf)(&c)
 			if tt.wantErr {
 				assert.Error(t, err)
 			} else {
@@ -34,13 +34,13 @@ func TestBuffer(t *testing.T) {
 
 func TestRequeue(t *testing.T) {
 	c := consumer{}
-	err := Requeue(false)(&c)
+	err := WithRequeue(false)(&c)
 	assert.NoError(t, err)
 }
 
 func TestTimeout(t *testing.T) {
 	c := consumer{}
-	err := Timeout(time.Second)(&c)
+	err := WithTimeout(time.Second)(&c)
 	assert.NoError(t, err)
 }
 
@@ -60,7 +60,7 @@ func TestBindings(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			c := consumer{}
-			err := Bindings(tt.args.bindings...)(&c)
+			err := WithBindings(tt.args.bindings...)(&c)
 			if tt.wantErr {
 				assert.Error(t, err)
 			} else {
diff --git a/component/async/kafka/group/group_test.go b/component/async/kafka/group/group_test.go
index 3f1360429..671d98515 100644
--- a/component/async/kafka/group/group_test.go
+++ b/component/async/kafka/group/group_test.go
@@ -108,7 +108,7 @@ func TestFactory_Create(t *testing.T) {
 				clientName: "clientB",
 				topics:     []string{"topicA"},
 				brokers:    []string{"192.168.1.1"},
-				oo:         []kafka.OptionFunc{kafka.Buffer(-100)},
+				oo:         []kafka.OptionFunc{kafka.WithBuffer(-100)},
 			},
 			wantErr: true,
 		},
diff --git a/component/async/kafka/group/integration_test.go b/component/async/kafka/group/integration_test.go
index 7f03889d0..0d09547c7 100644
--- a/component/async/kafka/group/integration_test.go
+++ b/component/async/kafka/group/integration_test.go
@@ -43,8 +43,8 @@ func TestGroupConsume(t *testing.T) {
 		saramaCfg, err := kafkacmp.DefaultConsumerSaramaConfig("test-group-consumer", true)
 		require.NoError(t, err)
 
-		factory, err := New("test1", uuid.New().String(), []string{groupTopic1}, []string{broker}, saramaCfg, kafka.DecoderJSON(),
-			kafka.Version(sarama.V2_1_0_0.String()), kafka.StartFromNewest())
+		factory, err := New("test1", uuid.New().String(), []string{groupTopic1}, []string{broker}, saramaCfg, kafka.WithDecoderJSON(),
+			kafka.WithVersion(sarama.V2_1_0_0.String()), kafka.WithStartFromNewest())
 		if err != nil {
 			chErr <- err
 			return
@@ -100,7 +100,7 @@ func TestGroupConsume_ClaimMessageError(t *testing.T) {
 
 	// Consumer will error out in ClaimMessage as no DecoderFunc has been set
 	factory, err := New("test1", uuid.New().String(), []string{groupTopic2}, []string{broker}, saramaCfg,
-		kafka.Version(sarama.V2_1_0_0.String()), kafka.StartFromNewest())
+		kafka.WithVersion(sarama.V2_1_0_0.String()), kafka.WithStartFromNewest())
 	require.NoError(t, err)
 	consumer, err := factory.Create()
 	require.NoError(t, err)
@@ -154,11 +154,11 @@ func TestKafkaAsyncPackageComponent_Success(t *testing.T) {
 	patronContext, patronCancel := context.WithCancel(context.Background())
 	var patronWG sync.WaitGroup
 	patronWG.Add(1)
-	svc, err := patron.New(successTopic1, "0", patron.TextLogger())
+	svc, err := patron.New(successTopic1, "0", patron.WithTextLogger(), patron.WithComponents(component))
 	require.NoError(t, err)
 
 	go func() {
-		err = svc.WithComponents(component).Run(patronContext)
+		err = svc.Run(patronContext)
 		require.NoError(t, err)
 		patronWG.Done()
 	}()
@@ -233,9 +233,9 @@ func TestKafkaAsyncPackageComponent_FailAllRetries(t *testing.T) {
 	}()
 
 	// Run Patron with the component - no need for goroutine since we expect it to stop after the retries fail
-	svc, err := patron.New(failAllRetriesTopic1, "0", patron.TextLogger())
+	svc, err := patron.New(failAllRetriesTopic1, "0", patron.WithTextLogger(), patron.WithComponents(component))
 	require.NoError(t, err)
-	err = svc.WithComponents(component).Run(context.Background())
+	err = svc.Run(context.Background())
 	assert.Error(t, err)
 
 	// Wait for the producer & consumer to finish
@@ -292,9 +292,9 @@ func TestKafkaAsyncPackageComponent_FailOnceAndRetry(t *testing.T) {
 	var patronWG sync.WaitGroup
 	patronWG.Add(1)
 	go func() {
-		svc, err := patron.New(failAndRetryTopic1, "0", patron.TextLogger())
+		svc, err := patron.New(failAndRetryTopic1, "0", patron.WithTextLogger(), patron.WithComponents(component))
 		require.NoError(t, err)
-		err = svc.WithComponents(component).Run(patronContext)
+		err = svc.Run(patronContext)
 		require.NoError(t, err)
 		patronWG.Done()
 	}()
@@ -330,7 +330,7 @@ func newKafkaAsyncPackageComponent(t *testing.T, name string, retries uint, proc
 	require.NoError(t, err)
 
 	factory, err := New(name, name+"-group", []string{name},
-		[]string{broker}, saramaCfg, kafka.Decoder(decode), kafka.Start(sarama.OffsetOldest))
+		[]string{broker}, saramaCfg, kafka.WithDecoder(decode), kafka.WithStart(sarama.OffsetOldest))
 	require.NoError(t, err)
 
 	cmp, err := async.New(name, factory, processorFunc).WithRetries(retries).
diff --git a/component/async/kafka/option_test.go b/component/async/kafka/option_test.go
index a7e0f4f27..81481e86c 100644
--- a/component/async/kafka/option_test.go
+++ b/component/async/kafka/option_test.go
@@ -26,7 +26,7 @@ func TestBuffer(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			c := ConsumerConfig{}
-			err := Buffer(tt.args.buf)(&c)
+			err := WithBuffer(tt.args.buf)(&c)
 			if tt.wantErr {
 				assert.Error(t, err)
 			} else {
@@ -40,7 +40,7 @@ func TestBuffer(t *testing.T) {
 func TestTimeout(t *testing.T) {
 	c := ConsumerConfig{}
 	c.SaramaConfig = sarama.NewConfig()
-	err := Timeout(time.Second)(&c)
+	err := WithTimeout(time.Second)(&c)
 	assert.NoError(t, err)
 }
 
@@ -62,7 +62,7 @@ func TestVersion(t *testing.T) {
 		t.Run(tt.name, func(t *testing.T) {
 			c := ConsumerConfig{}
 			c.SaramaConfig = sarama.NewConfig()
-			err := Version(tt.args.version)(&c)
+			err := WithVersion(tt.args.version)(&c)
 			if tt.wantErr {
 				assert.Error(t, err)
 			} else {
@@ -79,16 +79,16 @@ func TestStart(t *testing.T) {
 		optionFunc      OptionFunc
 		expectedOffsets int64
 	}{
-		"Start": {
-			Start(5),
+		"WithStart": {
+			WithStart(5),
 			int64(5),
 		},
-		"StartFromNewest": {
-			StartFromNewest(),
+		"WithStartFromNewest": {
+			WithStartFromNewest(),
 			sarama.OffsetNewest,
 		},
-		"StartFromOldest": {
-			StartFromOldest(),
+		"WithStartFromOldest": {
+			WithStartFromOldest(),
 			sarama.OffsetOldest,
 		},
 	}
@@ -128,7 +128,7 @@ func TestDecoder1(t *testing.T) {
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
 			c := ConsumerConfig{}
-			err := Decoder(tt.dec)(&c)
+			err := WithDecoder(tt.dec)(&c)
 			if tt.err {
 				assert.Error(t, err)
 			} else {
@@ -145,7 +145,7 @@ func TestDecoder1(t *testing.T) {
 
 func TestDecoderJSON(t *testing.T) {
 	c := ConsumerConfig{}
-	err := DecoderJSON()(&c)
+	err := WithDecoderJSON()(&c)
 	assert.NoError(t, err)
 	assert.Equal(t,
 		reflect.ValueOf(json.DecodeRaw).Pointer(),
diff --git a/component/async/kafka/simple/integration_test.go b/component/async/kafka/simple/integration_test.go
index e6ef74946..095625a23 100644
--- a/component/async/kafka/simple/integration_test.go
+++ b/component/async/kafka/simple/integration_test.go
@@ -36,8 +36,8 @@ func TestSimpleConsume(t *testing.T) {
 		saramaCfg, err := kafkacmp.DefaultConsumerSaramaConfig("test-simple-consumer", true)
 		require.NoError(t, err)
 
-		factory, err := New("test1", simpleTopic1, []string{broker}, saramaCfg, kafka.DecoderJSON(), kafka.Version(sarama.V2_1_0_0.String()),
-			kafka.StartFromNewest())
+		factory, err := New("test1", simpleTopic1, []string{broker}, saramaCfg, kafka.WithDecoderJSON(), kafka.WithVersion(sarama.V2_1_0_0.String()),
+			kafka.WithStartFromNewest())
 		if err != nil {
 			chErr <- err
 			return
@@ -90,8 +90,8 @@ func TestSimpleConsume_ClaimMessageError(t *testing.T) {
 		saramaCfg, err := kafkacmp.DefaultConsumerSaramaConfig("test-simple-consumer-claim", true)
 		require.NoError(t, err)
 
-		factory, err := New("test1", simpleTopic2, []string{broker}, saramaCfg, kafka.Version(sarama.V2_1_0_0.String()),
-			kafka.StartFromNewest())
+		factory, err := New("test1", simpleTopic2, []string{broker}, saramaCfg, kafka.WithVersion(sarama.V2_1_0_0.String()),
+			kafka.WithStartFromNewest())
 		if err != nil {
 			chErr <- err
 			return
@@ -153,8 +153,8 @@ func TestSimpleConsume_WithDurationOffset(t *testing.T) {
 		saramaCfg, err := kafkacmp.DefaultConsumerSaramaConfig("test-simple-consumer-w-duration", true)
 		require.NoError(t, err)
 
-		factory, err := New("test1", simpleTopic3, []string{broker}, saramaCfg, kafka.DecoderJSON(), kafka.Version(sarama.V2_1_0_0.String()),
-			kafka.StartFromNewest(), WithDurationOffset(4*time.Hour, timestampExtractor))
+		factory, err := New("test1", simpleTopic3, []string{broker}, saramaCfg, kafka.WithDecoderJSON(), kafka.WithVersion(sarama.V2_1_0_0.String()),
+			kafka.WithStartFromNewest(), WithDurationOffset(4*time.Hour, timestampExtractor))
 		if err != nil {
 			chErr <- err
 			return
@@ -220,8 +220,8 @@ func TestSimpleConsume_WithTimestampOffset(t *testing.T) {
 		saramaCfg, err := kafkacmp.DefaultConsumerSaramaConfig("test-simple-consumer-w-timestamp", true)
 		require.NoError(t, err)
 
-		factory, err := New("test1", simpleTopic6, []string{broker}, saramaCfg, kafka.DecoderJSON(), kafka.Version(sarama.V2_1_0_0.String()),
-			kafka.StartFromNewest(), WithTimestampOffset(4*time.Hour))
+		factory, err := New("test1", simpleTopic6, []string{broker}, saramaCfg, kafka.WithDecoderJSON(), kafka.WithVersion(sarama.V2_1_0_0.String()),
+			kafka.WithStartFromNewest(), WithTimestampOffset(4*time.Hour))
 		if err != nil {
 			chErr <- err
 			return
@@ -276,8 +276,8 @@ func TestSimpleConsume_WithNotificationOnceReachingLatestOffset(t *testing.T) {
 		saramaCfg, err := kafkacmp.DefaultConsumerSaramaConfig("test-simple-consumer-w-notif", true)
 		require.NoError(t, err)
 
-		factory, err := New("test4", simpleTopic4, []string{broker}, saramaCfg, kafka.DecoderJSON(), kafka.Version(sarama.V2_1_0_0.String()),
-			kafka.StartFromOldest(), WithNotificationOnceReachingLatestOffset(chNotif))
+		factory, err := New("test4", simpleTopic4, []string{broker}, saramaCfg, kafka.WithDecoderJSON(), kafka.WithVersion(sarama.V2_1_0_0.String()),
+			kafka.WithStartFromOldest(), WithNotificationOnceReachingLatestOffset(chNotif))
 		if err != nil {
 			chErr <- err
 			return
@@ -328,8 +328,8 @@ func TestSimpleConsume_WithNotificationOnceReachingLatestOffset_NoMessages(t *te
 		saramaCfg, err := kafkacmp.DefaultConsumerSaramaConfig("test-simple-consumer", true)
 		require.NoError(t, err)
 
-		factory, err := New("test5", simpleTopic5, []string{broker}, saramaCfg, kafka.DecoderJSON(), kafka.Version(sarama.V2_1_0_0.String()),
-			kafka.StartFromOldest(), WithNotificationOnceReachingLatestOffset(chNotif))
+		factory, err := New("test5", simpleTopic5, []string{broker}, saramaCfg, kafka.WithDecoderJSON(), kafka.WithVersion(sarama.V2_1_0_0.String()),
+			kafka.WithStartFromOldest(), WithNotificationOnceReachingLatestOffset(chNotif))
 		if err != nil {
 			chErr <- err
 			return
@@ -393,7 +393,7 @@ func TestSimpleConsume_WithNotificationOnceReachingLatestOffset_WithTimestampOff
 		saramaCfg, err := kafkacmp.DefaultConsumerSaramaConfig("test-simple-consumer", true)
 		require.NoError(t, err)
 
-		factory, err := New("test7", simpleTopic7, []string{broker}, saramaCfg, kafka.DecoderJSON(), kafka.Version(sarama.V2_1_0_0.String()),
+		factory, err := New("test7", simpleTopic7, []string{broker}, saramaCfg, kafka.WithDecoderJSON(), kafka.WithVersion(sarama.V2_1_0_0.String()),
 			WithTimestampOffset(4*time.Hour), WithNotificationOnceReachingLatestOffset(chNotif))
 		if err != nil {
 			chErr <- err
diff --git a/component/async/kafka/simple/simple_test.go b/component/async/kafka/simple/simple_test.go
index 6228bf168..9ee77d727 100644
--- a/component/async/kafka/simple/simple_test.go
+++ b/component/async/kafka/simple/simple_test.go
@@ -98,7 +98,7 @@ func TestFactory_Create(t *testing.T) {
 		wantErr bool
 	}{
 		{name: "success", wantErr: false},
-		{name: "failed with invalid option", fields: fields{oo: []kafka.OptionFunc{kafka.Buffer(-100)}}, wantErr: true},
+		{name: "failed with invalid option", fields: fields{oo: []kafka.OptionFunc{kafka.WithBuffer(-100)}}, wantErr: true},
 	}
 	for _, tt := range tests {
 		t.Run(tt.name, func(t *testing.T) {
diff --git a/component/grpc/component_test.go b/component/grpc/component_test.go
index cac86ac8c..362830ccc 100644
--- a/component/grpc/component_test.go
+++ b/component/grpc/component_test.go
@@ -38,13 +38,15 @@ func TestCreate(t *testing.T) {
 		expErr string
 	}{
 		"success":      {args: args{port: 60000}},
-		"invalid port": {args: args{port: -1}, expErr: "port is invalid: -1\n"},
+		"invalid port": {args: args{port: -1}, expErr: "port is invalid: -1"},
 	}
 	for name, tt := range tests {
 		tt := tt
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
-			got, err := New(tt.args.port).WithOptions(grpc.ConnectionTimeout(1 * time.Second)).WithReflection().Create()
+			got, err := New(tt.args.port,
+				WithServerOptions(grpc.ConnectionTimeout(1*time.Second)),
+				WithReflection())
 			if tt.expErr != "" {
 				assert.EqualError(t, err, tt.expErr)
 				assert.Nil(t, got)
@@ -59,7 +61,7 @@ func TestCreate(t *testing.T) {
 
 func TestComponent_Run_Unary(t *testing.T) {
 	t.Cleanup(func() { mtr.Reset() })
-	cmp, err := New(60000).WithReflection().Create()
+	cmp, err := New(60000, WithReflection())
 	require.NoError(t, err)
 	examples.RegisterGreeterServer(cmp.Server(), &server{})
 	ctx, cnl := context.WithCancel(context.Background())
@@ -124,7 +126,7 @@ func TestComponent_Run_Unary(t *testing.T) {
 
 func TestComponent_Run_Stream(t *testing.T) {
 	t.Cleanup(func() { mtr.Reset() })
-	cmp, err := New(60000).WithReflection().Create()
+	cmp, err := New(60000, WithReflection())
 	require.NoError(t, err)
 	examples.RegisterGreeterServer(cmp.Server(), &server{})
 	ctx, cnl := context.WithCancel(context.Background())
diff --git a/component/grpc/options_test.go b/component/grpc/options_test.go
new file mode 100644
index 000000000..aa69179a5
--- /dev/null
+++ b/component/grpc/options_test.go
@@ -0,0 +1,55 @@
+package grpc
+
+import (
+	"errors"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/assert"
+	"google.golang.org/grpc"
+)
+
+func TestGRPCOptions(t *testing.T) {
+	type args struct {
+		options []grpc.ServerOption
+	}
+	tests := map[string]struct {
+		args          args
+		expectedError error
+	}{
+		"option used with empty arguments": {args: args{}, expectedError: errors.New("no grpc options provided")},
+		"option used with non empty arguments": {args: args{
+			[]grpc.ServerOption{grpc.ConnectionTimeout(1 * time.Second)},
+		}, expectedError: nil},
+	}
+	for name, tt := range tests {
+		t.Run(name, func(t *testing.T) {
+			comp := new(Component)
+			err := WithServerOptions(tt.args.options...)(comp)
+			if tt.expectedError == nil {
+				assert.Equal(t, tt.args.options, comp.serverOptions)
+			} else {
+				assert.Equal(t, err.Error(), tt.expectedError.Error())
+			}
+		})
+	}
+}
+
+func TestReflection(t *testing.T) {
+	tests := map[string]struct {
+		expectedError error
+	}{
+		"option used": {expectedError: nil},
+	}
+	for name, tt := range tests {
+		t.Run(name, func(t *testing.T) {
+			comp := new(Component)
+			err := WithReflection()(comp)
+			if tt.expectedError == nil {
+				assert.Equal(t, true, comp.enableReflection)
+			} else {
+				assert.Equal(t, err.Error(), tt.expectedError.Error())
+			}
+		})
+	}
+}
diff --git a/component/http/v2/component_option_test.go b/component/http/v2/component_option_test.go
index 8c5fc147b..67f9d72c1 100644
--- a/component/http/v2/component_option_test.go
+++ b/component/http/v2/component_option_test.go
@@ -26,7 +26,7 @@ func TestTLS(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			cmp := &Component{}
-			err := TLS(tt.args.cert, tt.args.key)(cmp)
+			err := WithTLS(tt.args.cert, tt.args.key)(cmp)
 
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
@@ -56,7 +56,7 @@ func TestReadTimeout(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			cmp := &Component{}
-			err := ReadTimeout(tt.args.rt)(cmp)
+			err := WithReadTimeout(tt.args.rt)(cmp)
 
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
@@ -85,7 +85,7 @@ func TestWriteTimeout(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			cmp := &Component{}
-			err := WriteTimeout(tt.args.wt)(cmp)
+			err := WithWriteTimeout(tt.args.wt)(cmp)
 
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
@@ -114,7 +114,7 @@ func TestHandlerTimeout(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			cmp := &Component{}
-			err := HandlerTimeout(tt.args.wt)(cmp)
+			err := WithHandlerTimeout(tt.args.wt)(cmp)
 
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
@@ -143,7 +143,7 @@ func TestShutdownGracePeriod(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			cmp := &Component{}
-			err := ShutdownGracePeriod(tt.args.gp)(cmp)
+			err := WithShutdownGracePeriod(tt.args.gp)(cmp)
 
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
@@ -172,7 +172,7 @@ func TestPort(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			cmp := &Component{}
-			err := Port(tt.args.port)(cmp)
+			err := WithPort(tt.args.port)(cmp)
 
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
diff --git a/component/http/v2/component_test.go b/component/http/v2/component_test.go
index 45fe92fcf..ddc76dd62 100644
--- a/component/http/v2/component_test.go
+++ b/component/http/v2/component_test.go
@@ -30,15 +30,15 @@ func TestNew(t *testing.T) {
 	}{
 		"success": {args: args{
 			handler: &stubHandler{},
-			oo:      []OptionFunc{Port(50000)},
+			oo:      []OptionFunc{WithPort(50000)},
 		}},
 		"missing handler": {args: args{
 			handler: nil,
-			oo:      []OptionFunc{Port(50000)},
+			oo:      []OptionFunc{WithPort(50000)},
 		}, expectedErr: "handler is nil"},
 		"option error": {args: args{
 			handler: &stubHandler{},
-			oo:      []OptionFunc{Port(500000)},
+			oo:      []OptionFunc{WithPort(500000)},
 		}, expectedErr: "invalid HTTP Port provided"},
 	}
 	for name, tt := range tests {
@@ -64,7 +64,7 @@ func TestComponent_ListenAndServe_DefaultRoutes_Shutdown(t *testing.T) {
 	assert.True(t, ok)
 	require.NoError(t, listener.Close())
 
-	cmp, err := New(&stubHandler{}, Port(port.Port))
+	cmp, err := New(&stubHandler{}, WithPort(port.Port))
 	assert.NoError(t, err)
 	done := make(chan bool)
 	ctx, cnl := context.WithCancel(context.Background())
diff --git a/component/http/v2/route_option_test.go b/component/http/v2/route_option_test.go
index 95877bb1b..220239386 100644
--- a/component/http/v2/route_option_test.go
+++ b/component/http/v2/route_option_test.go
@@ -27,7 +27,7 @@ func (mo mockAuthenticator) Authenticate(_ *http.Request) (bool, error) {
 func TestRateLimiting(t *testing.T) {
 	t.Parallel()
 	route := &Route{}
-	assert.NoError(t, RateLimiting(0, 0)(route))
+	assert.NoError(t, WithRateLimiting(0, 0)(route))
 }
 
 func TestRouteMiddlewares(t *testing.T) {
@@ -47,7 +47,7 @@ func TestRouteMiddlewares(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			route := &Route{}
-			err := Middlewares(tt.args.mm...)(route)
+			err := WithMiddlewares(tt.args.mm...)(route)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -74,7 +74,7 @@ func TestAuth(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			route := &Route{}
-			err := Auth(tt.args.auth)(route)
+			err := WithAuth(tt.args.auth)(route)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -119,7 +119,7 @@ func TestCache(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			route := &Route{method: tt.fields.httpMethod}
-			err := Cache(tt.args.cache, tt.args.ageBounds)(route)
+			err := WithCache(tt.args.cache, tt.args.ageBounds)(route)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
diff --git a/component/http/v2/route_test.go b/component/http/v2/route_test.go
index d5763a9ef..b5feaad97 100644
--- a/component/http/v2/route_test.go
+++ b/component/http/v2/route_test.go
@@ -28,31 +28,31 @@ func TestNewRoute(t *testing.T) {
 			method:      http.MethodGet,
 			path:        "/api",
 			handler:     handler,
-			optionFuncs: []RouteOptionFunc{RateLimiting(1, 1)},
+			optionFuncs: []RouteOptionFunc{WithRateLimiting(1, 1)},
 		}},
 		"missing method": {args: args{
 			method:      "",
 			path:        "/api",
 			handler:     handler,
-			optionFuncs: []RouteOptionFunc{RateLimiting(1, 1)},
+			optionFuncs: []RouteOptionFunc{WithRateLimiting(1, 1)},
 		}, expectedErr: "method is empty"},
 		"missing path": {args: args{
 			method:      http.MethodGet,
 			path:        "",
 			handler:     handler,
-			optionFuncs: []RouteOptionFunc{RateLimiting(1, 1)},
+			optionFuncs: []RouteOptionFunc{WithRateLimiting(1, 1)},
 		}, expectedErr: "path is empty"},
 		"missing handler": {args: args{
 			method:      http.MethodGet,
 			path:        "/api",
 			handler:     nil,
-			optionFuncs: []RouteOptionFunc{RateLimiting(1, 1)},
+			optionFuncs: []RouteOptionFunc{WithRateLimiting(1, 1)},
 		}, expectedErr: "handler is nil"},
 		"missing middlewares": {args: args{
 			method:      http.MethodGet,
 			path:        "/api",
 			handler:     handler,
-			optionFuncs: []RouteOptionFunc{Middlewares()},
+			optionFuncs: []RouteOptionFunc{WithMiddlewares()},
 		}, expectedErr: "middlewares are empty"},
 	}
 	for name, tt := range tests {
@@ -74,63 +74,63 @@ func TestNewRoute(t *testing.T) {
 
 func TestNewGetRoute(t *testing.T) {
 	route, err := NewGetRoute("/api", func(writer http.ResponseWriter, request *http.Request) {},
-		[]RouteOptionFunc{RateLimiting(1, 1)}...)
+		[]RouteOptionFunc{WithRateLimiting(1, 1)}...)
 	require.NoError(t, err)
 	assertRoute(t, http.MethodGet, "/api", route)
 }
 
 func TestNewHeadRoute(t *testing.T) {
 	route, err := NewHeadRoute("/api", func(writer http.ResponseWriter, request *http.Request) {},
-		[]RouteOptionFunc{RateLimiting(1, 1)}...)
+		[]RouteOptionFunc{WithRateLimiting(1, 1)}...)
 	require.NoError(t, err)
 	assertRoute(t, http.MethodHead, "/api", route)
 }
 
 func TestNewPostRoute(t *testing.T) {
 	route, err := NewPostRoute("/api", func(writer http.ResponseWriter, request *http.Request) {},
-		[]RouteOptionFunc{RateLimiting(1, 1)}...)
+		[]RouteOptionFunc{WithRateLimiting(1, 1)}...)
 	require.NoError(t, err)
 	assertRoute(t, http.MethodPost, "/api", route)
 }
 
 func TestNewPutRoute(t *testing.T) {
 	route, err := NewPutRoute("/api", func(writer http.ResponseWriter, request *http.Request) {},
-		[]RouteOptionFunc{RateLimiting(1, 1)}...)
+		[]RouteOptionFunc{WithRateLimiting(1, 1)}...)
 	require.NoError(t, err)
 	assertRoute(t, http.MethodPut, "/api", route)
 }
 
 func TestNewPatchRoute(t *testing.T) {
 	route, err := NewPatchRoute("/api", func(writer http.ResponseWriter, request *http.Request) {},
-		[]RouteOptionFunc{RateLimiting(1, 1)}...)
+		[]RouteOptionFunc{WithRateLimiting(1, 1)}...)
 	require.NoError(t, err)
 	assertRoute(t, http.MethodPatch, "/api", route)
 }
 
 func TestNewDeleteRoute(t *testing.T) {
 	route, err := NewDeleteRoute("/api", func(writer http.ResponseWriter, request *http.Request) {},
-		[]RouteOptionFunc{RateLimiting(1, 1)}...)
+		[]RouteOptionFunc{WithRateLimiting(1, 1)}...)
 	require.NoError(t, err)
 	assertRoute(t, http.MethodDelete, "/api", route)
 }
 
 func TestNewConnectRoute(t *testing.T) {
 	route, err := NewConnectRoute("/api", func(writer http.ResponseWriter, request *http.Request) {},
-		[]RouteOptionFunc{RateLimiting(1, 1)}...)
+		[]RouteOptionFunc{WithRateLimiting(1, 1)}...)
 	require.NoError(t, err)
 	assertRoute(t, http.MethodConnect, "/api", route)
 }
 
 func TestNewOptionsRoute(t *testing.T) {
 	route, err := NewOptionsRoute("/api", func(writer http.ResponseWriter, request *http.Request) {},
-		[]RouteOptionFunc{RateLimiting(1, 1)}...)
+		[]RouteOptionFunc{WithRateLimiting(1, 1)}...)
 	require.NoError(t, err)
 	assertRoute(t, http.MethodOptions, "/api", route)
 }
 
 func TestNewTraceRoute(t *testing.T) {
 	route, err := NewTraceRoute("/api", func(writer http.ResponseWriter, request *http.Request) {},
-		[]RouteOptionFunc{RateLimiting(1, 1)}...)
+		[]RouteOptionFunc{WithRateLimiting(1, 1)}...)
 	require.NoError(t, err)
 	assertRoute(t, http.MethodTrace, "/api", route)
 }
diff --git a/component/http/v2/router/httprouter/router_option_test.go b/component/http/v2/router/httprouter/router_option_test.go
index 153619c4f..614bcef68 100644
--- a/component/http/v2/router/httprouter/router_option_test.go
+++ b/component/http/v2/router/httprouter/router_option_test.go
@@ -26,7 +26,7 @@ func TestRoutes(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			cfg := &Config{}
-			err := Routes(tt.args.routes...)(cfg)
+			err := WithRoutes(tt.args.routes...)(cfg)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -53,7 +53,7 @@ func TestAliveCheck(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			cfg := &Config{}
-			err := AliveCheck(tt.args.acf)(cfg)
+			err := WithAliveCheck(tt.args.acf)(cfg)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -80,7 +80,7 @@ func TestReadyCheck(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			cfg := &Config{}
-			err := ReadyCheck(tt.args.rcf)(cfg)
+			err := WithReadyCheck(tt.args.rcf)(cfg)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -92,10 +92,33 @@ func TestReadyCheck(t *testing.T) {
 
 func TestDeflateLevel(t *testing.T) {
 	t.Parallel()
-	cfg := &Config{}
-	err := DeflateLevel(10)(cfg)
-	assert.NoError(t, err)
-	assert.Equal(t, 10, cfg.deflateLevel)
+	type args struct {
+		deflateLevel int
+	}
+
+	tests := map[string]struct {
+		args        args
+		expectedErr string
+	}{
+		"too high deflate level":   {args: args{deflateLevel: 10}, expectedErr: "provided deflate level value not in the [-2, 9] range"},
+		"too low deflate level":    {args: args{deflateLevel: -3}, expectedErr: "provided deflate level value not in the [-2, 9] range"},
+		"acceptable deflate level": {args: args{deflateLevel: 6}},
+	}
+
+	for name, tt := range tests {
+		temp := tt
+		t.Run(name, func(t *testing.T) {
+			t.Parallel()
+			cfg := &Config{}
+			err := WithDeflateLevel(temp.args.deflateLevel)(cfg)
+			if temp.expectedErr != "" {
+				assert.EqualError(t, err, temp.expectedErr)
+				return
+			}
+
+			assert.Equal(t, temp.args.deflateLevel, cfg.deflateLevel)
+		})
+	}
 }
 
 func TestMiddlewares(t *testing.T) {
@@ -115,7 +138,7 @@ func TestMiddlewares(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			cfg := &Config{}
-			err := Middlewares(tt.args.mm...)(cfg)
+			err := WithMiddlewares(tt.args.mm...)(cfg)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -128,7 +151,7 @@ func TestMiddlewares(t *testing.T) {
 func TestDisableProfiling(t *testing.T) {
 	t.Parallel()
 	cfg := &Config{}
-	err := EnableExpVarProfiling()(cfg)
+	err := WithExpVarProfiling()(cfg)
 	assert.NoError(t, err)
 	assert.True(t, cfg.enableProfilingExpVar)
 }
@@ -150,7 +173,7 @@ func TestEnableAppNameHeaders(t *testing.T) {
 		tt := tt
 		t.Run(name, func(t *testing.T) {
 			cfg := &Config{}
-			err := EnableAppNameHeaders(tt.args.name, tt.args.version)(cfg)
+			err := WithAppNameHeaders(tt.args.name, tt.args.version)(cfg)
 
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
diff --git a/component/http/v2/router/httprouter/router_test.go b/component/http/v2/router/httprouter/router_test.go
index ff6c20171..5131589bb 100644
--- a/component/http/v2/router/httprouter/router_test.go
+++ b/component/http/v2/router/httprouter/router_test.go
@@ -23,8 +23,8 @@ func TestNew(t *testing.T) {
 		args        args
 		expectedErr string
 	}{
-		"success":            {args: args{oo: []OptionFunc{Routes(route)}}},
-		"option func failed": {args: args{oo: []OptionFunc{AliveCheck(nil)}}, expectedErr: "alive check function is nil"},
+		"success":            {args: args{oo: []OptionFunc{WithRoutes(route)}}},
+		"option func failed": {args: args{oo: []OptionFunc{WithAliveCheck(nil)}}, expectedErr: "alive check function is nil"},
 	}
 	for name, tt := range tests {
 		tt := tt
@@ -51,7 +51,7 @@ func TestVerifyRouter(t *testing.T) {
 	appVersionHeader := "X-App-Version"
 	appNameHeader := "X-App-Name"
 
-	router, err := New(Routes(route), EnableAppNameHeaders(appName, appVersion))
+	router, err := New(WithRoutes(route), WithAppNameHeaders(appName, appVersion))
 	require.NoError(t, err)
 
 	srv := httptest.NewServer(router)
diff --git a/component/kafka/group/component_test.go b/component/kafka/group/component_test.go
index 0912c4fb9..6a9826810 100644
--- a/component/kafka/group/component_test.go
+++ b/component/kafka/group/component_test.go
@@ -119,12 +119,12 @@ func TestNew(t *testing.T) {
 				tt.args.topics,
 				tt.args.p,
 				tt.args.saramaCfg,
-				FailureStrategy(tt.args.fs),
-				Retries(tt.args.retries),
-				RetryWait(tt.args.retryWait),
-				BatchSize(tt.args.batchSize),
-				BatchTimeout(tt.args.batchTimeout),
-				CommitSync())
+				WithFailureStrategy(tt.args.fs),
+				WithRetries(tt.args.retries),
+				WithRetryWait(tt.args.retryWait),
+				WithBatchSize(tt.args.batchSize),
+				WithBatchTimeout(tt.args.batchTimeout),
+				WithCommitSync())
 			if tt.wantErr {
 				assert.Error(t, err)
 				assert.Nil(t, got)
diff --git a/component/kafka/group/integration_test.go b/component/kafka/group/integration_test.go
index fe5bc4795..03e3d871b 100644
--- a/component/kafka/group/integration_test.go
+++ b/component/kafka/group/integration_test.go
@@ -245,7 +245,7 @@ func TestGroupConsume_CheckTopicFailsDueToNonExistingTopic(t *testing.T) {
 	}
 	invalidTopicName := "invalid-topic-name"
 	_, err := New(invalidTopicName, invalidTopicName+"-group", []string{broker},
-		[]string{invalidTopicName}, processorFunc, sarama.NewConfig(), CheckTopic())
+		[]string{invalidTopicName}, processorFunc, sarama.NewConfig(), WithCheckTopic())
 	require.EqualError(t, err, "topic invalid-topic-name does not exist in broker")
 }
 
@@ -255,7 +255,7 @@ func TestGroupConsume_CheckTopicFailsDueToNonExistingBroker(t *testing.T) {
 		return nil
 	}
 	_, err := New(successTopic2, successTopic2+"-group", []string{"127.0.0.1:9999"},
-		[]string{successTopic2}, processorFunc, sarama.NewConfig(), CheckTopic())
+		[]string{successTopic2}, processorFunc, sarama.NewConfig(), WithCheckTopic())
 	require.NotNil(t, err)
 	require.Contains(t, err.Error(), "failed to create client:")
 }
@@ -267,8 +267,8 @@ func newComponent(t *testing.T, name string, retries uint, batchSize uint, proce
 	require.NoError(t, err)
 
 	cmp, err := New(name, name+"-group", []string{broker}, []string{name}, processorFunc,
-		saramaCfg, FailureStrategy(kafka.ExitStrategy), BatchSize(batchSize), BatchTimeout(100*time.Millisecond),
-		Retries(retries), RetryWait(200*time.Millisecond), CommitSync(), CheckTopic())
+		saramaCfg, WithFailureStrategy(kafka.ExitStrategy), WithBatchSize(batchSize), WithBatchTimeout(100*time.Millisecond),
+		WithRetries(retries), WithRetryWait(200*time.Millisecond), WithCommitSync(), WithCheckTopic())
 	require.NoError(t, err)
 
 	return cmp
diff --git a/component/kafka/group/option_test.go b/component/kafka/group/option_test.go
index 2c342127d..4233644de 100644
--- a/component/kafka/group/option_test.go
+++ b/component/kafka/group/option_test.go
@@ -34,7 +34,7 @@ func TestFailureStrategy(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := FailureStrategy(tt.args.strategy)(c)
+			err := WithFailureStrategy(tt.args.strategy)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -47,7 +47,7 @@ func TestFailureStrategy(t *testing.T) {
 
 func TestRetries(t *testing.T) {
 	c := &Component{}
-	err := Retries(20)(c)
+	err := WithRetries(20)(c)
 	assert.NoError(t, err)
 	assert.Equal(t, c.retries, uint(20))
 }
@@ -74,7 +74,7 @@ func TestRetryWait(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := RetryWait(tt.args.retryWait)(c)
+			err := WithRetryWait(tt.args.retryWait)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -107,7 +107,7 @@ func TestBatchSize(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := BatchSize(tt.args.batchSize)(c)
+			err := WithBatchSize(tt.args.batchSize)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -140,7 +140,7 @@ func TestBatchTimeout(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := BatchTimeout(tt.args.batchTimeout)(c)
+			err := WithBatchTimeout(tt.args.batchTimeout)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -175,7 +175,7 @@ func TestNewSessionCallback(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := NewSessionCallback(tt.args.sessionCallback)(c)
+			err := WithNewSessionCallback(tt.args.sessionCallback)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 				assert.Nil(t, c.sessionCallback)
@@ -189,7 +189,7 @@ func TestNewSessionCallback(t *testing.T) {
 
 func TestBatchMessageDeduplication(t *testing.T) {
 	c := &Component{}
-	err := BatchMessageDeduplication()(c)
+	err := WithBatchMessageDeduplication()(c)
 	assert.NoError(t, err)
 	assert.Equal(t, c.batchMessageDeduplication, true)
 }
diff --git a/component/sqs/component_test.go b/component/sqs/component_test.go
index 185c86d90..cb2991994 100644
--- a/component/sqs/component_test.go
+++ b/component/sqs/component_test.go
@@ -32,7 +32,7 @@ func TestNew(t *testing.T) {
 				queueName: "queueName",
 				sqsAPI:    &stubSQSAPI{},
 				proc:      sp.process,
-				oo:        []OptionFunc{Retries(5)},
+				oo:        []OptionFunc{WithRetries(5)},
 			},
 		},
 		"missing name": {
@@ -41,7 +41,7 @@ func TestNew(t *testing.T) {
 				queueName: "queueName",
 				sqsAPI:    &stubSQSAPI{},
 				proc:      sp.process,
-				oo:        []OptionFunc{Retries(5)},
+				oo:        []OptionFunc{WithRetries(5)},
 			},
 			expectedErr: "component name is empty",
 		},
@@ -51,7 +51,7 @@ func TestNew(t *testing.T) {
 				queueName: "",
 				sqsAPI:    &stubSQSAPI{},
 				proc:      sp.process,
-				oo:        []OptionFunc{Retries(5)},
+				oo:        []OptionFunc{WithRetries(5)},
 			},
 			expectedErr: "queue name is empty",
 		},
@@ -63,7 +63,7 @@ func TestNew(t *testing.T) {
 					getQueueUrlWithContextErr: errors.New("QUEUE URL ERROR"),
 				},
 				proc: sp.process,
-				oo:   []OptionFunc{Retries(5)},
+				oo:   []OptionFunc{WithRetries(5)},
 			},
 			expectedErr: "failed to get queue URL: QUEUE URL ERROR",
 		},
@@ -73,7 +73,7 @@ func TestNew(t *testing.T) {
 				queueName: "queueName",
 				sqsAPI:    nil,
 				proc:      sp.process,
-				oo:        []OptionFunc{Retries(5)},
+				oo:        []OptionFunc{WithRetries(5)},
 			},
 			expectedErr: "SQS API is nil",
 		},
@@ -83,7 +83,7 @@ func TestNew(t *testing.T) {
 				queueName: "queueName",
 				sqsAPI:    &stubSQSAPI{},
 				proc:      nil,
-				oo:        []OptionFunc{Retries(5)},
+				oo:        []OptionFunc{WithRetries(5)},
 			},
 			expectedErr: "process function is nil",
 		},
@@ -93,7 +93,7 @@ func TestNew(t *testing.T) {
 				queueName: "queueName",
 				sqsAPI:    &stubSQSAPI{},
 				proc:      sp.process,
-				oo:        []OptionFunc{RetryWait(-1 * time.Second)},
+				oo:        []OptionFunc{WithRetryWait(-1 * time.Second)},
 			},
 			expectedErr: "retry wait time should be a positive number",
 		},
@@ -103,7 +103,7 @@ func TestNew(t *testing.T) {
 				queueName: "queueName",
 				sqsAPI:    &stubSQSAPI{},
 				proc:      sp.process,
-				oo:        []OptionFunc{QueueOwner("10201020")},
+				oo:        []OptionFunc{WithQueueOwner("10201020")},
 			},
 		},
 		"queue owner fails": {
@@ -112,7 +112,7 @@ func TestNew(t *testing.T) {
 				queueName: "queueName",
 				sqsAPI:    &stubSQSAPI{},
 				proc:      sp.process,
-				oo:        []OptionFunc{QueueOwner("")},
+				oo:        []OptionFunc{WithQueueOwner("")},
 			},
 			expectedErr: "queue owner should not be empty",
 		},
@@ -142,7 +142,7 @@ func TestComponent_Run_Success(t *testing.T) {
 		succeededMessage: createMessage(nil, "1"),
 		failedMessage:    createMessage(nil, "2"),
 	}
-	cmp, err := New("name", queueName, sqsAPI, sp.process, QueueStatsInterval(10*time.Millisecond))
+	cmp, err := New("name", queueName, sqsAPI, sp.process, WithQueueStatsInterval(10*time.Millisecond))
 	require.NoError(t, err)
 	ctx, cnl := context.WithCancel(context.Background())
 	wg := sync.WaitGroup{}
@@ -168,7 +168,7 @@ func TestComponent_RunEvenIfStatsFail_Success(t *testing.T) {
 		failedMessage:                    createMessage(nil, "2"),
 		getQueueAttributesWithContextErr: errors.New("STATS FAIL"),
 	}
-	cmp, err := New("name", queueName, sqsAPI, sp.process, QueueStatsInterval(10*time.Millisecond))
+	cmp, err := New("name", queueName, sqsAPI, sp.process, WithQueueStatsInterval(10*time.Millisecond))
 	require.NoError(t, err)
 	ctx, cnl := context.WithCancel(context.Background())
 	wg := sync.WaitGroup{}
@@ -194,7 +194,7 @@ func TestComponent_Run_Error(t *testing.T) {
 		succeededMessage:             createMessage(nil, "1"),
 		failedMessage:                createMessage(nil, "2"),
 	}
-	cmp, err := New("name", queueName, sqsAPI, sp.process, Retries(2), RetryWait(10*time.Millisecond))
+	cmp, err := New("name", queueName, sqsAPI, sp.process, WithRetries(2), WithRetryWait(10*time.Millisecond))
 	require.NoError(t, err)
 	ctx, cnl := context.WithCancel(context.Background())
 	wg := sync.WaitGroup{}
diff --git a/component/sqs/integration_test.go b/component/sqs/integration_test.go
index 3d194b823..16b24e7eb 100644
--- a/component/sqs/integration_test.go
+++ b/component/sqs/integration_test.go
@@ -65,8 +65,8 @@ func Test_SQS_Consume(t *testing.T) {
 		}
 	}
 
-	cmp, err := New("123", queueName, api, procFunc, MaxMessages(10),
-		PollWaitSeconds(20), VisibilityTimeout(30), QueueStatsInterval(10*time.Millisecond))
+	cmp, err := New("123", queueName, api, procFunc, WithMaxMessages(10),
+		WithPollWaitSeconds(20), WithVisibilityTimeout(30), WithQueueStatsInterval(10*time.Millisecond))
 	require.NoError(t, err)
 
 	go func() { require.NoError(t, cmp.Run(context.Background())) }()
diff --git a/component/sqs/option_test.go b/component/sqs/option_test.go
index 3e32efcf4..dc1d7e621 100644
--- a/component/sqs/option_test.go
+++ b/component/sqs/option_test.go
@@ -33,7 +33,7 @@ func TestMaxMessages(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := MaxMessages(tt.args.maxMessages)(c)
+			err := WithMaxMessages(tt.args.maxMessages)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -70,7 +70,7 @@ func TestPollWaitSeconds(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := PollWaitSeconds(tt.args.waitSeconds)(c)
+			err := WithPollWaitSeconds(tt.args.waitSeconds)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -107,7 +107,7 @@ func TestVisibilityTimeout(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := VisibilityTimeout(tt.args.timeout)(c)
+			err := WithVisibilityTimeout(tt.args.timeout)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -140,7 +140,7 @@ func TestQueueStatsInterval(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := QueueStatsInterval(tt.args.interval)(c)
+			err := WithQueueStatsInterval(tt.args.interval)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -153,7 +153,7 @@ func TestQueueStatsInterval(t *testing.T) {
 
 func TestRetries(t *testing.T) {
 	c := &Component{}
-	err := Retries(20)(c)
+	err := WithRetries(20)(c)
 	assert.NoError(t, err)
 	assert.Equal(t, c.retry.count, uint(20))
 }
@@ -180,7 +180,7 @@ func TestRetryWait(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := RetryWait(tt.args.retryWait)(c)
+			err := WithRetryWait(tt.args.retryWait)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
@@ -213,7 +213,7 @@ func TestQueueOwner(t *testing.T) {
 		t.Run(name, func(t *testing.T) {
 			t.Parallel()
 			c := &Component{}
-			err := QueueOwner(tt.args.queueOwner)(c)
+			err := WithQueueOwner(tt.args.queueOwner)(c)
 			if tt.expectedErr != "" {
 				assert.EqualError(t, err, tt.expectedErr)
 			} else {
diff --git a/options_test.go b/options_test.go
new file mode 100644
index 000000000..8053d174e
--- /dev/null
+++ b/options_test.go
@@ -0,0 +1,159 @@
+package patron
+
+import (
+	"errors"
+	"net/http"
+	"os"
+	"testing"
+
+	"github.com/beatlabs/patron/log/std"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestComponents(t *testing.T) {
+	comp := &testComponent{}
+
+	type args struct {
+		cc []Component
+	}
+	tests := map[string]struct {
+		args           args
+		wantComponents []Component
+		wantError      error
+	}{
+		"no components provided": {args: args{cc: nil}, wantComponents: nil, wantError: errors.New("provided components slice was empty")},
+		"components provided":    {args: args{cc: []Component{comp}}, wantComponents: []Component{comp}, wantError: nil},
+	}
+	for name, tt := range tests {
+		temp := tt
+		t.Run(name, func(t *testing.T) {
+			svc := &Service{}
+			err := WithComponents(temp.args.cc...)(svc)
+			assert.Equal(t, temp.wantError, err)
+			assert.Equal(t, temp.wantComponents, svc.cps)
+		})
+	}
+}
+
+func TestLogFields(t *testing.T) {
+	defaultFields := defaultLogFields("test", "1.0")
+	fields := map[string]interface{}{"key": "value"}
+	fields1 := defaultLogFields("name1", "version1")
+	type args struct {
+		fields map[string]interface{}
+	}
+	tests := map[string]struct {
+		args args
+		want config
+	}{
+		"success":      {args: args{fields: fields}, want: config{fields: mergeFields(defaultFields, fields)}},
+		"no overwrite": {args: args{fields: fields1}, want: config{fields: defaultFields}},
+	}
+	for name, tt := range tests {
+		temp := tt
+		t.Run(name, func(t *testing.T) {
+			svc := &Service{
+				config: config{
+					fields: defaultFields,
+				},
+			}
+
+			err := WithLogFields(temp.args.fields)(svc)
+			assert.NoError(t, err)
+
+			assert.Equal(t, temp.want, svc.config)
+		})
+	}
+}
+
+func mergeFields(ff1, ff2 map[string]interface{}) map[string]interface{} {
+	ff := map[string]interface{}{}
+	for k, v := range ff1 {
+		ff[k] = v
+	}
+	for k, v := range ff2 {
+		ff[k] = v
+	}
+	return ff
+}
+
+func TestLogger(t *testing.T) {
+	logger := std.New(os.Stderr, getLogLevel(), nil)
+	svc := &Service{}
+
+	err := WithLogger(logger)(svc)
+	assert.NoError(t, err)
+	assert.Equal(t, logger, svc.config.logger)
+}
+
+func TestRouter(t *testing.T) {
+	type args struct {
+		handler http.Handler
+	}
+
+	tests := map[string]struct {
+		args        args
+		wantHandler http.Handler
+		wantError   error
+	}{
+		"empty value for handler":     {args: args{handler: nil}, wantHandler: nil, wantError: errors.New("provided router is nil")},
+		"non empty value for handler": {args: args{handler: noopHTTPHandler{}}, wantHandler: noopHTTPHandler{}, wantError: nil},
+	}
+
+	for name, tt := range tests {
+		t.Run(name, func(t *testing.T) {
+			temp := tt
+			svc := &Service{}
+
+			err := WithRouter(temp.args.handler)(svc)
+			assert.Equal(t, temp.wantError, err)
+			assert.Equal(t, temp.wantHandler, svc.httpRouter)
+		})
+	}
+}
+
+type noopHTTPHandler struct{}
+
+func (noopHTTPHandler) ServeHTTP(writer http.ResponseWriter, request *http.Request) {
+	return
+}
+
+func TestSIGHUP(t *testing.T) {
+	t.Parallel()
+
+	type args struct {
+		handler func()
+	}
+
+	t.Run("empty value for sighup handler", func(t *testing.T) {
+		t.Parallel()
+		svc := &Service{}
+
+		err := WithSIGHUP(nil)(svc)
+		assert.Equal(t, errors.New("provided WithSIGHUP handler was nil"), err)
+		assert.Nil(t, nil, svc.sighupHandler)
+	})
+
+	t.Run("non empty value for sighup handler", func(t *testing.T) {
+		t.Parallel()
+
+		svc := &Service{}
+		comp := &testSighupAlterable{}
+
+		err := WithSIGHUP(testSighupHandle(comp))(svc)
+		assert.Equal(t, nil, err)
+		assert.NotNil(t, svc.sighupHandler)
+		svc.sighupHandler()
+		assert.Equal(t, 1, comp.value)
+	})
+}
+
+type testSighupAlterable struct {
+	value int
+}
+
+func testSighupHandle(value *testSighupAlterable) func() {
+	return func() {
+		value.value = 1
+	}
+}
diff --git a/service_test.go b/service_test.go
index b107211af..f40334727 100644
--- a/service_test.go
+++ b/service_test.go
@@ -10,41 +10,25 @@ import (
 	"strconv"
 	"testing"
 
-	patronhttp "github.com/beatlabs/patron/component/http"
-	"github.com/beatlabs/patron/component/http/middleware"
 	"github.com/beatlabs/patron/log"
-	"github.com/beatlabs/patron/log/std"
 	"github.com/stretchr/testify/assert"
 	"github.com/stretchr/testify/require"
 )
 
 func TestNewServer(t *testing.T) {
-	t.Parallel()
-	routesBuilder := patronhttp.NewRoutesBuilder().
-		Append(patronhttp.NewRawRouteBuilder("/", func(w http.ResponseWriter, r *http.Request) {}).MethodGet())
-
 	mw := func(h http.Handler) http.Handler {
 		return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
 			h.ServeHTTP(w, r)
 		})
 	}
 
-	httpBuilderAllErrors := "routes builder is nil\n" +
-		"provided middlewares slice was empty\n" +
-		"alive check func provided was nil\n" +
-		"ready check func provided was nil\n" +
-		"provided components slice was empty\n" +
-		"provided SIGHUP handler was nil\n" +
-		"provided uncompressed paths slice was empty\n" +
+	httpBuilderAllErrors := "provided components slice was empty\n" +
+		"provided WithSIGHUP handler was nil\n" +
 		"provided router is nil\n"
 
 	tests := map[string]struct {
 		fields            map[string]interface{}
 		cps               []Component
-		routesBuilder     *patronhttp.RoutesBuilder
-		middlewares       []middleware.Func
-		acf               patronhttp.AliveCheckFunc
-		rcf               patronhttp.ReadyCheckFunc
 		sighupHandler     func()
 		uncompressedPaths []string
 		handler           http.Handler
@@ -53,21 +37,13 @@ func TestNewServer(t *testing.T) {
 		"success": {
 			fields:            map[string]interface{}{"env": "dev"},
 			cps:               []Component{&testComponent{}, &testComponent{}},
-			routesBuilder:     routesBuilder,
-			middlewares:       []middleware.Func{mw},
-			acf:               patronhttp.DefaultAliveCheck,
-			rcf:               patronhttp.DefaultReadyCheck,
-			sighupHandler:     func() { log.Info("SIGHUP received: nothing setup") },
+			sighupHandler:     func() { log.Info("WithSIGHUP received: nothing setup") },
 			uncompressedPaths: []string{"/foo", "/bar"},
 			handler:           mw(nil),
 			wantErr:           "",
 		},
 		"nil inputs steps": {
 			cps:               nil,
-			routesBuilder:     nil,
-			middlewares:       nil,
-			acf:               nil,
-			rcf:               nil,
 			sighupHandler:     nil,
 			uncompressedPaths: nil,
 			handler:           nil,
@@ -75,10 +51,6 @@ func TestNewServer(t *testing.T) {
 		},
 		"error in all builder steps": {
 			cps:               []Component{},
-			routesBuilder:     nil,
-			middlewares:       []middleware.Func{},
-			acf:               nil,
-			rcf:               nil,
 			sighupHandler:     nil,
 			uncompressedPaths: []string{},
 			handler:           nil,
@@ -87,45 +59,26 @@ func TestNewServer(t *testing.T) {
 	}
 
 	for name, tt := range tests {
-		tt := tt
+		temp := tt
 		t.Run(name, func(t *testing.T) {
-			t.Parallel()
-			svc, err := New("name", "1.0", LogFields(tt.fields), TextLogger())
-			require.NoError(t, err)
-			gotService, gotErr := svc.
-				WithRoutesBuilder(tt.routesBuilder).
-				WithMiddlewares(tt.middlewares...).
-				WithAliveCheck(tt.acf).
-				WithReadyCheck(tt.rcf).
-				WithComponents(tt.cps...).
-				WithSIGHUP(tt.sighupHandler).
-				WithUncompressedPaths(tt.uncompressedPaths...).
-				WithRouter(tt.handler).
-				build()
-
-			if tt.wantErr != "" {
-				assert.EqualError(t, gotErr, tt.wantErr)
+			gotService, gotErr := New("name", "1.0", WithLogFields(temp.fields), WithTextLogger(),
+				WithComponents(temp.cps...), WithSIGHUP(temp.sighupHandler), WithRouter(temp.handler))
+
+			if temp.wantErr != "" {
+				assert.EqualError(t, gotErr, temp.wantErr)
 				assert.Nil(t, gotService)
 			} else {
 				assert.Nil(t, gotErr)
 				assert.NotNil(t, gotService)
-				assert.IsType(t, &service{}, gotService)
+				assert.IsType(t, &Service{}, gotService)
 
 				assert.NotEmpty(t, gotService.cps)
-				assert.NotNil(t, gotService.routesBuilder)
-				assert.Len(t, gotService.middlewares, len(tt.middlewares))
-				assert.NotNil(t, gotService.rcf)
-				assert.NotNil(t, gotService.acf)
 				assert.NotNil(t, gotService.termSig)
 				assert.NotNil(t, gotService.sighupHandler)
 
-				for _, comp := range tt.cps {
+				for _, comp := range temp.cps {
 					assert.Contains(t, gotService.cps, comp)
 				}
-
-				for _, mw := range tt.middlewares {
-					assert.NotNil(t, mw)
-				}
 			}
 		})
 	}
@@ -140,15 +93,15 @@ func TestServer_Run_Shutdown(t *testing.T) {
 		"failed to run": {cp: &testComponent{errorRunning: true}, wantErr: true},
 	}
 	for name, tt := range tests {
-		tt := tt
+		temp := tt
 		t.Run(name, func(t *testing.T) {
 			defer os.Clearenv()
 			err := os.Setenv("PATRON_HTTP_DEFAULT_PORT", getRandomPort(t))
 			require.NoError(t, err)
-			svc, err := New("test", "", TextLogger())
-			require.NoError(t, err)
-			err = svc.WithComponents(tt.cp, tt.cp, tt.cp).Run(context.Background())
-			if tt.wantErr {
+			svc, err := New("test", "", WithTextLogger(), WithComponents(temp.cp, temp.cp, temp.cp))
+			assert.NoError(t, err)
+			err = svc.Run(context.Background())
+			if temp.wantErr {
 				assert.Error(t, err)
 			} else {
 				assert.NoError(t, err)
@@ -172,90 +125,89 @@ func TestServer_SetupTracing(t *testing.T) {
 		{name: "success w/ custom default buckets", cp: &testComponent{}, host: "127.0.0.1", port: "6831", buckets: ".1, .3"},
 	}
 	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
+		temp := tt
+		t.Run(temp.name, func(t *testing.T) {
 			defer os.Clearenv()
 
-			if tt.host != "" {
-				err := os.Setenv("PATRON_JAEGER_AGENT_HOST", tt.host)
+			if temp.host != "" {
+				err := os.Setenv("PATRON_JAEGER_AGENT_HOST", temp.host)
 				assert.NoError(t, err)
 			}
-			if tt.port != "" {
-				err := os.Setenv("PATRON_JAEGER_AGENT_PORT", tt.port)
+			if temp.port != "" {
+				err := os.Setenv("PATRON_JAEGER_AGENT_PORT", temp.port)
 				assert.NoError(t, err)
 			}
-			if tt.buckets != "" {
-				err := os.Setenv("PATRON_JAEGER_DEFAULT_BUCKETS", tt.buckets)
+			if temp.buckets != "" {
+				err := os.Setenv("PATRON_JAEGER_DEFAULT_BUCKETS", temp.buckets)
 				assert.NoError(t, err)
 			}
-			svc, err := New("test", "", TextLogger())
-			require.NoError(t, err)
-			s, err := svc.WithComponents(tt.cp, tt.cp, tt.cp).build()
+
+			svc, err := New("test", "", WithTextLogger(), WithComponents(tt.cp, tt.cp, tt.cp))
 			assert.NoError(t, err)
-			err = s.run(context.Background())
+
+			err = svc.Run(context.Background())
 			assert.NoError(t, err)
 		})
 	}
 }
 
-func TestBuilder_WithComponentsTwice(t *testing.T) {
-	svc, err := New("test", "", TextLogger())
+func TestNewServer_WithComponentsTwice(t *testing.T) {
+	svc, err := New("test", "", WithTextLogger(), WithComponents(&testComponent{}, &testComponent{}))
 	require.NoError(t, err)
-	bld := svc.WithComponents(&testComponent{}).WithComponents(&testComponent{})
-	assert.Len(t, bld.cps, 2)
+	assert.Len(t, svc.cps, 3)
 }
 
-func TestBuild_FailingConditions(t *testing.T) {
+func TestNewServer_FailingConditions(t *testing.T) {
 	tests := map[string]struct {
-		jaegerSamplerParam string
-		port               string
-		jaegerBuckets      string
-		expectedBuildErr   string
-		expectedRunErr     string
+		jaegerSamplerParam       string
+		port                     string
+		jaegerBuckets            string
+		expectedConstructorError string
 	}{
-		"failure with wrong w/ port":             {port: "foo", expectedRunErr: "env var for HTTP default port is not valid: strconv.ParseInt: parsing \"foo\": invalid syntax"},
-		"success with wrong w/ overflowing port": {port: "153000", expectedRunErr: "failed to create default HTTP component: invalid HTTP Port provided\n"},
-		"failure w/ sampler param":               {jaegerSamplerParam: "foo", expectedRunErr: "env var for jaeger sampler param is not valid: strconv.ParseFloat: parsing \"foo\": invalid syntax"},
-		"failure w/ overflowing sampler param":   {jaegerSamplerParam: "8", expectedRunErr: "cannot initialize jaeger tracer: invalid Param for probabilistic sampler; expecting value between 0 and 1, received 8"},
-		"failure w/ custom default buckets":      {jaegerSamplerParam: "1", jaegerBuckets: "foo", expectedRunErr: "env var for jaeger default buckets contains invalid value: strconv.ParseFloat: parsing \"foo\": invalid syntax"},
+		"failure with wrong w/ port":             {port: "foo", expectedConstructorError: "env var for HTTP default port is not valid: strconv.ParseInt: parsing \"foo\": invalid syntax"},
+		"success with wrong w/ overflowing port": {port: "153000", expectedConstructorError: "invalid HTTP Port provided"},
+		"failure w/ sampler param":               {jaegerSamplerParam: "foo", expectedConstructorError: "env var for jaeger sampler param is not valid: strconv.ParseFloat: parsing \"foo\": invalid syntax"},
+		"failure w/ overflowing sampler param":   {jaegerSamplerParam: "8", expectedConstructorError: "cannot initialize jaeger tracer: invalid Param for probabilistic sampler; expecting value between 0 and 1, received 8"},
+		"failure w/ custom default buckets":      {jaegerSamplerParam: "1", jaegerBuckets: "foo", expectedConstructorError: "env var for jaeger default buckets contains invalid value: strconv.ParseFloat: parsing \"foo\": invalid syntax"},
 	}
 
 	for name, tt := range tests {
-		tt := tt
+		temp := tt
 		t.Run(name, func(t *testing.T) {
 			defer os.Clearenv()
 
-			if tt.port != "" {
-				err := os.Setenv("PATRON_HTTP_DEFAULT_PORT", tt.port)
+			if temp.port != "" {
+				err := os.Setenv("PATRON_HTTP_DEFAULT_PORT", temp.port)
 				require.NoError(t, err)
 			}
-			if tt.jaegerSamplerParam != "" {
-				err := os.Setenv("PATRON_JAEGER_SAMPLER_PARAM", tt.jaegerSamplerParam)
+			if temp.jaegerSamplerParam != "" {
+				err := os.Setenv("PATRON_JAEGER_SAMPLER_PARAM", temp.jaegerSamplerParam)
 				require.NoError(t, err)
 			}
-			if tt.jaegerBuckets != "" {
-				err := os.Setenv("PATRON_JAEGER_DEFAULT_BUCKETS", tt.jaegerBuckets)
+			if temp.jaegerBuckets != "" {
+				err := os.Setenv("PATRON_JAEGER_DEFAULT_BUCKETS", temp.jaegerBuckets)
 				require.NoError(t, err)
 			}
 
-			svc, err := New("test", "", TextLogger())
-			if tt.expectedBuildErr != "" {
-				require.EqualError(t, err, tt.expectedBuildErr)
+			svc, err := New("test", "", WithTextLogger())
+
+			if temp.expectedConstructorError != "" {
+				require.EqualError(t, err, temp.expectedConstructorError)
 				require.Nil(t, svc)
-			} else {
-				require.NoError(t, err)
-				require.NotNil(t, svc)
+
+				return
 			}
 
+			require.NoError(t, err)
+			require.NotNil(t, svc)
+
 			// start running with a canceled context, on purpose
 			ctx, cancel := context.WithCancel(context.Background())
 			cancel()
 			err = svc.Run(ctx)
+			require.NoError(t, err)
 
-			if tt.expectedRunErr != "" {
-				require.EqualError(t, err, tt.expectedRunErr)
-			} else {
-				require.Equal(t, err, context.Canceled)
-			}
+			require.Equal(t, err, context.Canceled)
 		})
 	}
 }
@@ -277,22 +229,21 @@ func TestServer_SetupReadWriteTimeouts(t *testing.T) {
 		{name: "failed w/ zero read timeout", cp: &testComponent{}, ctx: context.Background(), rt: "0s", wantErr: true},
 	}
 	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
+		temp := tt
+		t.Run(temp.name, func(t *testing.T) {
 			defer os.Clearenv()
 
-			if tt.rt != "" {
-				err := os.Setenv("PATRON_HTTP_READ_TIMEOUT", tt.rt)
+			if temp.rt != "" {
+				err := os.Setenv("PATRON_HTTP_READ_TIMEOUT", temp.rt)
 				assert.NoError(t, err)
 			}
-			if tt.wt != "" {
-				err := os.Setenv("PATRON_HTTP_WRITE_TIMEOUT", tt.wt)
+			if temp.wt != "" {
+				err := os.Setenv("PATRON_HTTP_WRITE_TIMEOUT", temp.wt)
 				assert.NoError(t, err)
 			}
-			svc, err := New("test", "", TextLogger())
-			require.NoError(t, err)
+			_, err := New("test", "", WithTextLogger(), WithComponents(temp.cp, temp.cp, temp.cp))
 
-			_, err = svc.WithComponents(tt.cp, tt.cp, tt.cp).build()
-			if tt.wantErr {
+			if temp.wantErr {
 				assert.Error(t, err)
 			} else {
 				assert.NoError(t, err)
@@ -319,17 +270,17 @@ func TestServer_SetupDeflateLevel(t *testing.T) {
 		{name: "failed with invalid compression deflate level", component: &testComponent{}, ctx: context.Background(), level: "blah", wantErr: true},
 	}
 	for _, tt := range tests {
+		temp := tt
 		t.Run(tt.name, func(t *testing.T) {
 			defer os.Clearenv()
 
-			if tt.level != "" {
-				err := os.Setenv("PATRON_COMPRESSION_DEFLATE_LEVEL", tt.level)
+			if temp.level != "" {
+				err := os.Setenv("PATRON_COMPRESSION_DEFLATE_LEVEL", temp.level)
 				assert.NoError(t, err)
 			}
-			svc, err := New("test", "", TextLogger())
-			require.NoError(t, err)
 
-			_, err = svc.WithComponents(tt.component, tt.component, tt.component).build()
+			_, err := New("test", "", WithTextLogger(), WithComponents(temp.component, temp.component, temp.component))
+
 			if tt.wantErr {
 				assert.Error(t, err)
 			} else {
@@ -355,45 +306,3 @@ func (ts testComponent) Run(_ context.Context) error {
 	}
 	return nil
 }
-
-func TestLogFields(t *testing.T) {
-	defaultFields := defaultLogFields("test", "1.0")
-	fields := map[string]interface{}{"key": "value"}
-	fields1 := defaultLogFields("name1", "version1")
-	type args struct {
-		fields map[string]interface{}
-	}
-	tests := map[string]struct {
-		args args
-		want Config
-	}{
-		"success":      {args: args{fields: fields}, want: Config{fields: mergeFields(defaultFields, fields)}},
-		"no overwrite": {args: args{fields: fields1}, want: Config{fields: defaultFields}},
-	}
-	for name, tt := range tests {
-		tt := tt
-		t.Run(name, func(t *testing.T) {
-			cfg := Config{fields: defaultFields}
-			LogFields(tt.args.fields)(&cfg)
-			assert.Equal(t, tt.want, cfg)
-		})
-	}
-}
-
-func mergeFields(ff1, ff2 map[string]interface{}) map[string]interface{} {
-	ff := map[string]interface{}{}
-	for k, v := range ff1 {
-		ff[k] = v
-	}
-	for k, v := range ff2 {
-		ff[k] = v
-	}
-	return ff
-}
-
-func TestLogger(t *testing.T) {
-	logger := std.New(os.Stderr, getLogLevel(), nil)
-	cfg := Config{}
-	Logger(logger)(&cfg)
-	assert.Equal(t, logger, cfg.logger)
-}