@@ -14,6 +14,7 @@ and let us know if it's not up-to-date (even better, submit a PR with your corr
14
14
- [ Step 4: Commit] ( #step-4-commit )
15
15
- [ Step 5: Pull Request] ( #step-5-pull-request )
16
16
- [ Step 6: Merge] ( #step-6-merge )
17
+ - [ Breaking Changes] ( #breaking-changes )
17
18
- [ Tools] ( #tools )
18
19
- [ Main build scripts] ( #main-build-scripts )
19
20
- [ Partial build tools] ( #partial-build-tools )
@@ -266,6 +267,143 @@ BREAKING CHANGE: Description of what broke and how to achieve this behavior now
266
267
* Once approved and tested, a maintainer will squash-merge to master and will use your PR title/description as the
267
268
commit message.
268
269
270
+ ## Breaking Changes
271
+
272
+ Whenever you are making changes, there is a chance for those changes to be
273
+ * breaking* existing users of the library. A change is breaking if there are
274
+ programs that customers could have been writing against the current version
275
+ of the CDK, that will no longer "work correctly" with the proposed new
276
+ version of the CDK.
277
+
278
+ Breaking changes are not allowed in * stable* libraries¹. They are permissible
279
+ but still * highly discouraged* in experimental libraries, and require explicit
280
+ callouts in the bodies of Pull Requests that introduce them.
281
+
282
+ > ¹) Note that starting in version 2 of the CDK, the majority of library code will be
283
+ > bundled into a single main CDK library which will be considered stable, and so
284
+ > no code in there can undergo breaking changes.
285
+
286
+ Breaking changes come in two flavors:
287
+
288
+ * API surface changes
289
+ * Behavior changes
290
+
291
+ ### API surface changes
292
+
293
+ This encompasses any changes that affect the shape of the API. Changes that
294
+ will make existing programs fail to compile are not allowed. Typical examples
295
+ of that are:
296
+
297
+ * Renaming classes or methods
298
+ * Adding required properties to a struct that is used as an input to a constructor
299
+ or method. This also includes changing a type from nullable to non-nullable.
300
+ * Removing properties from a struct that is returned from a method, or removing
301
+ properties from a class. This also includes changing a type from non-nullable
302
+ to nullable.
303
+
304
+ To see why the latter is a problem, consider the following class:
305
+
306
+ ``` ts
307
+ class SomeClass {
308
+ public readonly count: number ;
309
+ // ❓ let's say I want to change this to 'count?: number',
310
+ // i.e. make it optional.
311
+ }
312
+
313
+ // Someone could have written the following code:
314
+ const obj = new SomeClass ();
315
+ console .log (obj .count + 1 );
316
+
317
+ // After the proposed change, this code that used to compile fine will now throw:
318
+ console .log (obj .count + 1 );
319
+ // ~~~~~~~~~ Error: Object is possibly 'undefined'.
320
+ ```
321
+
322
+ CDK comes with build tooling to check whether changes you made introduce breaking
323
+ changes to the API surface. In a package directory, run:
324
+
325
+ ``` shell
326
+ $ yarn build
327
+ $ yarn compat
328
+ ```
329
+
330
+ To figure out if the changes you made were breaking. See the section [ API Compatibility
331
+ Checks] ( #api-compatibility-checks ) for more information.
332
+
333
+ #### Dealing with breaking API surface changes
334
+
335
+ If you need to change the type of some API element, introduce a new API
336
+ element and mark the old API element as ` @deprecated ` .
337
+
338
+ If you need to pretend to have a value for the purposes of implementing an API
339
+ and you don't actually have a useful value to return, it is acceptable to make
340
+ the property a ` getter ` and throw an exception (keeping in mind to write error
341
+ messages that will be useful to a user of your construct):
342
+
343
+ ``` ts
344
+ class SomeClass implements ICountable {
345
+ constructor (private readonly _count ? : number ) {
346
+ }
347
+
348
+ public get count(): number {
349
+ if (this ._count === undefined ) {
350
+ // ✅ DO: throw a descriptive error that tells the user what to do
351
+ throw new Error (' This operation requires that a \' count\' is specified when SomeClass is created.' );
352
+ // ❌ DO NOT: just throw an error like 'count is missing'
353
+ }
354
+ return this ._count ;
355
+ }
356
+ }
357
+ ```
358
+
359
+ ### Behavior changes
360
+
361
+ These are changes that do not directly affect the compilation of programs
362
+ written against the previous API, but may change their meaning. In practice,
363
+ even though the user didn't change their code, the CloudFormation template
364
+ that gets synthesized is now different.
365
+
366
+ ** Not all template changes are breaking changes!** Consider a user that has
367
+ created a Stack using the previous version of the library, has updated their
368
+ version of the CDK library and is now deploying an update. A behavior change
369
+ is breaking if:
370
+
371
+ * The update cannot be applied at all
372
+ * The update can be applied but causes service interruption or data loss.
373
+
374
+ Data loss happens when the [ Logical
375
+ ID] ( https://docs.aws.amazon.com/cdk/latest/guide/identifiers.html#identifiers_logical_ids )
376
+ of a stateful resource changes, or one of the [ resource properties that requires
377
+ replacement] ( https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-updating-stacks-update-behaviors.html )
378
+ is modified. In both of these cases, CloudFormation will delete the
379
+ resource, and if it was a stateful resource like a database the data in it is now gone.
380
+
381
+ If a change applies cleanly and does not cause any service interruption, it
382
+ is not breaking. Nevertheless, it might still be wise to avoid those kinds of
383
+ changes as users are understandably wary of unexpected template changes, will
384
+ scrutinize them heavily, and we don't want to cause unnecessary panic and churn
385
+ in our use base.
386
+
387
+ Determining whether or not behavioral changes are breaking requires expertise
388
+ and judgement on the part of the library owner, and testing.
389
+
390
+ #### Dealing with breaking behavior changes
391
+
392
+ Most of the time, behavioral changes will arise because we want to change the
393
+ default value or default behavior of some property (i.e., we want to change the
394
+ interpretation of what it means if the value is missing).
395
+
396
+ If the new behavior is going to be breaking, the user must opt in to it, either by:
397
+
398
+ * Adding a new API element (class, property, method, ...) to have users
399
+ explicitly opt in to the new behavior at the source code level (potentially
400
+ ` @deprecate ` ing the old API element); or
401
+ * Use the [ feature flag] ( #feature-flags ) mechanism to have the user opt in to the new
402
+ behavior without changing the source code.
403
+
404
+ Of these two, the first one is preferred if possible (as feature flags have
405
+ non-local effects which can cause unintended effects).
406
+
269
407
## Tools
270
408
271
409
The CDK is a big project, and at the moment, all of the CDK modules are mastered in a single monolithic repository
0 commit comments