Skip to content
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

refactor: Add GuAppAwareConstruct mixin #853

Merged
merged 2 commits into from
Oct 22, 2021
Merged

refactor: Add GuAppAwareConstruct mixin #853

merged 2 commits into from
Oct 22, 2021

Conversation

akash1810
Copy link
Member

@akash1810 akash1810 commented Oct 21, 2021

What does this change?

When a construct is app aware we:

  • Suffix it's ID with the app string
  • Add the App tag

Currently we have to remember to do this and remember it during review.

This change creates a mixin to simplify this.

Before

interface MyBucketProps extends BucketProps, AppIdentity {}

export class MyBucket extends Bucket {
  constructor(scope: GuStack, id: string, props: MyBucketProps) {
    const idWithApp = AppIdentity.suffixText(props, id) # <-- this is getting replaced

    super(scope, idWithApp, props);

    AppIdentity.taggedConstruct(props, this); # <-- this is getting replaced
  }
}

After

interface MyBucketProps extends BucketProps, AppIdentity {}

class MyBucket extends GuAppAwareConstruct(Bucket) {
  constructor(scope: GuStack, id: string, props: MyBucketProps) {
    super(scope, id, props);
  }
}

In this change, we apply the new mixin to the GuCertificate construct to demonstrate its usage.

This is similar to #418.

Does this change require changes to existing projects or CDK CLI?

No.

Does this change require changes to the library documentation?

No.

How to test

Observe CI, it should continue to pass.

How can we measure success?

A DRYer codebase and less pressure on the review stage!

Have we considered potential risks?

As noted in #418:

Mixins can definitely become complicated. They can also be quite simple and useful and bring a sprinkling of Scala to a TypeScript codebase!

The risk is the codebase is more complicated to understand.

@akash1810 akash1810 force-pushed the aa-mixin-app-aware branch 2 times, most recently from 7dfdd8d to f748d64 Compare October 22, 2021 08:01
@akash1810 akash1810 marked this pull request as ready for review October 22, 2021 08:11
@akash1810 akash1810 requested a review from a team October 22, 2021 08:11
@@ -71,16 +72,16 @@ export class GuCertificate extends GuStatefulMigratableConstruct(Certificate) {
})
)
: undefined;
const awsCertificateProps: CertificateProps & GuMigratingResource = {
const awsCertificateProps: CertificateProps & GuMigratingResource & AppIdentity = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: could this be simplified to GuCertificatePropsWithApp & GuMigratingResource?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah! I hadn't noticed that type. Unfortunately, the compiler isn't happy about this exact change as GuCertificatePropsWithApp wants some stage dependant values.

I've a suspicion we'll refactor how we do this once we address #850. That is, can I ask permission to be lazy? 😄

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for trying this out - my comment was a bit lazy to be honest, when I said "could this be simplified" it was because I genuinely wasn't sure if it'd build or not!

// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- mixin
const [scope, id, props, ...rest] = args;

if (!AppIdentity.isAppIdentity(props)) {
Copy link
Contributor

@jacobwinch jacobwinch Oct 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find this a little confusing... Presumably if you are trying to use the GuAppAwareConstruct Mixin but you haven't got an app property then you've made a mistake? I wonder if we should:

a) Investigate using Constrained Mixins to prevent people from making this mistake, or
b) Throw an error in this scenario

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constrained mixins look a bit too advanced for me atm! I think we'd want to add a constraint based on the type/shape of the constructor? I find this variant a bit easier to read. That is, I'd prefer option b, but not sure if throwing is the right thing to do - is the intention that by throwing we'll catch issues at compile/test time rather than runtime?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Constrained mixins look a bit too advanced for me atm! I think we'd want to add a constraint based on the type/shape of the constructor?

Yes I think so, but I was also struggling a bit with the docs so I'm happy to avoid this complexity for now!

is the intention that by throwing we'll catch issues at compile/test time rather than runtime?

Yes. For example, if we have code which starts using a field called idWithApp when we couldn't actually append an app name to the id, then this is likely to lead to confusing/buggy code, so I'd rather just fail with an error than let users get into this situation.

I don't feel too strongly about this though so feel free to merge as is if you're not keen on the idea of throwing

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think throwing is sensible, especially as it a code path that shouldn't be taken. Will update.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Throwing is a lot clearer too! Thanks for the suggestion.

When a construct is app aware we:
  - Suffix it's ID with the app string
  - Add the `App` tag

Currently we have to remember to do this and remember it during review.

This change creates a mixin to simplify this.

Before
```typescript
interface MyBucketProps extends BucketProps, AppIdentity {}

export class MyBucket extends Bucket {
  constructor(scope: GuStack, id: string, props: MyBucketProps) {
    const idWithApp = AppIdentity.suffixText(props, id) # <-- this is getting replaced

    super(scope, idWithApp, props);

    AppIdentity.taggedConstruct(props, this); # <-- this is getting replaced
  }
}
```

After
```typescript
interface MyBucketProps extends BucketProps, AppIdentity {}

class MyBucket extends GuAppAwareConstruct(Bucket) {
  constructor(scope: GuStack, id: string, props: MyBucketProps) {
    super(scope, id, props);
  }
}
```

This is similar to #418.
@akash1810 akash1810 merged commit d9aeea8 into main Oct 22, 2021
@akash1810 akash1810 deleted the aa-mixin-app-aware branch October 22, 2021 10:05
@github-actions
Copy link
Contributor

🎉 This PR is included in version 27.2.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants