Application Programming Interface
A service endpoint that another program can call to query for data, or have some piece of work done.
Metaphor
"If one component of a system fails, but that failure doesn't cascade, you can isolate the problem and the rest of the system can carry on working."
A bulkhead in a ship separates the ship into multiple water-tight segments (among other purposes). If one part of the ship leaks, only part of the ship will be flooded.
Having "bulkheads" in a software system increases the resiliency of the system.
Platform as a Service (PaaS)
Application Platform as a Service (aPaaS)
Platform-based Service
A category of cloud computing services that provides a platform allowing customers to develop, run, and manage applications without the complexity of building and maintaining the infrastructure typically associated with developing and launching an app.
aka Ports and Adapters Pattern
See Clean Architecture for details about implementing this design.
Allow an application to equally be driven by users, programs, automated tests, or batch scripts.
And to be developed and tested in isolation from its eventual run-time devices and databases.
Explicitly separate Application, Domain, and Infrastructure.
- Application: the front-end, what the end users interacts with (aka User Side)
- Domain: business logic
- Infrastructure: non-domain things the software depends on, such as database, file system, logging, email (aka Server Side)
Dependencies point only from Application and Infrastructure into the Domain.
Boundaries are isolated by using ports and adapters.
Separation of concerns.
Making the Domain (business logic) the most important and stable part of the system.
Enable isolated testing.
The Domain has no dependencies on anything else in the system.
The Domain defines at least two interfaces: one for the Application to implement and one for the Infrastructure to implement.
The Application and Infrastructure implement the interfaces they need, which gives the Domain control of those parts of the system without the Domain having a code dependency on them.
Ex:
Domain.IManageCustomers defines FindCustomer(Id) method
Domain.ManageCustomers implements IManageCustomer; this class is private
Domain.ICustomerRepository defines FindCustomer(Id) method
Infrastructure.SqlCustomerRepository implements Domain.ICustomerRepository which actually accesses the database
Application.ConsoleAdapter instantiates Infrastructure.SqlCustomerRepository
Application.ConsoleAdapter instantiates Domain.ManageCustomers(ICustomerRepository) and passes it Infrastructure.SqlCustomerRepository
Application.ConsoleAdapter calls Domain.ManageCustomers.FindCustomer(Id) which causes Domain.ManageCustomer to use its Domain.ICustomerRepository which is actually Infrastructure.SqlCustomerRepository
The Application drives the Domain through an Interface defined in the Domain.
The Domain drives the Infrastructure through an Interface defined in the Domain.
The Interfaces are Explicit Insulators between different parts of the system.
See Dependency Inversion.
In this metaphor, each Interface is a Port.
Each implementation of an Interfaces is an Adapter.
All kinds of Adapters can be interchanged and connected to the Ports.
Imagine a hexagon with the Domain in the center.
There are three sides on the left where different Applications can connect to the Domain (website, console, 3rd party API, etc).
There are three sides on the right where different Infrastructures can connection to the Domain (SQL Server, MongoDb, file system, etc).
This is one way to visualize the benefits of this pattern.
Recommended that you organize your code files by business function rather than by programming category.
Ex: folders for RequestQuote and BindPolicy rather than for Repositories and Controllers.
Robert Martin's "Clean Architecture" speaks in depth about dependecy inversion.
Ex:
Instead of a RestEntryPoint having a reference to Mediator,
The RestEntryPoint will provide an interface defining all the operations it will need
Then Mediator implements the RestEntryPoint interface
Thus the Mediator has a code reference to RestEntryPoint instead of the the other way around
In C#, a class should be able to implement any number of interfaces, and the users of the interface should not care what else you are implementing.
But with C#'s dependency injection library, the users of the concrete class are bound to provide any dependencies that the class requires. Now the class cannot implement just any interface. It has to be aware of what resources each user can provide.
My mistake was putting the dependencies of different interfaces into one concrete constructor - of course that tied the users of the interfaces to dependencies they did not expect. If you must have one class implementing all these interfaces, then the dependencies should be passed in as method arguments. That means (with C#'s dependency injection model) that the users of the interface will list the dependencies in their own constructor.
Or, divide interface implementation up by use-case, so that all the interface methods use the same dependencies.
[Stackoverflow workaround]
You can have the constructor accept 0 or more candidates for a dependency
services.AddTransient<IWarehouseRepo, ActionRepository>();
services.AddTransient<IWarehouseRepo, EventRepository>();
services.AddTransient<IWarehouseRepo, AuditRepository>();
...
public WarehouseHandler(IEnumerable<IWarehouseRepo> repos)
The key here being, 0 is acceptable. Theoretically, this means you can have an optional dependency in the constructor.
Note: This did not work for me. Possibly due to company-set infrastructure constraints?