@@ -14,6 +14,7 @@ and let us know if it's not up-to-date (even better, submit a PR with your corr
1414 - [ Step 4: Commit] ( #step-4-commit )
1515 - [ Step 5: Pull Request] ( #step-5-pull-request )
1616 - [ Step 6: Merge] ( #step-6-merge )
17+ - [ Breaking Changes] ( #breaking-changes )
1718- [ Tools] ( #tools )
1819 - [ Main build scripts] ( #main-build-scripts )
1920 - [ Partial build tools] ( #partial-build-tools )
@@ -266,6 +267,143 @@ BREAKING CHANGE: Description of what broke and how to achieve this behavior now
266267* Once approved and tested, a maintainer will squash-merge to master and will use your PR title/description as the
267268 commit message.
268269
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+
269407## Tools
270408
271409The CDK is a big project, and at the moment, all of the CDK modules are mastered in a single monolithic repository
0 commit comments