-
Notifications
You must be signed in to change notification settings - Fork 3.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ref types should be interfaces (BucketRef -> IBucket) #742
Comments
Makes sense... I suspect the reason we didn't use interfaces back then was that jsii didn't support interfaces, so we tried to avoid them... My only concern is that there's a difference in API capabilities between the "ref" object and the concrete object. This means that there will be potentially a few capabilities one can do with a What do you think? |
Not sure what you mean. Isn't it the same distinction? An |
Yes, makes sense. I also really dislike the “Ref” terminology. Let’s do it! |
Fixes #742 Built on top of #1428 BREAKING CHANGE: AWS resource-related classes have been changed to conform to API guidelines: - `XxxRef` abstract classes are now `IXxx` interfaces - `XxxRefProps` are now `XxxImportProps` - `XxxRef.import(...)` are now `Xxx.import(...)` accept `XxxImportProps` and return `IXxx` - `export(): XxxImportProps` is now defined in `IXxx` and implemented by imported resources - Lambda's static "metric" methods moved from `lambda.FunctionRef` to `lambda.Function`. - Route53 record classes now require a `zone` when created (not assuming zone is the parent construct).
I'm running into issues right now modeling ELBv2, and I think modeling Refs as interaces is more natural. Hear me out.
ELBv2
ELBv2 comes in two flavors: Application Load Balancer and Network Load Balancer. They're juuust different enough in terms of parameters and things you can configure on them that I want to separate them out, so I can have different properties and methods for each type.
(Examples for the doubtful: "enable access logging" only exists on an ALB, not an NLB. Only ALBs have Security Groups and so are Connectable, NLBs are not. ALBs have a protocol selector, NLBs always just have "TCP", which has bearing on optionality of parameters. Etc.)
However, since we also need to have the Ref types, this leaves me with the following inheritance diagram:
It's hard for me to share implementation between the two sides of this divide, and I end up copy/pasting a bunch of code. Yes, I'm aware I can do an inner object. I think it just adds more code (basically duplicate all lines yet again, and add forwarding functions on the outer class), and is not worth it in this case.
On the other hand, if I had interfaces, I can do the following:
And similar for
ImportedApplicationLoadBalancer
. Much more natural, and I get to reuse some things that are common between load balancers, such asAttributes
.VPCs
I'm also thinking a bit about VPCs, and the myriad of VPC setups that @moofish32 is encountering as he's dealing with power user setups. We can possibly allow all of them in our current implementation; it would far overcomplicate the design for the 90% case of users, so we should allow a mechanism where people can write new kinds of VPC constructs.
Yes, right now we have
VpcNetworkRef
which they could extend, but I would argue that this class already ties way too much into implementation details that might break or complicate actual other VPC implementors.For example, it dictates presence of member variables that are only used in implementations of a subnet selector and export mechanism defined in that class, both of which a different implementor might want to implement differently. To properly allow for a broad set of implementations, only the minimal set functions should be exposed and they should all be abstract--in which case the class is nothing more than an interface anyway, except with the restriction that you can't inherit from anything while implementing it.
Consequences
The
import()
andexport()
methods should go into the concrete type, not theRef
type. But I'd argue this makes more sense anyway. Exporting/importing is a feature of the classes we're providing, and classes 3rd parties write might or might not provide the same capabilities. And even export/import makes more sense on the concrete class with an interface than with this artificial Ref type. Examples:Wrap-up
It seems so much more correct to me to be using interfaces instead of base classes anyway that I can't even remember why we weren't doing that in the first place. Was it the extra
I
at the start which will confuse/irk people in Javaland? Because I'm not sure that's a good reason to settle for an inferior design; and also that's something that can/should be solved by the code generator (same as we do with cases like "whoopsimport
happens to be a reserved word here let's append a_
" or "I will represent properties as getters and setters").@eladb @RomainMuller
The text was updated successfully, but these errors were encountered: