├── .eslintignore ├── .eslintrc.json ├── .gitignore ├── .npmignore ├── .prettierignore ├── .prettierrc ├── .vscode ├── extensions.json └── settings.json ├── README.md ├── bin └── cdk-gof-design-pattern.ts ├── cdk.json ├── drawio ├── abstract-factory │ ├── abstract-factory-cdk-simplified.drawio.svg │ ├── abstract-factory-cdk.drawio.svg │ └── abstract-factory-concept.drawio.svg ├── adapter │ ├── adapter-cdk.drawio.svg │ └── adapter-concept.drawio.svg ├── composite │ ├── composite-cdk-simplified.drawio.svg │ ├── composite-cdk.drawio.svg │ └── composite-concept.drawio.svg ├── decorator │ ├── decorator-cdk-simplified.drawio.svg │ ├── decorator-cdk.drawio.svg │ └── decorator-concept.drawio.svg ├── facade │ ├── facade-cdk.drawio.svg │ └── facade-concept.drawio.svg ├── factory-method │ ├── factory-method-cdk.drawio.svg │ └── factory-method-concept.drawio.svg ├── singleton │ ├── singleton-cdk.drawio.svg │ └── singleton-concept.drawio.svg ├── strategy │ ├── strategy-cdk-simplified.drawio.svg │ ├── strategy-cdk.drawio.svg │ └── strategy-concept.drawio.svg ├── template-method │ ├── template-method-cdk.drawio.svg │ └── template-method-concept.drawio.svg └── visitor │ ├── visitor-cdk-simplified.drawio.svg │ ├── visitor-cdk.drawio.svg │ └── visitor-concept.drawio.svg ├── ja ├── README.md └── drawio │ ├── abstract-factory │ ├── abstract-factory-cdk-simplified.drawio.svg │ ├── abstract-factory-cdk.drawio.svg │ └── abstract-factory-concept.drawio.svg │ ├── adapter │ ├── adapter-cdk.drawio.svg │ └── adapter-concept.drawio.svg │ ├── composite │ ├── composite-cdk-simplified.drawio.svg │ ├── composite-cdk.drawio.svg │ └── composite-concept.drawio.svg │ ├── decorator │ ├── decorator-cdk-simplified.drawio.svg │ ├── decorator-cdk.drawio.svg │ └── decorator-concept.drawio.svg │ ├── facade │ ├── facade-cdk.drawio.svg │ └── facade-concept.drawio.svg │ ├── factory-method │ ├── factory-method-cdk.drawio.svg │ └── factory-method-concept.drawio.svg │ ├── singleton │ ├── singleton-cdk.drawio.svg │ └── singleton-concept.drawio.svg │ ├── strategy │ ├── strategy-cdk-simplified.drawio.svg │ ├── strategy-cdk.drawio.svg │ └── strategy-concept.drawio.svg │ ├── template-method │ ├── template-method-cdk.drawio.svg │ └── template-method-concept.drawio.svg │ └── visitor │ ├── visitor-cdk-simplified.drawio.svg │ ├── visitor-cdk.drawio.svg │ └── visitor-concept.drawio.svg ├── jest.config.js ├── lib └── stack │ ├── abstract-factory │ ├── abstract-factory-stack.ts │ ├── component-construct │ │ ├── app-a.ts │ │ ├── app-b.ts │ │ ├── batch-a.ts │ │ ├── batch-b.ts │ │ └── waf-a.ts │ ├── config.ts │ ├── factory │ │ ├── abstract-factory.ts │ │ ├── dev-factory.ts │ │ └── prd-factory.ts │ ├── lambda │ │ ├── app.ts │ │ └── batch.ts │ └── product-construct │ │ ├── dev-product-a.ts │ │ ├── dev-product-b.ts │ │ ├── my-product-a.ts │ │ ├── my-product-b.ts │ │ ├── prd-product-a.ts │ │ └── prd-product-b.ts │ ├── adapter │ ├── adapter-stack.ts │ ├── bucket-adapter.ts │ ├── config.ts │ └── multiple-resource-policy-target.ts │ ├── composite │ ├── composite-stack.ts │ ├── config.ts │ └── construct │ │ ├── retain-construct.ts │ │ └── retain-descendant.ts │ ├── decorator │ ├── config.ts │ ├── decorator-stack.ts │ ├── destroy-removal-policy-decorator.ts │ ├── removal-policy-resource-decorator.ts │ └── retain-removal-policy-decorator.ts │ ├── facade │ ├── config.ts │ ├── construct │ │ ├── facade-module-a.ts │ │ ├── facade-module-b.ts │ │ └── facade.ts │ └── facade-stack.ts │ ├── factory-method │ ├── config.ts │ ├── factory-method-stack.ts │ ├── retain-bucket-creator.ts │ ├── retain-queue-creator.ts │ └── retain-resource-creator.ts │ ├── singleton │ ├── config.ts │ ├── lambda │ │ └── index.ts │ ├── my-singleton-function.ts │ └── singleton-stack.ts │ ├── strategy │ ├── config.ts │ ├── strategy-stack.ts │ └── validator.ts │ ├── template-method │ ├── config.ts │ ├── template-method-stack.ts │ └── validator │ │ ├── dev-validator.ts │ │ ├── prod-validator.ts │ │ └── validator.ts │ └── visitor │ ├── aspect.ts │ ├── config.ts │ └── visitor-stack.ts ├── package.json ├── test └── cdk-gof-design-pattern.test.ts ├── tsconfig.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | /dist 2 | .git/ 3 | .vscode/ 4 | node_modules 5 | package.json 6 | jest.config.js 7 | .prettierrc 8 | .eslintrc.json -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true, 4 | "ES2020": true 5 | }, 6 | "extends": [ 7 | "airbnb-base", 8 | "plugin:@typescript-eslint/recommended", 9 | "plugin:prettier/recommended", 10 | "prettier/@typescript-eslint" 11 | ], 12 | "parser": "@typescript-eslint/parser", 13 | "parserOptions": { 14 | "ecmaVersion": "latest", 15 | "sourceType": "module" 16 | }, 17 | "plugins": [ 18 | "@typescript-eslint" 19 | ], 20 | "rules": { 21 | } 22 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.js 2 | !jest.config.js 3 | *.d.ts 4 | node_modules 5 | 6 | # CDK asset staging directory 7 | .cdk.staging 8 | cdk.out 9 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | *.ts 2 | !*.d.ts 3 | 4 | # CDK asset staging directory 5 | .cdk.staging 6 | cdk.out 7 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | /dist 2 | .git/ 3 | .vscode/ 4 | node_modules 5 | package.json 6 | jest.config.js 7 | .prettierrc 8 | .eslintrc.json -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "printWidth": 100, 5 | "trailingComma": "all" 6 | } -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "esbenp.prettier-vscode", 4 | "dbaeumer.vscode-eslint", 5 | "streetsidesoftware.code-spell-checker" 6 | ] 7 | } 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.defaultFormatter": "esbenp.prettier-vscode", 3 | "editor.formatOnPaste": true, 4 | "editor.formatOnSave": true, 5 | "editor.formatOnType": true, 6 | "editor.codeActionsOnSave": ["source.fixAll.eslint"], 7 | "search.exclude": {}, 8 | "cSpell.words": ["datapoints", "drawio"], 9 | "typescript.preferences.importModuleSpecifier": "relative" 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cdk-gof-design-pattern 2 | 3 | This repository is about **AWS CDK with Gof Design patterns**, including class diagrams and CDK code. 4 | 5 | The following in Japanese, [Japanese README](./ja/README.md). 6 | 7 | ## Composite 8 | 9 | ### Composite: Concept 10 | 11 | ![composite-concept](./drawio/composite/composite-concept.drawio.svg) 12 | 13 | ### Composite: CDK 14 | 15 | ![composite-cdk](./drawio/composite/composite-cdk.drawio.svg) 16 | 17 | ### Composite: Simplified CDK 18 | 19 | ![composite-cdk-simplified](./drawio/composite/composite-cdk-simplified.drawio.svg) 20 | 21 | ## Facade 22 | 23 | ### Facade: Concept 24 | 25 | ![facade-concept](./drawio/facade/facade-concept.drawio.svg) 26 | 27 | ### Facade: CDK 28 | 29 | ![facade-cdk](./drawio/facade/facade-cdk.drawio.svg) 30 | 31 | ## Adapter 32 | 33 | ### Adapter: Concept 34 | 35 | ![adapter-concept](./drawio/adapter/adapter-concept.drawio.svg) 36 | 37 | ### Adapter: CDK 38 | 39 | ![adapter-cdk](./drawio/adapter/adapter-cdk.drawio.svg) 40 | 41 | ## Decorator 42 | 43 | ### Decorator: Concept 44 | 45 | ![decorator-concept](./drawio/decorator/decorator-concept.drawio.svg) 46 | 47 | ### Decorator: CDK 48 | 49 | ![decorator-cdk](./drawio/decorator/decorator-cdk.drawio.svg) 50 | 51 | ### Decorator: Simplified CDK 52 | 53 | ![decorator-cdk](./drawio/decorator/decorator-cdk-simplified.drawio.svg) 54 | 55 | ## Singleton 56 | 57 | ### Singleton: Concept 58 | 59 | ![singleton-concept](./drawio/singleton/singleton-concept.drawio.svg) 60 | 61 | ### Singleton: CDK 62 | 63 | ![singleton-cdk](./drawio/singleton/singleton-cdk.drawio.svg) 64 | 65 | ## Strategy 66 | 67 | ### Strategy: Concept 68 | 69 | ![strategy-concept](./drawio/strategy/strategy-concept.drawio.svg) 70 | 71 | ### Strategy: CDK 72 | 73 | ![strategy-cdk](./drawio/strategy/strategy-cdk.drawio.svg) 74 | 75 | ### Strategy: Simplified CDK 76 | 77 | ![strategy-cdk-simplified](./drawio/strategy/strategy-cdk-simplified.drawio.svg) 78 | 79 | ## Template Method 80 | 81 | ### Template Method: Concept 82 | 83 | ![template-method-concept](./drawio/template-method/template-method-concept.drawio.svg) 84 | 85 | ### Template Method: CDK 86 | 87 | ![template-method-cdk](./drawio/template-method/template-method-cdk.drawio.svg) 88 | 89 | ## Factory Method 90 | 91 | ### Factory Method: Concept 92 | 93 | ![factory-method-concept](./drawio/factory-method/factory-method-concept.drawio.svg) 94 | 95 | ### Factory Method: CDK 96 | 97 | ![factory-method-cdk](./drawio/factory-method/factory-method-cdk.drawio.svg) 98 | 99 | ## Abstract Factory 100 | 101 | ### Abstract Factory: Concept 102 | 103 | ![abstract-factory-concept](./drawio/abstract-factory/abstract-factory-concept.drawio.svg) 104 | 105 | ### Abstract Factory: CDK 106 | 107 | ![abstract-factory-cdk](./drawio/abstract-factory/abstract-factory-cdk.drawio.svg) 108 | 109 | ### Abstract Factory: Simplified CDK 110 | 111 | ![abstract-factory-cdk-simplified](./drawio/abstract-factory/abstract-factory-cdk-simplified.drawio.svg) 112 | 113 | ## Visitor 114 | 115 | ### Visitor: Concept 116 | 117 | ![visitor-concept](./drawio/visitor/visitor-concept.drawio.svg) 118 | 119 | ### Visitor: CDK 120 | 121 | ![visitor-cdk](./drawio/visitor/visitor-cdk.drawio.svg) 122 | 123 | ### Visitor: Simplified CDK 124 | 125 | ![visitor-cdk-simplified](./drawio/visitor/visitor-cdk-simplified.drawio.svg) 126 | -------------------------------------------------------------------------------- /bin/cdk-gof-design-pattern.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import "source-map-support/register"; 3 | import * as cdk from "aws-cdk-lib"; 4 | import { compositeConfigStackProps } from "../lib/stack/composite/config"; 5 | import { CompositeStack } from "../lib/stack/composite/composite-stack"; 6 | import { DecoratorStack } from "../lib/stack/decorator/decorator-stack"; 7 | import { decoratorConfigStackProps } from "../lib/stack/decorator/config"; 8 | import { FacadeStack } from "../lib/stack/facade/facade-stack"; 9 | import { facadeConfigStackProps } from "../lib/stack/facade/config"; 10 | import { AdapterStack } from "../lib/stack/adapter/adapter-stack"; 11 | import { adapterConfigStackProps } from "../lib/stack/adapter/config"; 12 | import { TemplateMethodStack } from "../lib/stack/template-method/template-method-stack"; 13 | import { getTemplateMethodConfigStackProps } from "../lib/stack/template-method/config"; 14 | import { SingletonStack } from "../lib/stack/singleton/singleton-stack"; 15 | import { singletonConfigStackProps } from "../lib/stack/singleton/config"; 16 | import { VisitorStack } from "../lib/stack/visitor/visitor-stack"; 17 | import { visitorConfigStackProps } from "../lib/stack/visitor/config"; 18 | import { BucketVersioningChecker } from "../lib/stack/visitor/aspect"; 19 | import { StrategyStack } from "../lib/stack/strategy/strategy-stack"; 20 | import { strategyConfigStackProps } from "../lib/stack/strategy/config"; 21 | import { FactoryMethodStack } from "../lib/stack/factory-method/factory-method-stack"; 22 | import { factoryMethodConfigStackProps } from "../lib/stack/factory-method/config"; 23 | import { AbstractFactoryStack } from "../lib/stack/abstract-factory/abstract-factory-stack"; 24 | import { getAbstractFactoryConfigStackProps } from "../lib/stack/abstract-factory/config"; 25 | 26 | const app = new cdk.App(); 27 | 28 | new CompositeStack(app, "CompositeStack", compositeConfigStackProps); 29 | 30 | new FacadeStack(app, "FacadeStack", facadeConfigStackProps); 31 | 32 | new AdapterStack(app, "AdapterStack", adapterConfigStackProps); 33 | 34 | new DecoratorStack(app, "DecoratorStack", decoratorConfigStackProps); 35 | 36 | new SingletonStack(app, "SingletonStack", singletonConfigStackProps); 37 | 38 | new StrategyStack(app, "StrategyStack", strategyConfigStackProps); 39 | 40 | new TemplateMethodStack(app, "TemplateMethodStack", getTemplateMethodConfigStackProps("dev")); 41 | 42 | new FactoryMethodStack(app, "FactoryMethodStack", factoryMethodConfigStackProps); 43 | 44 | new AbstractFactoryStack(app, "AbstractFactoryStack", getAbstractFactoryConfigStackProps("dev")); 45 | 46 | const visitorStack = new VisitorStack(app, "VisitorStack", visitorConfigStackProps); 47 | cdk.Aspects.of(visitorStack).add(new BucketVersioningChecker()); 48 | -------------------------------------------------------------------------------- /cdk.json: -------------------------------------------------------------------------------- 1 | { 2 | "app": "npx ts-node --prefer-ts-exts bin/cdk-gof-design-pattern.ts", 3 | "watch": { 4 | "include": [ 5 | "**" 6 | ], 7 | "exclude": [ 8 | "README.md", 9 | "cdk*.json", 10 | "**/*.d.ts", 11 | "**/*.js", 12 | "tsconfig.json", 13 | "package*.json", 14 | "yarn.lock", 15 | "node_modules", 16 | "test" 17 | ] 18 | }, 19 | "context": { 20 | "@aws-cdk/aws-lambda:recognizeLayerVersion": true, 21 | "@aws-cdk/core:checkSecretUsage": true, 22 | "@aws-cdk/core:target-partitions": [ 23 | "aws", 24 | "aws-cn" 25 | ], 26 | "@aws-cdk-containers/ecs-service-extensions:enableDefaultLogDriver": true, 27 | "@aws-cdk/aws-ec2:uniqueImdsv2TemplateName": true, 28 | "@aws-cdk/aws-ecs:arnFormatIncludesClusterName": true, 29 | "@aws-cdk/aws-iam:minimizePolicies": true, 30 | "@aws-cdk/core:validateSnapshotRemovalPolicy": true, 31 | "@aws-cdk/aws-codepipeline:crossAccountKeyAliasStackSafeResourceName": true, 32 | "@aws-cdk/aws-s3:createDefaultLoggingPolicy": true, 33 | "@aws-cdk/aws-sns-subscriptions:restrictSqsDescryption": true, 34 | "@aws-cdk/aws-apigateway:disableCloudWatchRole": true, 35 | "@aws-cdk/core:enablePartitionLiterals": true, 36 | "@aws-cdk/aws-events:eventsTargetQueueSameAccount": true, 37 | "@aws-cdk/aws-iam:standardizedServicePrincipals": true, 38 | "@aws-cdk/aws-ecs:disableExplicitDeploymentControllerForCircuitBreaker": true, 39 | "@aws-cdk/aws-iam:importedRoleStackSafeDefaultPolicyName": true, 40 | "@aws-cdk/aws-s3:serverAccessLogsUseBucketPolicy": true, 41 | "@aws-cdk/customresources:installLatestAwsSdkDefault": false 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /drawio/adapter/adapter-cdk.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | BucketAdapter 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | + addManyToResourcePolicy(statements) 20 |
21 |
22 |
23 |
24 | 25 | + addManyToResourcePolicy(statements) 26 | 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | MultipleResourcePolicyTarget 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 |
44 | 45 | + addManyToResourcePolicy(statements) 46 | 47 |
48 |
49 |
50 |
51 | 52 | + addManyToResourcePolicy(statements) 53 | 54 |
55 |
56 | 57 | 58 | 59 | 60 | 61 | Bucket 62 | 63 | 64 | 65 | 66 | 67 | 68 |
69 |
70 |
71 | + addToResourcePolicy(statement) 72 |
73 |
74 |
75 |
76 | 77 | + addToResourcePolicy(statement) 78 | 79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 |
90 |
91 |
92 | My own Class 93 |
94 |
95 |
96 |
97 | 98 | My own Class 99 | 100 |
101 |
102 | 103 | 104 | 105 | 106 |
107 |
108 |
109 | Provided by CDK 110 |
111 |
112 |
113 |
114 | 115 | Provided by... 116 | 117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | Text is not SVG - cannot display 125 | 126 | 127 | 128 |
-------------------------------------------------------------------------------- /drawio/adapter/adapter-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Adapter 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | + requireMethod() 20 |
21 |
22 |
23 |
24 | 25 | + requireMethod() 26 | 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | Target 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 |
44 | 45 | + requireMethod() 46 | 47 |
48 |
49 |
50 |
51 | 52 | + requireMethod() 53 | 54 |
55 |
56 | 57 | 58 | 59 | 60 | 61 | Adaptee 62 | 63 | 64 | 65 | 66 | 67 | 68 |
69 |
70 |
71 | + oldMethod() 72 |
73 |
74 |
75 |
76 | 77 | + oldMethod() 78 | 79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 |
90 |
91 |
92 | Concept 93 |
94 |
95 |
96 |
97 | 98 | Concept 99 | 100 |
101 |
102 |
103 | 104 | 105 | 106 | 107 | Text is not SVG - cannot display 108 | 109 | 110 | 111 |
-------------------------------------------------------------------------------- /drawio/decorator/decorator-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ConcreteComponent 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | + operation() 20 |
21 |
22 |
23 |
24 | 25 | + operation() 26 | 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | Decorator 35 | 36 | 37 | 38 | 39 | 40 |
41 |
42 |
43 | - component 44 |
45 |
46 |
47 |
48 | 49 | - component 50 | 51 |
52 |
53 | 54 | 55 | 56 | 57 |
58 |
59 |
60 | 61 | + operation() 62 | 63 |
64 |
65 |
66 |
67 | 68 | + operation() 69 | 70 |
71 |
72 | 73 | 74 | 75 | 76 | 77 | Component 78 | 79 | 80 | 81 | 82 | 83 | 84 |
85 |
86 |
87 | 88 | + operation() 89 | 90 |
91 |
92 |
93 |
94 | 95 | + operation() 96 | 97 |
98 |
99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | ConcreteDecorator 109 | 110 | 111 | 112 | 113 | 114 | 115 |
116 |
117 |
118 | + operation() 119 |
120 |
121 |
122 |
123 | 124 | + operation() 125 | 126 |
127 |
128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 |
137 |
138 |
139 | Concept 140 |
141 |
142 |
143 |
144 | 145 | Concept 146 | 147 |
148 |
149 |
150 | 151 | 152 | 153 | 154 | Text is not SVG - cannot display 155 | 156 | 157 | 158 |
-------------------------------------------------------------------------------- /drawio/facade/facade-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Facade 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ModuleB 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | ModuleA 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ModuleC 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
63 |
64 |
65 | Concept 66 |
67 |
68 |
69 |
70 | 71 | Concept 72 | 73 |
74 |
75 |
76 | 77 | 78 | 79 | 80 | Text is not SVG - cannot display 81 | 82 | 83 | 84 |
-------------------------------------------------------------------------------- /drawio/singleton/singleton-cdk.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | SingletonFunction 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 | My own Class 21 |
22 |
23 |
24 |
25 | 26 | My own Class 27 | 28 |
29 |
30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 | Provided by CDK 38 |
39 |
40 |
41 |
42 | 43 | Provided by... 44 | 45 |
46 |
47 | 48 | 49 | 50 | 51 | 52 | MySingletonFunction 53 | 54 | 55 | 56 | 57 | 58 |
59 |
60 |
61 | 62 | - singleton: MySingletonFunction 63 | 64 |
65 |
66 |
67 |
68 | 69 | - singleton: MySingletonFunction 70 | 71 |
72 |
73 | 74 | 75 | 76 | 77 |
78 |
79 |
80 | - constructor() 81 |
82 |
83 |
84 |
85 | 86 | - constructor() 87 | 88 |
89 |
90 | 91 | 92 | 93 |
94 |
95 |
96 | 97 | + getInstance(): MySingletonFunction 98 | 99 |
100 |
101 |
102 |
103 | 104 | + getInstance(): MySingletonFunction 105 | 106 |
107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | NodejsFunction 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 |
124 |
125 |
126 |
127 | The AWS-provided SingletonFunction has the same behavior as the Singleton Pattern, but its implementation is more CDK-like, so I implemented it simply on my own. 128 |
129 |
130 |
131 |
132 |
133 | The ensureLambda method in the SingletonFunction corresponds to the Singleton Pattern (aws-cdk-lib/aws-lambda/lib/singleton-lambda.ts) 134 |
135 |
136 |
137 |
138 |
139 | 140 | The AWS-provided SingletonFunction has the same behavior as the Singl... 141 | 142 |
143 |
144 | 145 | 146 |
147 | 148 | 149 | 150 | 151 | Text is not SVG - cannot display 152 | 153 | 154 | 155 |
-------------------------------------------------------------------------------- /drawio/singleton/singleton-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Singleton 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 19 | - singleton: Singleton 20 | 21 |
22 |
23 |
24 |
25 | 26 | - singleton: Singleton 27 | 28 |
29 |
30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 | - constructor() 38 |
39 |
40 |
41 |
42 | 43 | - constructor() 44 | 45 |
46 |
47 | 48 | 49 | 50 |
51 |
52 |
53 | 54 | + getInstance(): Singleton 55 | 56 |
57 |
58 |
59 |
60 | 61 | + getInstance(): Singleton 62 | 63 |
64 |
65 | 66 | 67 | 68 | 69 |
70 |
71 |
72 | Concept 73 |
74 |
75 |
76 |
77 | 78 | Concept 79 | 80 |
81 |
82 |
83 | 84 | 85 | 86 | 87 | Text is not SVG - cannot display 88 | 89 | 90 | 91 |
-------------------------------------------------------------------------------- /drawio/strategy/strategy-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ConcreteStrategyB 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | + algorismMethod() 20 |
21 |
22 |
23 |
24 | 25 | + algorismMethod() 26 | 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | ConcreteStrategyA 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 |
44 | + algorismMethod() 45 |
46 |
47 |
48 |
49 | 50 | + algorismMethod() 51 | 52 |
53 |
54 | 55 | 56 | 57 | 58 | 59 | Strategy 60 | 61 | 62 | 63 | 64 | 65 | 66 |
67 |
68 |
69 | 70 | + algorismMethod() 71 | 72 |
73 |
74 |
75 |
76 | 77 | + algorismMethod() 78 | 79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 |
94 |
95 | Concept 96 |
97 |
98 |
99 |
100 | 101 | Concept 102 | 103 |
104 |
105 | 106 | 107 | 108 | 109 | 110 | Context 111 | 112 | 113 | 114 | 115 | 116 |
117 |
118 |
119 | - strategy: Strategy 120 |
121 |
122 |
123 |
124 | 125 | - strategy: Strategy 126 | 127 |
128 |
129 | 130 | 131 | 132 | 133 |
134 |
135 |
136 | + contextMethod() 137 |
138 |
139 |
140 |
141 | 142 | + contextMethod() 143 | 144 |
145 |
146 |
147 | 148 | 149 | 150 | 151 | Text is not SVG - cannot display 152 | 153 | 154 | 155 |
-------------------------------------------------------------------------------- /drawio/template-method/template-method-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ConcreteClass 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | # method1() 20 |
21 |
22 |
23 |
24 | 25 | # method1() 26 | 27 |
28 |
29 | 30 | 31 | 32 |
33 |
34 |
35 | # method2() 36 |
37 |
38 |
39 |
40 | 41 | # method2() 42 | 43 |
44 |
45 | 46 | 47 | 48 | 49 | 50 | <<Abstract>> 51 | 52 | 53 | AbstractClass 54 | 55 | 56 | 57 | 58 | 59 | 60 |
61 |
62 |
63 | + templateMethod() 64 |
65 |
66 |
67 |
68 | 69 | + templateMethod() 70 | 71 |
72 |
73 | 74 | 75 | 76 |
77 |
78 |
79 | 80 | # method1() 81 | 82 |
83 |
84 |
85 |
86 | 87 | # method1() 88 | 89 |
90 |
91 | 92 | 93 | 94 |
95 |
96 |
97 | 98 | # method2() 99 | 100 |
101 |
102 |
103 |
104 | 105 | # method2() 106 | 107 |
108 |
109 | 110 | 111 | 112 | 113 | 114 | 115 |
116 |
117 |
118 | Concept 119 |
120 |
121 |
122 |
123 | 124 | Concept 125 | 126 |
127 |
128 |
129 | 130 | 131 | 132 | 133 | Text is not SVG - cannot display 134 | 135 | 136 | 137 |
-------------------------------------------------------------------------------- /ja/README.md: -------------------------------------------------------------------------------- 1 | # cdk-gof-design-pattern 2 | 3 | AWS Dev Day 2023 Tokyo での登壇セッション『**AWS CDK で学ぶ GoF デザインパターン 〜IaC にもコード設計〜**』の CDK コード実例とクラス図集です。 4 | 5 | ※以下リンクからセッションの動画や登壇資料をご覧いただけます。 6 | 7 | - [YouTube](https://www.youtube.com/watch?v=Gi0m08NuLJw) 8 | - [登壇資料](https://speakerdeck.com/gotok365/aws-dev-day-cdk-gof-design-patterns) 9 | - その他参考 10 | - ブログ記事: [AWS CDK 内部実装で使われている GoF デザインパターン](https://go-to-k.hatenablog.com/entry/aws-cdk-internal-gof-paterns) 11 | 12 | ## Composite 13 | 14 | ### Composite: 概念 15 | 16 | ![composite-concept](./drawio/composite/composite-concept.drawio.svg) 17 | 18 | ### Composite: CDK 19 | 20 | ![composite-cdk](./drawio/composite/composite-cdk.drawio.svg) 21 | 22 | ### Composite: 簡略 CDK 23 | 24 | ![composite-cdk-simplified](./drawio/composite/composite-cdk-simplified.drawio.svg) 25 | 26 | ## Facade 27 | 28 | ### Facade: 概念 29 | 30 | ![facade-concept](./drawio/facade/facade-concept.drawio.svg) 31 | 32 | ### Facade: CDK 33 | 34 | ![facade-cdk](./drawio/facade/facade-cdk.drawio.svg) 35 | 36 | ## Adapter 37 | 38 | ### Adapter: 概念 39 | 40 | ![adapter-concept](./drawio/adapter/adapter-concept.drawio.svg) 41 | 42 | ### Adapter: CDK 43 | 44 | ![adapter-cdk](./drawio/adapter/adapter-cdk.drawio.svg) 45 | 46 | ## Decorator 47 | 48 | ### Decorator: 概念 49 | 50 | ![decorator-concept](./drawio/decorator/decorator-concept.drawio.svg) 51 | 52 | ### Decorator: CDK 53 | 54 | ![decorator-cdk](./drawio/decorator/decorator-cdk.drawio.svg) 55 | 56 | ### Decorator: 簡略 CDK 57 | 58 | ![decorator-cdk](./drawio/decorator/decorator-cdk-simplified.drawio.svg) 59 | 60 | ## Singleton 61 | 62 | ### Singleton: 概念 63 | 64 | ![singleton-concept](./drawio/singleton/singleton-concept.drawio.svg) 65 | 66 | ### Singleton: CDK 67 | 68 | ![singleton-cdk](./drawio/singleton/singleton-cdk.drawio.svg) 69 | 70 | ## Strategy 71 | 72 | ### Strategy: 概念 73 | 74 | ![strategy-concept](./drawio/strategy/strategy-concept.drawio.svg) 75 | 76 | ### Strategy: CDK 77 | 78 | ![strategy-cdk](./drawio/strategy/strategy-cdk.drawio.svg) 79 | 80 | ### Strategy: 簡略 CDK 81 | 82 | ![strategy-cdk-simplified](./drawio/strategy/strategy-cdk-simplified.drawio.svg) 83 | 84 | ## Template Method 85 | 86 | ### Template Method: 概念 87 | 88 | ![template-method-concept](./drawio/template-method/template-method-concept.drawio.svg) 89 | 90 | ### Template Method: CDK 91 | 92 | ![template-method-cdk](./drawio/template-method/template-method-cdk.drawio.svg) 93 | 94 | ## Factory Method 95 | 96 | ### Factory Method: 概念 97 | 98 | ![factory-method-concept](./drawio/factory-method/factory-method-concept.drawio.svg) 99 | 100 | ### Factory Method: CDK 101 | 102 | ![factory-method-cdk](./drawio/factory-method/factory-method-cdk.drawio.svg) 103 | 104 | ## Abstract Factory 105 | 106 | ### Abstract Factory: 概念 107 | 108 | ![abstract-factory-concept](./drawio/abstract-factory/abstract-factory-concept.drawio.svg) 109 | 110 | ### Abstract Factory: CDK 111 | 112 | ![abstract-factory-cdk](./drawio/abstract-factory/abstract-factory-cdk.drawio.svg) 113 | 114 | ### Abstract Factory: 簡略 CDK 115 | 116 | ![abstract-factory-cdk-simplified](./drawio/abstract-factory/abstract-factory-cdk-simplified.drawio.svg) 117 | 118 | ## Visitor 119 | 120 | ### Visitor: 概念 121 | 122 | ![visitor-concept](./drawio/visitor/visitor-concept.drawio.svg) 123 | 124 | ### Visitor: CDK 125 | 126 | ![visitor-cdk](./drawio/visitor/visitor-cdk.drawio.svg) 127 | 128 | ### Visitor: 簡略 CDK 129 | 130 | ![visitor-cdk-simplified](./drawio/visitor/visitor-cdk-simplified.drawio.svg) 131 | -------------------------------------------------------------------------------- /ja/drawio/adapter/adapter-cdk.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | BucketAdapter 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | + addManyToResourcePolicy(statements) 20 |
21 |
22 |
23 |
24 | 25 | + addManyToResourcePolicy(statements) 26 | 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | MultipleResourcePolicyTarget 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 |
44 | 45 | + addManyToResourcePolicy(statements) 46 | 47 |
48 |
49 |
50 |
51 | 52 | + addManyToResourcePolicy(statements) 53 | 54 |
55 |
56 | 57 | 58 | 59 | 60 | 61 | Bucket 62 | 63 | 64 | 65 | 66 | 67 | 68 |
69 |
70 |
71 | + addToResourcePolicy(statement) 72 |
73 |
74 |
75 |
76 | 77 | + addToResourcePolicy(statement) 78 | 79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 |
90 |
91 |
92 | 独自 93 |
94 |
95 |
96 |
97 | 98 | 独自 99 | 100 |
101 |
102 | 103 | 104 | 105 | 106 |
107 |
108 |
109 | CDK提供 110 |
111 |
112 |
113 |
114 | 115 | CDK提供 116 | 117 |
118 |
119 |
120 | 121 | 122 | 123 | 124 | Text is not SVG - cannot display 125 | 126 | 127 | 128 |
-------------------------------------------------------------------------------- /ja/drawio/adapter/adapter-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Adapter 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | + requireMethod() 20 |
21 |
22 |
23 |
24 | 25 | + requireMethod() 26 | 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | Target 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 |
44 | 45 | + requireMethod() 46 | 47 |
48 |
49 |
50 |
51 | 52 | + requireMethod() 53 | 54 |
55 |
56 | 57 | 58 | 59 | 60 | 61 | Adaptee 62 | 63 | 64 | 65 | 66 | 67 | 68 |
69 |
70 |
71 | + oldMethod() 72 |
73 |
74 |
75 |
76 | 77 | + oldMethod() 78 | 79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 |
90 |
91 |
92 | 概念 93 |
94 |
95 |
96 |
97 | 98 | 概念 99 | 100 |
101 |
102 |
103 | 104 | 105 | 106 | 107 | Text is not SVG - cannot display 108 | 109 | 110 | 111 |
-------------------------------------------------------------------------------- /ja/drawio/facade/facade-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Facade 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | ModuleB 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | ModuleA 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | ModuleC 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 |
63 |
64 |
65 | 概念 66 |
67 |
68 |
69 |
70 | 71 | 概念 72 | 73 |
74 |
75 |
76 | 77 | 78 | 79 | 80 | Text is not SVG - cannot display 81 | 82 | 83 | 84 |
-------------------------------------------------------------------------------- /ja/drawio/singleton/singleton-cdk.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | SingletonFunction 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 |
20 | 独自 21 |
22 |
23 |
24 |
25 | 26 | 独自 27 | 28 |
29 |
30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 | CDK提供 38 |
39 |
40 |
41 |
42 | 43 | CDK提供 44 | 45 |
46 |
47 | 48 | 49 | 50 | 51 | 52 | MySingletonFunction 53 | 54 | 55 | 56 | 57 | 58 |
59 |
60 |
61 | 62 | - singleton: MySingletonFunction 63 | 64 |
65 |
66 |
67 |
68 | 69 | - singleton: MySingletonFunction 70 | 71 |
72 |
73 | 74 | 75 | 76 | 77 |
78 |
79 |
80 | - constructor() 81 |
82 |
83 |
84 |
85 | 86 | - constructor() 87 | 88 |
89 |
90 | 91 | 92 | 93 |
94 |
95 |
96 | 97 | + getInstance(): MySingletonFunction 98 | 99 |
100 |
101 |
102 |
103 | 104 | + getInstance(): MySingletonFunction 105 | 106 |
107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | NodejsFunction 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 |
124 |
125 |
126 | ※AWS提供のSingletonFunctionは、挙動はいわゆるSingletonパターンと同じですが実装がCDK色強いため、自前で簡易実装しました。 127 |
128 |
129 | ※SingletonFunction.ensureLambdaメソッドがSingletonパターンにあたる(aws-cdk-lib/aws-lambda/lib/singleton-lambda.ts) 130 |
131 |
132 |
133 |
134 | 135 | ※AWS提供のSingletonFunctionは、挙動はいわゆるSingletonパターンと同じですが実装がCDK色強いため、自前で簡易実装しました。... 136 | 137 |
138 |
139 | 140 | 141 |
142 | 143 | 144 | 145 | 146 | Text is not SVG - cannot display 147 | 148 | 149 | 150 |
-------------------------------------------------------------------------------- /ja/drawio/singleton/singleton-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | Singleton 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 |
18 | 19 | - singleton: Singleton 20 | 21 |
22 |
23 |
24 |
25 | 26 | - singleton: Singleton 27 | 28 |
29 |
30 | 31 | 32 | 33 | 34 |
35 |
36 |
37 | - constructor() 38 |
39 |
40 |
41 |
42 | 43 | - constructor() 44 | 45 |
46 |
47 | 48 | 49 | 50 |
51 |
52 |
53 | 54 | + getInstance(): Singleton 55 | 56 |
57 |
58 |
59 |
60 | 61 | + getInstance(): Singleton 62 | 63 |
64 |
65 | 66 | 67 | 68 | 69 |
70 |
71 |
72 | 概念 73 |
74 |
75 |
76 |
77 | 78 | 概念 79 | 80 |
81 |
82 |
83 | 84 | 85 | 86 | 87 | Text is not SVG - cannot display 88 | 89 | 90 | 91 |
-------------------------------------------------------------------------------- /ja/drawio/strategy/strategy-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ConcreteStrategyB 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | + algorismMethod() 20 |
21 |
22 |
23 |
24 | 25 | + algorismMethod() 26 | 27 |
28 |
29 | 30 | 31 | 32 | 33 | 34 | ConcreteStrategyA 35 | 36 | 37 | 38 | 39 | 40 | 41 |
42 |
43 |
44 | + algorismMethod() 45 |
46 |
47 |
48 |
49 | 50 | + algorismMethod() 51 | 52 |
53 |
54 | 55 | 56 | 57 | 58 | 59 | Strategy 60 | 61 | 62 | 63 | 64 | 65 | 66 |
67 |
68 |
69 | 70 | + algorismMethod() 71 | 72 |
73 |
74 |
75 |
76 | 77 | + algorismMethod() 78 | 79 |
80 |
81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 |
93 |
94 |
95 | 概念 96 |
97 |
98 |
99 |
100 | 101 | 概念 102 | 103 |
104 |
105 | 106 | 107 | 108 | 109 | 110 | Context 111 | 112 | 113 | 114 | 115 | 116 |
117 |
118 |
119 | - strategy: Strategy 120 |
121 |
122 |
123 |
124 | 125 | - strategy: Strategy 126 | 127 |
128 |
129 | 130 | 131 | 132 | 133 |
134 |
135 |
136 | + contextMethod() 137 |
138 |
139 |
140 |
141 | 142 | + contextMethod() 143 | 144 |
145 |
146 |
147 | 148 | 149 | 150 | 151 | Text is not SVG - cannot display 152 | 153 | 154 | 155 |
-------------------------------------------------------------------------------- /ja/drawio/template-method/template-method-concept.drawio.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ConcreteClass 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 |
18 |
19 | # method1() 20 |
21 |
22 |
23 |
24 | 25 | # method1() 26 | 27 |
28 |
29 | 30 | 31 | 32 |
33 |
34 |
35 | # method2() 36 |
37 |
38 |
39 |
40 | 41 | # method2() 42 | 43 |
44 |
45 | 46 | 47 | 48 | 49 | 50 | <<Abstract>> 51 | 52 | 53 | AbstractClass 54 | 55 | 56 | 57 | 58 | 59 | 60 |
61 |
62 |
63 | + templateMethod() 64 |
65 |
66 |
67 |
68 | 69 | + templateMethod() 70 | 71 |
72 |
73 | 74 | 75 | 76 |
77 |
78 |
79 | 80 | # method1() 81 | 82 |
83 |
84 |
85 |
86 | 87 | # method1() 88 | 89 |
90 |
91 | 92 | 93 | 94 |
95 |
96 |
97 | 98 | # method2() 99 | 100 |
101 |
102 |
103 |
104 | 105 | # method2() 106 | 107 |
108 |
109 | 110 | 111 | 112 | 113 | 114 | 115 |
116 |
117 |
118 | 概念 119 |
120 |
121 |
122 |
123 | 124 | 概念 125 | 126 |
127 |
128 |
129 | 130 | 131 | 132 | 133 | Text is not SVG - cannot display 134 | 135 | 136 | 137 |
-------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | testEnvironment: 'node', 3 | roots: ['/test'], 4 | testMatch: ['**/*.test.ts'], 5 | transform: { 6 | '^.+\\.tsx?$': 'ts-jest' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/abstract-factory-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import { AbstractFactoryConfigStackProps } from "./config"; 4 | import { DevFactory } from "./factory/dev-factory"; 5 | import { PrdFactory } from "./factory/prd-factory"; 6 | 7 | export class AbstractFactoryStack extends cdk.Stack { 8 | constructor(scope: Construct, id: string, props: AbstractFactoryConfigStackProps) { 9 | super(scope, id, props); 10 | 11 | const factory = props.stage === "prd" ? new PrdFactory() : new DevFactory(); 12 | 13 | factory.createProductA(this, "ProductA", { 14 | appModuleConstructProps: { 15 | memorySize: props.config.memorySize, 16 | }, 17 | }); 18 | 19 | factory.createProductB(this, "ProductB", { 20 | appModuleConstructProps: { 21 | memorySize: props.config.memorySize, 22 | }, 23 | }); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/component-construct/app-a.ts: -------------------------------------------------------------------------------- 1 | import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; 2 | import { Construct } from "constructs"; 3 | import { join } from "path"; 4 | 5 | export interface AppModuleAConstructProps { 6 | memorySize: number; 7 | } 8 | 9 | export class AppModuleA extends Construct { 10 | constructor(scope: Construct, id: string, props: AppModuleAConstructProps) { 11 | super(scope, id); 12 | 13 | new NodejsFunction(this, "AppFunctionA1", { 14 | entry: join(__dirname, "../lambda/app.ts"), 15 | bundling: { 16 | forceDockerBundling: false, 17 | }, 18 | memorySize: props.memorySize, 19 | }); 20 | 21 | new NodejsFunction(this, "AppFunctionA2", { 22 | entry: join(__dirname, "../lambda/app.ts"), 23 | bundling: { 24 | forceDockerBundling: false, 25 | }, 26 | }); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/component-construct/app-b.ts: -------------------------------------------------------------------------------- 1 | import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; 2 | import { Construct } from "constructs"; 3 | import { join } from "path"; 4 | 5 | export interface AppModuleBConstructProps { 6 | memorySize: number; 7 | } 8 | 9 | export class AppModuleB extends Construct { 10 | constructor(scope: Construct, id: string, props: AppModuleBConstructProps) { 11 | super(scope, id); 12 | 13 | new NodejsFunction(this, "AppFunctionB1", { 14 | entry: join(__dirname, "../lambda/app.ts"), 15 | bundling: { 16 | forceDockerBundling: false, 17 | }, 18 | memorySize: props.memorySize, 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/component-construct/batch-a.ts: -------------------------------------------------------------------------------- 1 | import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; 2 | import { Construct } from "constructs"; 3 | import { join } from "path"; 4 | 5 | export interface BatchModuleAConstructProps {} 6 | 7 | export class BatchModuleA extends Construct { 8 | constructor(scope: Construct, id: string, props?: BatchModuleAConstructProps) { 9 | super(scope, id); 10 | 11 | new NodejsFunction(this, "BatchFunctionA", { 12 | entry: join(__dirname, "../lambda/batch.ts"), 13 | bundling: { 14 | forceDockerBundling: false, 15 | }, 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/component-construct/batch-b.ts: -------------------------------------------------------------------------------- 1 | import { NodejsFunction } from "aws-cdk-lib/aws-lambda-nodejs"; 2 | import { Construct } from "constructs"; 3 | import { join } from "path"; 4 | 5 | export interface BatchModuleBConstructProps {} 6 | 7 | export class BatchModuleB extends Construct { 8 | constructor(scope: Construct, id: string, props?: BatchModuleBConstructProps) { 9 | super(scope, id); 10 | 11 | new NodejsFunction(this, "BatchFunctionB", { 12 | entry: join(__dirname, "../lambda/batch.ts"), 13 | bundling: { 14 | forceDockerBundling: false, 15 | }, 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/component-construct/waf-a.ts: -------------------------------------------------------------------------------- 1 | import { CfnWebACL } from "aws-cdk-lib/aws-wafv2"; 2 | import { Construct } from "constructs"; 3 | 4 | export interface WafModuleAConstructProps {} 5 | 6 | export class WafModuleA extends Construct { 7 | constructor(scope: Construct, id: string, props?: WafModuleAConstructProps) { 8 | super(scope, id); 9 | 10 | new CfnWebACL(this, "WebAclA", { 11 | name: "WebAclA", 12 | defaultAction: { block: {} }, 13 | scope: "REGIONAL", 14 | visibilityConfig: { 15 | cloudWatchMetricsEnabled: false, 16 | metricName: "WebAclA", 17 | sampledRequestsEnabled: false, 18 | }, 19 | }); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/config.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | 3 | export interface AbstractFactoryConfig { 4 | memorySize: number; 5 | } 6 | 7 | type StageType = "dev" | "prd"; 8 | 9 | export interface AbstractFactoryConfigStackProps extends StackProps { 10 | config: AbstractFactoryConfig; 11 | stage: StageType; 12 | } 13 | 14 | export const getAbstractFactoryConfigStackProps = ( 15 | stage: StageType, 16 | ): AbstractFactoryConfigStackProps => { 17 | return { 18 | env: { 19 | region: "ap-northeast-1", 20 | }, 21 | stage: stage, 22 | config: getAbstractFactoryStackConfig(stage), 23 | } as const; 24 | }; 25 | 26 | const getAbstractFactoryStackConfig = (stage: StageType): AbstractFactoryConfig => { 27 | switch (stage) { 28 | case "dev": 29 | stage; 30 | return { 31 | memorySize: 128, 32 | } as const; 33 | case "prd": 34 | return { 35 | memorySize: 256, 36 | } as const; 37 | default: 38 | throw new Error("Context value [stage] is invalid."); 39 | } 40 | }; 41 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/factory/abstract-factory.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { MyProductA, MyProductAConstructProps } from "../product-construct/my-product-a"; 3 | import { MyProductB, MyProductBConstructProps } from "../product-construct/my-product-b"; 4 | 5 | export abstract class AbstractFactory { 6 | abstract createProductA( 7 | scope: Construct, 8 | id: string, 9 | myProductConstructProps: MyProductAConstructProps, 10 | ): MyProductA; 11 | 12 | abstract createProductB( 13 | scope: Construct, 14 | id: string, 15 | myProductConstructProps: MyProductBConstructProps, 16 | ): MyProductB; 17 | } 18 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/factory/dev-factory.ts: -------------------------------------------------------------------------------- 1 | import { AbstractFactory } from "./abstract-factory"; 2 | import { DevProductA } from "../product-construct/dev-product-a"; 3 | import { Construct } from "constructs"; 4 | import { MyProductA, MyProductAConstructProps } from "../product-construct/my-product-a"; 5 | import { MyProductB, MyProductBConstructProps } from "../product-construct/my-product-b"; 6 | import { DevProductB } from "../product-construct/dev-product-b"; 7 | 8 | export class DevFactory extends AbstractFactory { 9 | createProductA( 10 | scope: Construct, 11 | id: string, 12 | myProductConstructProps: MyProductAConstructProps, 13 | ): MyProductA { 14 | return new DevProductA(scope, id, myProductConstructProps); 15 | } 16 | 17 | createProductB( 18 | scope: Construct, 19 | id: string, 20 | myProductConstructProps: MyProductBConstructProps, 21 | ): MyProductB { 22 | return new DevProductB(scope, id, myProductConstructProps); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/factory/prd-factory.ts: -------------------------------------------------------------------------------- 1 | import { AbstractFactory } from "./abstract-factory"; 2 | import { Construct } from "constructs"; 3 | import { MyProductA, MyProductAConstructProps } from "../product-construct/my-product-a"; 4 | import { MyProductB, MyProductBConstructProps } from "../product-construct/my-product-b"; 5 | import { PrdProductA } from "../product-construct/prd-product-a"; 6 | import { PrdProductB } from "../product-construct/prd-product-b"; 7 | 8 | export class PrdFactory extends AbstractFactory { 9 | createProductA( 10 | scope: Construct, 11 | id: string, 12 | myProductConstructProps: MyProductAConstructProps, 13 | ): MyProductA { 14 | return new PrdProductA(scope, id, myProductConstructProps); 15 | } 16 | 17 | createProductB( 18 | scope: Construct, 19 | id: string, 20 | myProductConstructProps: MyProductBConstructProps, 21 | ): MyProductB { 22 | return new PrdProductB(scope, id, myProductConstructProps); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/lambda/app.ts: -------------------------------------------------------------------------------- 1 | import { S3Event } from "aws-lambda"; 2 | 3 | export const handler = async (event: S3Event): Promise => { 4 | console.log("This is app function."); 5 | }; 6 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/lambda/batch.ts: -------------------------------------------------------------------------------- 1 | import { S3Event } from "aws-lambda"; 2 | 3 | export const handler = async (event: S3Event): Promise => { 4 | console.log("This is batch function."); 5 | }; 6 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/product-construct/dev-product-a.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { AppModuleA } from "../component-construct/app-a"; 3 | import { MyProductA, MyProductAConstructProps } from "./my-product-a"; 4 | 5 | export class DevProductA extends MyProductA { 6 | constructor(scope: Construct, id: string, props: MyProductAConstructProps) { 7 | super(scope, id); 8 | 9 | new AppModuleA(this, "AppModule", props.appModuleConstructProps); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/product-construct/dev-product-b.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { MyProductB, MyProductBConstructProps } from "./my-product-b"; 3 | import { AppModuleB } from "../component-construct/app-b"; 4 | 5 | export class DevProductB extends MyProductB { 6 | constructor(scope: Construct, id: string, props: MyProductBConstructProps) { 7 | super(scope, id); 8 | 9 | new AppModuleB(this, "AppModule", props.appModuleConstructProps); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/product-construct/my-product-a.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { AppModuleAConstructProps } from "../component-construct/app-a"; 3 | 4 | export interface MyProductAConstructProps { 5 | appModuleConstructProps: AppModuleAConstructProps; 6 | } 7 | 8 | export abstract class MyProductA extends Construct { 9 | constructor(scope: Construct, id: string, props?: MyProductAConstructProps) { 10 | super(scope, id); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/product-construct/my-product-b.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { AppModuleBConstructProps } from "../component-construct/app-b"; 3 | 4 | export interface MyProductBConstructProps { 5 | appModuleConstructProps: AppModuleBConstructProps; 6 | } 7 | 8 | export abstract class MyProductB extends Construct { 9 | constructor(scope: Construct, id: string, props?: MyProductBConstructProps) { 10 | super(scope, id); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/product-construct/prd-product-a.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { MyProductA, MyProductAConstructProps } from "./my-product-a"; 3 | import { AppModuleA } from "../component-construct/app-a"; 4 | import { BatchModuleA } from "../component-construct/batch-a"; 5 | import { WafModuleA } from "../component-construct/waf-a"; 6 | 7 | export class PrdProductA extends MyProductA { 8 | constructor(scope: Construct, id: string, props: MyProductAConstructProps) { 9 | super(scope, id); 10 | 11 | new AppModuleA(this, "AppModule", props.appModuleConstructProps); 12 | new BatchModuleA(this, "BatchModule"); 13 | new WafModuleA(this, "WafModule"); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/stack/abstract-factory/product-construct/prd-product-b.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { MyProductB, MyProductBConstructProps } from "./my-product-b"; 3 | import { AppModuleB } from "../component-construct/app-b"; 4 | import { BatchModuleB } from "../component-construct/batch-b"; 5 | 6 | export class PrdProductB extends MyProductB { 7 | constructor(scope: Construct, id: string, props: MyProductBConstructProps) { 8 | super(scope, id); 9 | 10 | new AppModuleB(this, "AppModule", props.appModuleConstructProps); 11 | new BatchModuleB(this, "BatchModule"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/stack/adapter/adapter-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import { AdapterConfigStackProps } from "./config"; 4 | import { BucketAdapter } from "./bucket-adapter"; 5 | import { AnyPrincipal, Effect, PolicyStatement } from "aws-cdk-lib/aws-iam"; 6 | 7 | export class AdapterStack extends cdk.Stack { 8 | constructor(scope: Construct, id: string, props: AdapterConfigStackProps) { 9 | super(scope, id, props); 10 | 11 | // Create Bucket with custom methods 12 | const bucketAdapter = new BucketAdapter(this, "BucketAdapter"); 13 | 14 | // Create Some PolicyStatements 15 | const policyStatements = this.createPolicyStatements(bucketAdapter.bucketArn); 16 | 17 | // Apply multiple PolicyStatements at once 18 | bucketAdapter.addManyToResourcePolicy(policyStatements); 19 | } 20 | 21 | private createPolicyStatements(bucketArn: string): PolicyStatement[] { 22 | return [ 23 | new PolicyStatement({ 24 | effect: Effect.DENY, 25 | principals: [new AnyPrincipal()], 26 | actions: ["s3:PutObject"], 27 | resources: [`${bucketArn}/*`], 28 | conditions: { 29 | StringLike: { 30 | "aws:Referer": ["http://www.abc.example.com/*"], 31 | }, 32 | }, 33 | }), 34 | new PolicyStatement({ 35 | effect: Effect.DENY, 36 | principals: [new AnyPrincipal()], 37 | actions: ["s3:GetObject"], 38 | resources: [`${bucketArn}/*`], 39 | conditions: { 40 | StringLike: { 41 | "aws:Referer": ["http://www.cde.example.com/*"], 42 | }, 43 | }, 44 | }), 45 | ]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /lib/stack/adapter/bucket-adapter.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { MultipleResourcePolicyTarget } from "./multiple-resource-policy-target"; 3 | import { AddToResourcePolicyResult, PolicyStatement } from "aws-cdk-lib/aws-iam"; 4 | import { Bucket, BucketProps } from "aws-cdk-lib/aws-s3"; 5 | 6 | export interface BucketAdapterProps extends BucketProps {} 7 | 8 | export class BucketAdapter extends Bucket implements MultipleResourcePolicyTarget { 9 | constructor(scope: Construct, id: string, props?: BucketAdapterProps) { 10 | super(scope, id, props); 11 | } 12 | 13 | addManyToResourcePolicy(statements: PolicyStatement[]): AddToResourcePolicyResult[] { 14 | return statements.map((statement) => { 15 | return this.addToResourcePolicy(statement); 16 | }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/stack/adapter/config.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | 3 | export interface AdapterConfig {} 4 | 5 | export interface AdapterConfigStackProps extends StackProps { 6 | config: AdapterConfig; 7 | } 8 | 9 | export const adapterConfigStackProps: AdapterConfigStackProps = { 10 | env: { 11 | region: "ap-northeast-1", 12 | }, 13 | config: {}, 14 | }; 15 | -------------------------------------------------------------------------------- /lib/stack/adapter/multiple-resource-policy-target.ts: -------------------------------------------------------------------------------- 1 | import { AddToResourcePolicyResult, PolicyStatement } from "aws-cdk-lib/aws-iam"; 2 | 3 | export interface MultipleResourcePolicyTarget { 4 | addManyToResourcePolicy(statements: PolicyStatement[]): AddToResourcePolicyResult[]; 5 | } 6 | -------------------------------------------------------------------------------- /lib/stack/composite/composite-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct, IConstruct } from "constructs"; 3 | import { CompositeConfigStackProps } from "./config"; 4 | import { RetainConstruct } from "./construct/retain-construct"; 5 | import { Queue } from "aws-cdk-lib/aws-sqs"; 6 | 7 | export class CompositeStack extends cdk.Stack { 8 | constructor(scope: Construct, id: string, props: CompositeConfigStackProps) { 9 | super(scope, id, props); 10 | 11 | // Dummy 12 | new Queue(this, "OtherQueue"); 13 | 14 | // Ex.1) Can delete all resources in a stack in a development environment, etc. 15 | this.addRemovalPolicy(this.node.children, cdk.RemovalPolicy.DESTROY); 16 | 17 | // Ex.2) RETAIN all resources in a specific construct. 18 | const retainConstruct = new RetainConstruct(this, "RetainConstruct"); 19 | this.addRemovalPolicy(retainConstruct.node.children, cdk.RemovalPolicy.RETAIN); 20 | } 21 | 22 | private addRemovalPolicy(children: IConstruct[], removalPolicy: cdk.RemovalPolicy) { 23 | children.forEach((child) => { 24 | if (cdk.Resource.isResource(child)) { 25 | child.applyRemovalPolicy(removalPolicy); 26 | } else if (Construct.isConstruct(child)) { 27 | this.addRemovalPolicy(child.node.children, removalPolicy); 28 | } 29 | }); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /lib/stack/composite/config.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | 3 | export interface CompositeConfig {} 4 | 5 | export interface CompositeConfigStackProps extends StackProps { 6 | config: CompositeConfig; 7 | } 8 | 9 | export const compositeConfigStackProps: CompositeConfigStackProps = { 10 | env: { 11 | region: "ap-northeast-1", 12 | }, 13 | config: {}, 14 | }; 15 | -------------------------------------------------------------------------------- /lib/stack/composite/construct/retain-construct.ts: -------------------------------------------------------------------------------- 1 | import { Queue } from "aws-cdk-lib/aws-sqs"; 2 | import { Construct } from "constructs"; 3 | import { RetainDescendant } from "./retain-descendant"; 4 | 5 | export interface RetainConstructProps {} 6 | 7 | export class RetainConstruct extends Construct { 8 | constructor(scope: Construct, id: string, props?: RetainConstructProps) { 9 | super(scope, id); 10 | new Queue(this, "ChildQueue1"); 11 | new Queue(this, "ChildQueue2"); 12 | new RetainDescendant(this, "RetainDescendant"); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /lib/stack/composite/construct/retain-descendant.ts: -------------------------------------------------------------------------------- 1 | import { Queue } from "aws-cdk-lib/aws-sqs"; 2 | import { Construct } from "constructs"; 3 | 4 | export interface RetainDescendantProps {} 5 | 6 | export class RetainDescendant extends Construct { 7 | constructor(scope: Construct, id: string, props?: RetainDescendantProps) { 8 | super(scope, id); 9 | new Queue(this, "DescendantQueue"); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /lib/stack/decorator/config.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | 3 | export interface DecoratorConfig {} 4 | 5 | export interface DecoratorConfigStackProps extends StackProps { 6 | config: DecoratorConfig; 7 | } 8 | 9 | export const decoratorConfigStackProps: DecoratorConfigStackProps = { 10 | env: { 11 | region: "ap-northeast-1", 12 | }, 13 | config: {}, 14 | }; 15 | -------------------------------------------------------------------------------- /lib/stack/decorator/decorator-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import { DecoratorConfigStackProps } from "./config"; 4 | import { DestroyRemovalPolicyDecorator } from "./destroy-removal-policy-decorator"; 5 | import { Queue } from "aws-cdk-lib/aws-sqs"; 6 | import { RetainRemovalPolicyDecorator } from "./retain-removal-policy-decorator"; 7 | 8 | export class DecoratorStack extends cdk.Stack { 9 | constructor(scope: Construct, id: string, props: DecoratorConfigStackProps) { 10 | super(scope, id, props); 11 | 12 | new DestroyRemovalPolicyDecorator(this, "SQSQueueDestroy1", new Queue(this, "SQSQueue1")); 13 | new DestroyRemovalPolicyDecorator(this, "SQSQueueDestroy2", new Queue(this, "SQSQueue2")); 14 | new RetainRemovalPolicyDecorator(this, "SQSQueueRetain3", new Queue(this, "SQSQueue3")); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/stack/decorator/destroy-removal-policy-decorator.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { RemovalPolicyResourceDecorator } from "./removal-policy-resource-decorator"; 3 | import { RemovalPolicy, Resource } from "aws-cdk-lib"; 4 | 5 | export class DestroyRemovalPolicyDecorator extends RemovalPolicyResourceDecorator { 6 | constructor(scope: Construct, id: string, resource: Resource) { 7 | super(scope, id, resource); 8 | } 9 | 10 | protected getOwnRemovalPolicy(): RemovalPolicy { 11 | return RemovalPolicy.DESTROY; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/stack/decorator/removal-policy-resource-decorator.ts: -------------------------------------------------------------------------------- 1 | import { RemovalPolicy, Resource } from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | 4 | export abstract class RemovalPolicyResourceDecorator extends Resource { 5 | private resource: Resource; 6 | 7 | // Extended constructor 8 | constructor(scope: Construct, id: string, resource: Resource) { 9 | super(scope, id); 10 | this.resource = resource; 11 | this.applyRemovalPolicy(this.getOwnRemovalPolicy()); 12 | } 13 | 14 | // In this example, this method is not extended in effect, 15 | // but it can be extended to change the behavior of this method, etc. 16 | applyRemovalPolicy(policy: RemovalPolicy): void { 17 | this.resource.applyRemovalPolicy(policy); 18 | } 19 | 20 | protected abstract getOwnRemovalPolicy(): RemovalPolicy; 21 | } 22 | -------------------------------------------------------------------------------- /lib/stack/decorator/retain-removal-policy-decorator.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { RemovalPolicyResourceDecorator } from "./removal-policy-resource-decorator"; 3 | import { RemovalPolicy, Resource } from "aws-cdk-lib"; 4 | 5 | export class RetainRemovalPolicyDecorator extends RemovalPolicyResourceDecorator { 6 | constructor(scope: Construct, id: string, resource: Resource) { 7 | super(scope, id, resource); 8 | } 9 | 10 | protected getOwnRemovalPolicy(): RemovalPolicy { 11 | return RemovalPolicy.RETAIN; 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/stack/facade/config.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | 3 | export interface FacadeConfig { 4 | } 5 | 6 | export interface FacadeConfigStackProps extends StackProps { 7 | config: FacadeConfig; 8 | } 9 | 10 | export const facadeConfigStackProps: FacadeConfigStackProps = { 11 | env: { 12 | region: "ap-northeast-1", 13 | }, 14 | config: { 15 | }, 16 | }; -------------------------------------------------------------------------------- /lib/stack/facade/construct/facade-module-a.ts: -------------------------------------------------------------------------------- 1 | import { Queue } from "aws-cdk-lib/aws-sqs"; 2 | import { Construct } from "constructs"; 3 | 4 | export interface FacadeModuleAConstructProps {} 5 | export class FacadeModuleA extends Construct { 6 | constructor(scope: Construct, id: string, props?: FacadeModuleAConstructProps) { 7 | super(scope, id); 8 | 9 | // Assumptions of complex and numerous resource definitions 10 | new Queue(this, `${id}SQSQueue1`); 11 | new Queue(this, `${id}SQSQueue2`); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/stack/facade/construct/facade-module-b.ts: -------------------------------------------------------------------------------- 1 | import { Queue } from "aws-cdk-lib/aws-sqs"; 2 | import { Construct } from "constructs"; 3 | import { FacadeModuleA } from "./facade-module-a"; 4 | 5 | export interface FacadeModuleBConstructProps {} 6 | export class FacadeModuleB extends Construct { 7 | constructor(scope: Construct, id: string, props?: FacadeModuleBConstructProps) { 8 | super(scope, id); 9 | 10 | // Assumptions of complex and numerous resource definitions 11 | new Queue(this, `${id}SQSQueue1`); 12 | new Queue(this, `${id}SQSQueue2`); 13 | 14 | // FacadeA can also be called 15 | new FacadeModuleA(this, "FacadeBA"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /lib/stack/facade/construct/facade.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { FacadeModuleA } from "./facade-module-a"; 3 | import { FacadeModuleB } from "./facade-module-b"; 4 | 5 | export interface FacadeConstructProps {} 6 | export class Facade extends Construct { 7 | constructor(scope: Construct, id: string, props?: FacadeConstructProps) { 8 | super(scope, id); 9 | 10 | new FacadeModuleA(this, "FacadeModuleA"); 11 | new FacadeModuleB(this, "FacadeModuleB"); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /lib/stack/facade/facade-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import { FacadeConfigStackProps } from "./config"; 4 | import { Facade } from "./construct/facade"; 5 | 6 | export class FacadeStack extends cdk.Stack { 7 | constructor(scope: Construct, id: string, props: FacadeConfigStackProps) { 8 | super(scope, id, props); 9 | 10 | new Facade(this, "Facade"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /lib/stack/factory-method/config.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | 3 | export interface FactoryMethodConfig {} 4 | 5 | export interface FactoryMethodConfigStackProps extends StackProps { 6 | config: FactoryMethodConfig; 7 | } 8 | 9 | export const factoryMethodConfigStackProps: FactoryMethodConfigStackProps = { 10 | env: { 11 | region: "ap-northeast-1", 12 | }, 13 | config: {}, 14 | }; 15 | -------------------------------------------------------------------------------- /lib/stack/factory-method/factory-method-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import { FactoryMethodConfigStackProps } from "./config"; 4 | import { RetainQueueCreator } from "./retain-queue-creator"; 5 | import { RetainBucketCreator } from "./retain-bucket-creator"; 6 | 7 | export class FactoryMethodStack extends cdk.Stack { 8 | constructor(scope: Construct, id: string, props: FactoryMethodConfigStackProps) { 9 | super(scope, id, props); 10 | 11 | const retainQueueCreator = new RetainQueueCreator(); 12 | const retainBucketCreator = new RetainBucketCreator(); 13 | 14 | retainQueueCreator.create(this, "RetainQueueA"); 15 | retainQueueCreator.create(this, "RetainQueueB"); 16 | retainBucketCreator.create(this, "RetainBucketA"); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/stack/factory-method/retain-bucket-creator.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { Resource } from "aws-cdk-lib"; 3 | import { RetainResourceCreator } from "./retain-resource-creator"; 4 | import { Bucket } from "aws-cdk-lib/aws-s3"; 5 | 6 | export class RetainBucketCreator extends RetainResourceCreator { 7 | protected createResource(scope: Construct, id: string): Resource { 8 | return new Bucket(scope, id); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/stack/factory-method/retain-queue-creator.ts: -------------------------------------------------------------------------------- 1 | import { Construct } from "constructs"; 2 | import { Resource } from "aws-cdk-lib"; 3 | import { RetainResourceCreator } from "./retain-resource-creator"; 4 | import { Queue } from "aws-cdk-lib/aws-sqs"; 5 | 6 | export class RetainQueueCreator extends RetainResourceCreator { 7 | protected createResource(scope: Construct, id: string): Resource { 8 | return new Queue(scope, id); 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /lib/stack/factory-method/retain-resource-creator.ts: -------------------------------------------------------------------------------- 1 | import { RemovalPolicy, Resource } from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | 4 | export abstract class RetainResourceCreator { 5 | create(scope: Construct, id: string): Resource { 6 | const resource = this.createResource(scope, id); 7 | resource.applyRemovalPolicy(RemovalPolicy.RETAIN); 8 | return resource; 9 | } 10 | 11 | protected abstract createResource(scope: Construct, id: string): Resource; 12 | } 13 | -------------------------------------------------------------------------------- /lib/stack/singleton/config.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | 3 | export interface SingletonConfig {} 4 | 5 | export interface SingletonConfigStackProps extends StackProps { 6 | config: SingletonConfig; 7 | } 8 | 9 | export const singletonConfigStackProps: SingletonConfigStackProps = { 10 | env: { 11 | region: "ap-northeast-1", 12 | }, 13 | config: {}, 14 | }; 15 | -------------------------------------------------------------------------------- /lib/stack/singleton/lambda/index.ts: -------------------------------------------------------------------------------- 1 | import { S3Event } from "aws-lambda"; 2 | 3 | export const handler = async (event: S3Event): Promise => { 4 | event.Records.forEach((record) => console.log(record.s3.object.key)); 5 | }; 6 | -------------------------------------------------------------------------------- /lib/stack/singleton/my-singleton-function.ts: -------------------------------------------------------------------------------- 1 | import { NodejsFunction, NodejsFunctionProps } from "aws-cdk-lib/aws-lambda-nodejs"; 2 | import { Construct } from "constructs"; 3 | 4 | export class MySingletonFunction extends NodejsFunction { 5 | private static singleton: MySingletonFunction; 6 | 7 | private constructor(scope: Construct, id: string, props: NodejsFunctionProps) { 8 | super(scope, id, props); 9 | } 10 | 11 | static getInstance( 12 | scope: Construct, 13 | id: string, 14 | props: NodejsFunctionProps, 15 | ): MySingletonFunction { 16 | if (this.singleton === undefined) { 17 | this.singleton = new MySingletonFunction(scope, id, props); 18 | } 19 | return this.singleton; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/stack/singleton/singleton-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import { SingletonConfigStackProps } from "./config"; 4 | import { Code, Runtime, SingletonFunction } from "aws-cdk-lib/aws-lambda"; 5 | import { join } from "path"; 6 | import { MySingletonFunction } from "./my-singleton-function"; 7 | 8 | export class SingletonStack extends cdk.Stack { 9 | constructor(scope: Construct, id: string, props: SingletonConfigStackProps) { 10 | super(scope, id, props); 11 | 12 | // SingletonFunction provided by AWS 13 | // No matter how many times you call it, they only make one. 14 | this.createLambda("A"); 15 | this.createLambda("B"); 16 | this.createLambda("C"); 17 | 18 | // MySingletonFunction of my own creation (inherits from NodejsFunction) 19 | // No matter how many times you call it, they only make one. 20 | this.createMyLambda("A"); 21 | this.createMyLambda("B"); 22 | this.createMyLambda("C"); 23 | } 24 | 25 | // Deploy after `yarn build-singleton` in repository's root directory 26 | private createLambda(suffix: string): SingletonFunction { 27 | return new SingletonFunction(this, `Singleton${suffix}`, { 28 | uuid: "ff5cb24a-ea95-11ed-a05b-0242ac120003", 29 | code: Code.fromAsset(join(__dirname, "./lambda")), 30 | handler: "index.handler", 31 | runtime: Runtime.NODEJS_18_X, 32 | }); 33 | } 34 | 35 | private createMyLambda(suffix: string): MySingletonFunction { 36 | return MySingletonFunction.getInstance(this, `MySingleton${suffix}`, { 37 | entry: join(__dirname, "./lambda/index.ts"), 38 | bundling: { 39 | forceDockerBundling: false, 40 | }, 41 | }); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /lib/stack/strategy/config.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | 3 | export interface StrategyConfig { 4 | scopeType: string; 5 | } 6 | 7 | export interface StrategyConfigStackProps extends StackProps { 8 | config: StrategyConfig; 9 | } 10 | 11 | export const strategyConfigStackProps: StrategyConfigStackProps = { 12 | env: { 13 | region: "ap-northeast-1", 14 | }, 15 | config: { 16 | scopeType: "REGIONAL", 17 | // scopeType: "CLOUDFRONT", 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /lib/stack/strategy/strategy-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import { StrategyConfigStackProps } from "./config"; 4 | import { Validator } from "./validator"; 5 | 6 | export class StrategyStack extends cdk.Stack { 7 | constructor(scope: Construct, id: string, props: StrategyConfigStackProps) { 8 | super(scope, id, props); 9 | this.init(props); 10 | } 11 | 12 | private init(props: StrategyConfigStackProps) { 13 | const validator = new Validator(props.config.scopeType, this.region); 14 | this.node.addValidation(validator); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /lib/stack/strategy/validator.ts: -------------------------------------------------------------------------------- 1 | import { IValidation } from "constructs"; 2 | 3 | export class Validator implements IValidation { 4 | private scopeType: string; 5 | private region: string; 6 | 7 | constructor(scopeType: string, region: string) { 8 | this.scopeType = scopeType; 9 | this.region = region; 10 | } 11 | 12 | public validate(): string[] { 13 | const errors: string[] = []; 14 | 15 | if (this.scopeType === "CLOUDFRONT" && this.region !== "us-east-1") { 16 | errors.push("Region must be us-east-1"); 17 | } 18 | return errors; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /lib/stack/template-method/config.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | 3 | export interface TemplateMethodConfig { 4 | cpu: number; 5 | memoryLimitMiB: number; 6 | desiredCount: number; 7 | } 8 | 9 | type StageType = "dev" | "prd"; 10 | 11 | export interface TemplateMethodConfigStackProps extends StackProps { 12 | stage: StageType; 13 | config: TemplateMethodConfig; 14 | } 15 | 16 | export const getTemplateMethodConfigStackProps = ( 17 | stage: StageType, 18 | ): TemplateMethodConfigStackProps => { 19 | return { 20 | env: { 21 | region: "ap-northeast-1", 22 | }, 23 | stage: stage, 24 | config: getTemplateMethodStackConfig(stage), 25 | } as const; 26 | }; 27 | 28 | const getTemplateMethodStackConfig = (stage: StageType): TemplateMethodConfig => { 29 | switch (stage) { 30 | case "dev": 31 | stage; 32 | return { 33 | cpu: 1024, 34 | memoryLimitMiB: 2048, 35 | desiredCount: 2, 36 | } as const; 37 | case "prd": 38 | return { 39 | cpu: 4096, 40 | memoryLimitMiB: 8192, 41 | desiredCount: 6, 42 | } as const; 43 | default: 44 | throw new Error("Context value [stage] is invalid."); 45 | } 46 | }; 47 | -------------------------------------------------------------------------------- /lib/stack/template-method/template-method-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import { TemplateMethodConfigStackProps } from "./config"; 4 | import { ProdValidator } from "./validator/prod-validator"; 5 | import { DevValidator } from "./validator/dev-validator"; 6 | 7 | export class TemplateMethodStack extends cdk.Stack { 8 | constructor(scope: Construct, id: string, props: TemplateMethodConfigStackProps) { 9 | super(scope, id, props); 10 | 11 | const validator = 12 | props.stage === "dev" ? new DevValidator(props.config) : new ProdValidator(props.config); 13 | this.node.addValidation(validator); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /lib/stack/template-method/validator/dev-validator.ts: -------------------------------------------------------------------------------- 1 | import { TemplateMethodConfig } from "../config"; 2 | import { Validator } from "./validator"; 3 | 4 | export class DevValidator extends Validator { 5 | constructor(config: TemplateMethodConfig) { 6 | super(config); 7 | } 8 | 9 | protected checkCpuThreshold(cpu: number): boolean { 10 | return cpu <= 2048; 11 | } 12 | protected checkMemoryLimitMiBThreshold(memoryLimitMiB: number): boolean { 13 | return memoryLimitMiB <= 4096; 14 | } 15 | protected checkDesiredCountThreshold(desiredCount: number): boolean { 16 | return desiredCount === 2; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/stack/template-method/validator/prod-validator.ts: -------------------------------------------------------------------------------- 1 | import { TemplateMethodConfig } from "../config"; 2 | import { Validator } from "./validator"; 3 | 4 | export class ProdValidator extends Validator { 5 | constructor(config: TemplateMethodConfig) { 6 | super(config); 7 | } 8 | 9 | protected checkCpuThreshold(cpu: number): boolean { 10 | return cpu >= 4096; 11 | } 12 | protected checkMemoryLimitMiBThreshold(memoryLimitMiB: number): boolean { 13 | return memoryLimitMiB >= 8192; 14 | } 15 | protected checkDesiredCountThreshold(desiredCount: number): boolean { 16 | return desiredCount >= 6; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/stack/template-method/validator/validator.ts: -------------------------------------------------------------------------------- 1 | import { IValidation } from "constructs"; 2 | import { TemplateMethodConfig } from "../config"; 3 | 4 | export abstract class Validator implements IValidation { 5 | protected config: TemplateMethodConfig; 6 | 7 | constructor(config: TemplateMethodConfig) { 8 | this.config = config; 9 | } 10 | 11 | public validate(): string[] { 12 | const errors: string[] = []; 13 | 14 | if (!this.checkCpuThreshold(this.config.cpu)) { 15 | errors.push("CPU is invalid."); 16 | } 17 | if (!this.checkMemoryLimitMiBThreshold(this.config.memoryLimitMiB)) { 18 | errors.push("Memory is invalid."); 19 | } 20 | if (!this.checkDesiredCountThreshold(this.config.desiredCount)) { 21 | errors.push("DesiredCount is invalid."); 22 | } 23 | 24 | return errors; 25 | } 26 | 27 | protected abstract checkCpuThreshold(cpu: number): boolean; 28 | protected abstract checkMemoryLimitMiBThreshold(memoryLimitMiB: number): boolean; 29 | protected abstract checkDesiredCountThreshold(desiredCount: number): boolean; 30 | } 31 | -------------------------------------------------------------------------------- /lib/stack/visitor/aspect.ts: -------------------------------------------------------------------------------- 1 | import { Annotations, IAspect, Tokenization } from "aws-cdk-lib"; 2 | import { CfnBucket } from "aws-cdk-lib/aws-s3"; 3 | import { IConstruct } from "constructs"; 4 | 5 | // From the official page: https://docs.aws.amazon.com/cdk/v2/guide/aspects.html 6 | export class BucketVersioningChecker implements IAspect { 7 | public visit(node: IConstruct): void { 8 | // See that we're dealing with a CfnBucket 9 | if (node instanceof CfnBucket) { 10 | // Check for versioning property, exclude the case where the property 11 | // can be a token (IResolvable). 12 | if ( 13 | !node.versioningConfiguration || 14 | (!Tokenization.isResolvable(node.versioningConfiguration) && 15 | node.versioningConfiguration.status !== "Enabled") 16 | ) { 17 | Annotations.of(node).addError("Bucket versioning is not enabled"); 18 | } 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /lib/stack/visitor/config.ts: -------------------------------------------------------------------------------- 1 | import { StackProps } from "aws-cdk-lib"; 2 | 3 | export interface VisitorConfig {} 4 | 5 | export interface VisitorConfigStackProps extends StackProps { 6 | config: VisitorConfig; 7 | } 8 | 9 | export const visitorConfigStackProps: VisitorConfigStackProps = { 10 | env: { 11 | region: "ap-northeast-1", 12 | }, 13 | config: {}, 14 | }; 15 | -------------------------------------------------------------------------------- /lib/stack/visitor/visitor-stack.ts: -------------------------------------------------------------------------------- 1 | import * as cdk from "aws-cdk-lib"; 2 | import { Construct } from "constructs"; 3 | import { VisitorConfigStackProps } from "./config"; 4 | import { Bucket } from "aws-cdk-lib/aws-s3"; 5 | 6 | export class VisitorStack extends cdk.Stack { 7 | constructor(scope: Construct, id: string, props: VisitorConfigStackProps) { 8 | super(scope, id, props); 9 | 10 | new Bucket(this, "Bucket", { 11 | versioned: true, 12 | }); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cdk-gof-design-pattern", 3 | "version": "0.1.0", 4 | "bin": { 5 | "cdk-gof-design-pattern": "bin/cdk-gof-design-pattern.js" 6 | }, 7 | "scripts": { 8 | "build": "tsc", 9 | "watch": "tsc -w", 10 | "test": "jest", 11 | "cdk": "cdk", 12 | "build-singleton": "esbuild ./lib/stack/singleton/lambda/index.ts --bundle --outdir=./lib/stack/singleton/lambda --platform=node --external:aws-sdk" 13 | }, 14 | "devDependencies": { 15 | "@types/aws-lambda": "^8.10.115", 16 | "@types/jest": "^29.2.5", 17 | "@types/node": "18.11.18", 18 | "@types/prettier": "2.6.0", 19 | "@typescript-eslint/eslint-plugin": "^5.30.5", 20 | "@typescript-eslint/parser": "^5.30.5", 21 | "aws-cdk": "2.60.0", 22 | "esbuild": "^0.17.18", 23 | "eslint": "^8.19.0", 24 | "eslint-config-airbnb-base": "^15.0.0", 25 | "eslint-config-prettier": "^8.5.0", 26 | "eslint-plugin-import": "^2.26.0", 27 | "eslint-plugin-prettier": "^4.2.1", 28 | "jest": "^29.3.1", 29 | "prettier": "^2.7.1", 30 | "ts-jest": "^29.0.3", 31 | "ts-node": "^10.9.1", 32 | "typescript": "~4.9.4" 33 | }, 34 | "dependencies": { 35 | "aws-cdk-lib": "2.60.0", 36 | "constructs": "^10.0.0", 37 | "source-map-support": "^0.5.21" 38 | }, 39 | "volta": { 40 | "node": "18.16.0", 41 | "yarn": "1.22.17" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /test/cdk-gof-design-pattern.test.ts: -------------------------------------------------------------------------------- 1 | // import * as cdk from 'aws-cdk-lib'; 2 | // import { Template } from 'aws-cdk-lib/assertions'; 3 | // import * as CdkAddValidation from '../lib/cdk-gof-design-pattern-stack'; 4 | 5 | // example test. To run these tests, uncomment this file along with the 6 | // example resource in lib/cdk-gof-design-pattern-stack.ts 7 | test("SQS Queue Created", () => { 8 | // const app = new cdk.App(); 9 | // // WHEN 10 | // const stack = new CdkAddValidation.CdkAddValidationStack(app, 'MyTestStack'); 11 | // // THEN 12 | // const template = Template.fromStack(stack); 13 | // template.hasResourceProperties('AWS::SQS::Queue', { 14 | // VisibilityTimeout: 300 15 | // }); 16 | }); 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2020", 4 | "module": "commonjs", 5 | "lib": [ 6 | "es2020" 7 | ], 8 | "declaration": true, 9 | "strict": true, 10 | "noImplicitAny": true, 11 | "strictNullChecks": true, 12 | "noImplicitThis": true, 13 | "alwaysStrict": true, 14 | "noUnusedLocals": false, 15 | "noUnusedParameters": false, 16 | "noImplicitReturns": true, 17 | "noFallthroughCasesInSwitch": false, 18 | "inlineSourceMap": true, 19 | "inlineSources": true, 20 | "experimentalDecorators": true, 21 | "strictPropertyInitialization": false, 22 | "typeRoots": [ 23 | "./node_modules/@types" 24 | ] 25 | }, 26 | "exclude": [ 27 | "node_modules", 28 | "cdk.out" 29 | ] 30 | } 31 | --------------------------------------------------------------------------------