The More General Part of the Answer
I'm going to answer the question you stated in your closing line, but there's a caveat - see below.
Is this okay? Considering the Interface-Adapter and Gateway are using
something outside of their boundary.
The interface adapters and gateways are supposed to use/reference something from an inner layer. They can, of course, use things from their own layer, but to actually do anything useful, they have to cross the layer boundary at some point. If you're following the dependency rule, the dependencies should only go towards the inner layers (and, in the more strict approach, only towards the next layer in). To achieve this, you either use a thing from an inner layer (to tell it to do something), or you implement an interface from an inner layer (so that that inner-layer code can call a thing in the outer layer, without depending on any types defined there).
This image sort of summarizes Clean Architecture.
Look closely at the inset:
The presenter (an interface adapter) implements an interface defined in the application business rules layer (the next layer in). This is precisely what enables dependency inversion. The interface (the "output port") is defined for the purposes of the interactor (the methods on the interface are designed to serve the needs of the specific interactor; it's not designed as some generic abstraction of a presenter). It's the interactor that "owns" the interface. The presenter then forms a bridge between the interface required by the interactor, and the interface(s) exposed by the GUI library you're using - in other words, it adapts one interface to work with a different one.
Similarly, the controller just makes use of a type defined in the application business rules layer. You can think of it as adapting the interfaces in the other direction - it translates from whatever general-purpose API the frameworks you're using have, to the interface that's more application-specific, expressed in terms that make more sense for the design of the interactor.
Now, this is just an example; you don't have to have this exact structure - the number and kinds of elements in each layer could vary (maybe you merge or split some objects that are in the same layer, maybe you have an abstract base class instead of an interface, etc.). What matters is the general principle - for classes that need to interact across the layer boundary, be conscious of which layer is the more higher level one, which objects should define/own types (not just interfaces, but also things like methods parameters, etc.), and control the direction of your dependencies.
This same basic idea repeats across every layer boundary. That doesn't mean you should have a large, elaborate web of interfaces and classes - keep it as simple as possible. It also doesn't mean that the exact same elements should appear in every layer. So, don't automatically apply this as a generic pattern to every class you create - this is meant for the classes that are at layer boundaries; internally, you could factor your code as you see fit. E.g. maybe your interactor manipulates the entities directly, or maybe it orchestrates two or three other, intermediary classes, that manipulate entities in turn - that's for you to figure out (maybe over project lifetime), as you wrestle with your problem domain, and with the inflow of new feature and change requests.
The Caveat
struct HostEnvironment {
...
}
struct StripeEnvironment {
...
}
These classes should be Entities, right? Because they are the business
rules that will be the same across the enterprise among different apps.
Actually, these don't really look like business rules to me (as the other answer mentioned, they are more like config that belongs in the infrastructure layer). You could maybe argue that one of them (StripeEnvironment
) is an entity in an anemic domain model, but even then, it doesn't actually express/encapsulate any business rules. Some data on its own does not business rule make (I hope that didn't sound condescending, I just wanted to make a point).
By "business rule", we don't mean any arbitrary rule vaguely related to the business. A business rule is something that's part of the higher-level rules that govern how things work in the domain, the rules of how the actual day-to-day business reality is put into practice, that we need to embody in our application. It's a distilled understanding of how people who are going to be using and benefiting from your application think about and go about their work - or some aspect of their work.
(Some of) your business rules are actually represented by the code you haven't shown; e.g. in case of payments, it's the code that decides when and how to call pay
(and probably how to handle any thrown exceptions):
// Look at whatever calls this - that'll be your business logic
protocol PaymentGateway {
func pay(params: PaymentParam) -> Observable<PaymentInfo>
}
Note, for example, that you can't infer the rules (the logic) expressed there (in the calling code) by simply looking at StripeEnvironment
- that's what I mean when I say that StripeEnvironment
and HostEnvironment
don't really capture any business rules - the relevant code is quite literally not in there.
It's possible that you haven't factored out that code into its own thing; if not, than what's there would constitute the basis of your as-of-yet nonexisting interactor. Now, the interactor code might be simple and straightforward (one or two lines - perfectly fine), or it might be more complicated. E.g., it could have a number of conditionals, or it could delegate parts of its work to more specialized classes - and some of those narrowly specialized classes would be Clean Architecture's entities.
You see, the entities in the context of Clean Architecture aren't all simple data structures with no behavior. A good chunk of the code in the innermost layer is meant to consist of proper, encapsulated objects that allow you to ask them to do stuff for you - by calling methods, and passing (sometimes callable) arguments. Note that this is different from what ORMs call entities, and also different (but in less significant way) from what entities refer to in DDD. Just something to be aware of. You can find material online that explores each of these further, but you'll have to do some sifting, as there's a lot of subpar content out there; try to find/obtain original sources where you can.
Now, you don't have to do it that way. You could go down the anemic domain model route, and have your logic mostly reside in the surrounding classes and functions. That works better for some people for some types of applications. Also, some frameworks might kind of force you to adopt an approach that's more like that. So, there are practicalities to consider that might cause you to deviate from the ideal - whatever that ideal might be for you.