forked from r0light/cna-quality-tool
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathqualitymodel.ts
1976 lines (1948 loc) · 144 KB
/
qualitymodel.ts
1
2
3
4
5
6
7
8
9
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
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
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
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
import { ENDPOINT_TOSCA_EQUIVALENT } from "@/core/entities/endpoint"
import { ENTITIES } from "./entities"
import { LiteratureKey } from "./literature"
type HighLevelQualityAspecSpec = {
name: string,
aspects: { [aspectKey: string]: QualityAspectSpec }
}
type QualityAspectSpec = {
name: string,
description: string
}
const qualityAspects = {
"security": {
"name": "Security",
"aspects": {
"confidentiality": {
"name": "Confidentiality",
"description": "Confidentiality describes to what extent data processed in a system is only accessible to those who actually need it and is otherwise protected from illegitimate access."
},
"integrity": {
"name": "Integrity",
"description": "Integrity describes how well a system is able to prevent unauthorized access or manipulation of functions and data."
},
"nonrepudiation": {
"name": "Non-repudiation",
"description": "Non-repudiation describes to what extent it is possible to prove and reconstruct which actions have taken place in a system."
},
"accountability": {
"name": "Accountability",
"description": "Accountability describes to what extent it is possible in a system to trace back actions that have taken place back to the subject that performed them."
},
"authenticity": {
"name": "Authenticity",
"description": "Authenticity describes how well a system is able to identify a subject and validate its identity as well as claims made by a subject."
}
}
},
"maintainability": {
"name": "Maintainability",
"aspects": {
"modularity": {
"name": "Modularity",
"description": "Modularity describes how well a system is composed of different components, so that a change in one component has a minimal impact on other components."
},
"reusability": {
"name": "Reusability",
"description": "Reusability describes to what extent parts of a system can be used in more than one system."
},
"analyzability": {
"name": "Analyzability",
"description": "Analyzability describes to what extent it is possible to accurately assess the impact of an intended change as well as the extent to which failures can be diagnosed to find their cause or parts that need to be changed can be identified."
},
"modifiability": {
"name": "Modifiability",
"description": "Modifiability describes how well a system can be modified without introducing defects or degrading other qualities of the system."
},
"testability": {
"name": "Testability",
"description": "Testability describes how effective test criteria can be defined and used for a system are to check the intended behavior of a system as well as how facile it is to perform the tests to determine whether the test criteria are met."
},
"simplicity": {
"name": "Simplicity",
"description": "Simplicity describes how well a system is composed of as few components as possible and includes simple instead of complex interrelations to enable a good overview and understanding of the system."
}
}
},
"performanceEfficiency": {
"name": "Performance efficiency",
"aspects": {
"timeBehaviour": {
"name": "Time-behaviour",
"description": "Time-behaviour describes how well a system performs in terms of processing and response times as well as the throughput rate when performing its functions."
},
"resourceUtilization": {
"name": "Resource utilization",
"description": "Resource utilization describes to what extent resources are available and used as required by a system when performing its functions, in terms of storage space needed, CPU utilization, memory usage, or network usage."
},
"capability": {
"name": "Capability",
"description": "Capability describes to which extent the maximum limits of a system meet its requirements, in terms of workload sizes or number of concurrent users."
},
"elasticity": {
"name": "Elasticity",
"description": "Elasticity describes the rapidness and accurateness with which a system is able to adjust its allocated resources to the currently required amount without over- or under-allocation."
}
}
},
"portability": {
"name": "Portability",
"aspects": {
"adaptability": {
"name": "Adaptability",
"description": "Adaptability describes how well and how easy a system can be adapted to be executed on different or evolving software, platforms, environments, or hardware."
},
"installability": {
"name": "Installability",
"description": "Installability describes how well a system can be installed or uninstalled completely and correctly in a specific environment."
},
"replaceability": {
"name": "Replaceability",
"description": "Replaceability describes how well a component or system can replace another component or system for the same purpose in the same environment."
}
}
},
"reliability": {
"name": "Reliability",
"aspects": {
"availability": {
"name": "Availability",
"description": "Availability describes to what extent a system is operational and accessible at any point in time when it is needed."
},
"faultTolerance": {
"name": "Fault tolerance",
"description": "Fault tolerance describes how well a system is able to operate even when facing software or hardware faults."
},
"recoverability": {
"name": "Recoverability",
"description": "Recoverability describes how well a system is able to recover and return to the intended state after an interruption or failure."
},
"maturity": {
"name": "Maturity",
"description": "Maturity describes to what extent a system meets the specified needs for reliability in normal, expected circumstances."
}
}
},
"compatibility": {
"name": "Compatibility",
"aspects": {
"coExistence": {
"name": "Co-existence",
"description": "Co-existence describes how well a system can operate and perform its functions while sharing an environment and resources with other systems and without negatively impacting those other systems."
},
"interoperability": {
"name": "Interoperability",
"description": "Interoperability describes how well two parts of a system or two systems are able to exchange information and to process such exchanged information."
}
}
}
} satisfies { [highLevelAspectKey: string]: HighLevelQualityAspecSpec }
const highLevelAspectKeys = Object.freeze(qualityAspects);
export type HighLevelAspectKey = keyof typeof highLevelAspectKeys;
const qualityAspectKeys = Object.freeze({...qualityAspects.compatibility.aspects, ...qualityAspects.maintainability.aspects, ...qualityAspects.performanceEfficiency.aspects, ...qualityAspects.portability.aspects, ...qualityAspects.reliability.aspects, ...qualityAspects.security.aspects});
export type QualityAspectKey = keyof typeof qualityAspectKeys;
export type CategorySpec = {
name: string
}
const factorCategories = {
"cloudInfrastructure": {
"name": "Cloud Infrastructure"
},
"networkCommunication": {
"name": "Network Communication"
},
"applicationAdministration": {
"name": "Application Administration"
},
"dataManagement": {
"name": "Data Management"
},
"businessDomain": {
"name": "Business Domain"
}
} satisfies {[categoryKey: string]: CategorySpec}
const factorCategoryKeys = Object.freeze(factorCategories);
export type FactorCategoryKey = keyof typeof factorCategoryKeys;
export type ProductFactorSpec = {
name: string,
description: string,
categories: FactorCategoryKey[],
relevantEntities: `${ENTITIES}`[],
applicableEntities: `${ENTITIES}`[],
sources: SourceSpec[],
measures: MeasureKey[]
}
type SourceSpec = {
key: LiteratureKey,
section: string
}
const productFactors = {
"dataEncryptionInTransit": {
"name": "Data encryption in transit",
"description": "Data which is sent or received through a link from one component to or from an endpoint of another component is encrypted so that even when an attacker has access to the network layer, the data is protected.",
"categories": ["networkCommunication"],
"relevantEntities": [ENTITIES.LINK, ENTITIES.ENDPOINT],
"applicableEntities": [ENTITIES.LINK, ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [
{ "key": "Scholl2019", "section": "6 Encrypt Data in Transit" },
{ "key": "Indrasiri2021", "section": "2 Security (Use TLS for synchronous communications)" }
],
"measures": ["ratioOfEndpointsSupportingSsl", "ratioOfExternalEndpointsSupportingTls", "ratioOfSecuredLinks"]
},
"secretsManagement": {
"name": "Secrets management",
"description": "Secrets (e.g. passwords, access tokens, encryption keys) which allow access to other components or data are managed specifically to make sure they stay confidential and only authorized components or persons can access them. Managed in this case refers to where and how secrets are stored and how components which need them can access them.",
"categories": ["applicationAdministration", "cloudInfrastructure", "dataManagement"],
"relevantEntities": [ENTITIES.BACKING_SERVICE, ENTITIES.INFRASTRUCTURE, ENTITIES.BACKING_DATA, ENTITIES.COMPONENT],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": []
},
"isolatedSecrets": {
"name": "Isolated secrets",
"description": "Secrets (e.g. passwords, access tokens, encryption keys) are not stored in component artifacts (e.g. binaries, images). Instead, secrets are stored for example in the deployment environment and components are given access at runtime only to those secrets which they actually need and only when they need it.",
"categories": ["applicationAdministration"],
"relevantEntities": [ENTITIES.BACKING_SERVICE, ENTITIES.INFRASTRUCTURE, ENTITIES.BACKING_DATA, ENTITIES.COMPONENT],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Never Store Secrets or Configuration Inside an Image" }, { "key": "Adkins2020", "section": "14 Don't Check In Secrets" }],
"measures": []
},
"secretsStoredInSpecializedServices": {
"name": "Secrets stored in specialized services",
"description": "A dedicated backing service to host secrets (e.g. passwords, access tokens, encryption keys) exists. All secrets required by a system are hosted in this backing service where they can also be managed (for example they can be revoked or replaced with updated secrets). Components fetch secrets from this backing services in a controlled way when they need them.",
"categories": ["cloudInfrastructure", "dataManagement"],
"relevantEntities": [ENTITIES.BACKING_SERVICE, ENTITIES.BACKING_DATA, ENTITIES.COMPONENT],
"applicableEntities": [ENTITIES.SERVICE, ENTITIES.INFRASTRUCTURE, ENTITIES.BACKING_SERVICE, ENTITIES.BACKING_DATA],
"sources": [{ "key": "Scholl2019", "section": "6 Securely Store All Secrets" },
{ "key": "Arundel2019", "section": "10 Kubernetes Secrets" }
],
"measures": []
},
"accessRestriction": {
"name": "Access restriction",
"description": "Access to components is restricted to those who actually need it. Also, within a system access controls are put in place to have multiple layers of defense. A dedicated component to manage access policies can be used.",
"categories": ["networkCommunication", "applicationAdministration"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.ENDPOINT, ENTITIES.BACKING_SERVICE],
"applicableEntities": [ENTITIES.SYSTEM],
"sources": [],
"measures": []
},
"leastPrivilegedAccess": {
"name": "Least-privileged access",
"description": "Access to endpoints is given as restrictive as possible so that only components who really need it can access an endpoint.",
"categories": ["networkCommunication", "applicationAdministration"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.ENDPOINT],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.SYSTEM],
"sources": [{ "key": "Scholl2019", "section": "6 Grant Least-Privileged Access" }, { "key": "Arundel2019", "section": "11 Access Control and Permissions" }],
"measures": []
},
"accessControlManagementConsistency": {
"name": "Access control management consistency",
"description": "Access control for endpoints is managed in a consistent way, that means for example always the same format is used for access control lists or a single account directory in a dedicated backing service exists for all components. Access control configurations can then be made always in the same known style and only in a dedicated place. Based on such a consistent access control configuration, also verifications can be performed to ensure that access restrictions are implemented correctly.",
"categories": ["applicationAdministration", "networkCommunication"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.ENDPOINT, ENTITIES.BACKING_SERVICE],
"applicableEntities": [ENTITIES.SYSTEM],
"sources": [{ "key": "Adkins2020", "section": "6 Access Control (Access control managed by framework)" }, { "key": "Goniwada2021", "section": "9 Policy as Code (consistently describe your security policies in form of code)" }],
"measures": ["ratioOfEndpointsThatSupportTokenBasedAuthentication", "ratioOfEndpointsThatSupportApiKeys", "ratioOfEndpointsThatSupportPlaintextAuthentication", "ratioOfEndpointsThatAreIncludedInASingleSignOnApproach"]
},
"accountSeparation": {
"name": "Account separation",
"description": "Components are separated by assigning them different accounts. Ideally each component has an individual account. Through this, it is possible to trace which component performed which actions and it is possible to restrict access to other components on a fine-grained level, so that for example in the case of an attack, compromised components can be isolated based on their account.",
"categories": ["applicationAdministration", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Use Separate Accounts/Subscriptions/Tenants”" }, { "key": "Adkins2020", "section": "8 Role separation”(let different services run with different roles to restrict access)" }, { "key": "Adkins2020", "section": "8 “Location separation (use different roles for a service in different locations to limit attack impacts)" }],
"measures": []
},
"authenticationDelegation": {
"name": "Authentication delegation",
"description": "The verification of an entity for authenticity, for example upon a request, is delegated to a dedicated backing service. This concern is therefore removed from individual components so that their focus can remain on business functionalities while for example different authentication options can be managed in one place only.",
"categories": ["applicationAdministration", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.BACKING_SERVICE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Use Federated Identity Management" }, { "key": "Goniwada2021", "section": "9 Decentralized Identity" }],
"measures": []
},
"serviceOrientation": {
"name": "Service-orientation",
"description": "Cloud-native applications realize modularity by being service-oriented, that means the system is decomposed into services encapsulating specific functionalities and communicating with each other only through specific interfaces. Commonly, a microservices architectural style is used.",
"categories": ["businessDomain", "dataManagement", "networkCommunication"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.DATA_AGGREGATE, ENTITIES.ENDPOINT, ENTITIES.LINK],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT],
"sources": [],
"measures": []
},
"limitedFunctionalScope": {
"name": "Limited functional scope",
"description": "Each service covers only a limited, but cohesive functional scope to keep services manageable.",
"categories": ["businessDomain", "dataManagement"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.ENDPOINT, ENTITIES.LINK],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.SERVICE, ENTITIES.ENDPOINT],
"sources": [{ "key": "Reznik2019", "section": "9 Microservices Architecture" }, { "key": "Adkins2020", "section": "7 Use Microservices" }, { "key": "Goniwada2021", "section": "3 Polylithic Architecture Principle (Build separate services for different business functionalitites) " }],
"measures": ["totalServiceInterfaceCohesion", "cohesivenessOfService", "cohesionOfAServiceBasedOnOtherEndpointsCalled", "lackOfCohesion", "averageLackOfCohesion", "serviceSize", "unreachableEndpointCount"]
},
"limitedDataScope": {
"name": "Limited data scope",
"description": "The number of data aggregates that are processed in a service is limited to those which need to be administrated together, for example to fulfill data consistency requirements. The aim is to keep the functional scope of a service cohesive. Data aggregates for which consistency requirements can be relaxed might be distributed over separate services.",
"categories": ["businessDomain", "dataManagement"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.ENDPOINT, ENTITIES.DATA_AGGREGATE],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.SERVICE, ENTITIES.ENDPOINT],
"sources": [],
"measures": ["dataAggregateScope", "serviceInterfaceDataCohesion", "cohesionBetweenEndpointsBasedOnDataAggregateUsage", "resourceCount"]
},
"limitedEndpointScope": {
"name": "Limited endpoint scope",
"description": "To keep the functional scope of services limited, the number of endpoints of a service is limited to a cohesive set of endpoints that provide related operations.",
"categories": ["businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.ENDPOINT, ENTITIES.LINK],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.SERVICE, ENTITIES.ENDPOINT],
"sources": [],
"measures": ["numberOfProvidedSynchronousAndAsynchronousEndpoints", "numberOfSynchronousEndpointsOfferedByAService", "serviceInterfaceUsageCohesion", "distributionOfSynchronousCalls", "cohesionOfEndpointsBasedOnInvocationByOtherServices", "unusedEndpointCount"]
},
"commandQueryResponsibilitySegregation": {
"name": "Command Query Responsibility Segregation",
"description": "Endpoints for read (query) and write (command) operations on the same data aggregate are separated into different services. Changes to these operations can then be made independently and also different representations for data aggregates can be used. That way operations on data aggregates can be adjusted to differing usage patterns, different format requirements, or if they are changed for different reasons.",
"categories": ["networkCommunication", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.ENDPOINT, ENTITIES.LINK],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "4.4" }, { "key": "Richardson2019", "section": "7.2 Using the CQRS pattern" }, { "key": "Bastani2017", "section": "12 CQRS (Command Query Responsibility Segregation)" }, { "key": "Indrasiri2021", "section": "4 Command and Query Responsibility Segregation Pattern" }, { "key": "Goniwada2021", "section": "4 Command and Query Responsibility Segregation Pattern" }],
"measures": ["numberOfReadEndpointsProvidedByAService", "numberOfWriteEndpointsProvidedByAService"]
},
"separationByGateways": {
"name": "Separation by gateways",
"description": "Individual components or groups of components are separated through gateways. That means communication is proxied and controlled at specific gateway components. It also abstracts one part of a system from another so that it can be reused by different components without needing direct links to components that actually provide the needed functionality. This way, communication can also be redirected when component endpoints change without changing the gateway endpoint. Also incoming communication from outside of a system can be directed at external endpoints of a central component (the gateway).",
"categories": ["networkCommunication", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.PROXY_BACKING_SERVICE, ENTITIES.ENDPOINT, ENTITIES.LINK],
"applicableEntities": [ENTITIES.SYSTEM],
"sources": [{ "key": "Davis2019", "section": "10.2" },
{ "key": "Richardson2019", "section": "8.2" }, { "key": "Bastani2017", "section": "8 Edge Services: Filtering and Proxying with Netflix Zuul" }, { "key": "Indrasiri2021", "section": "7 API Gateway Pattern" }, { "key": "Indrasiri2021", "section": "7 API Microgateway Pattern (Smaller API microgateways to avoid having a monolithic API gateway)" }, { "key": "Goniwada2021", "section": "4 “Mediator” (Use a mediator pattern between clients and servers)" }],
"measures": ["externallyAvailableEndpoints", "centralizationOfExternallyAvailableEndpoints", "apiCompositionUtilizationMetric", "ratioOfRequestTracesThroughGateway"]
},
"isolatedState": {
"name": "Isolated state",
"description": "Services are structured by clearly separating stateless from stateful services. Stateful services should be reduced to a minimum. That way, state is isolated within these specifically stateful services which can be managed accordingly. The majority of stateless services is easier to deploy and modify.",
"categories": ["dataManagement", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.DATA_AGGREGATE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.STORAGE_BACKING_SERVICE],
"sources": [{ "key": "Goniwada2021", "section": "3 Coupling (Services should be as loosely coupled as possible)" }],
"measures": []
},
"mostlyStatelessServices": {
"name": "Mostly stateless services",
"description": "Most services in a system are kept stateless, that means not requiring durable disk space on the infrastructure that they run on. Stateless services can be replaced, updated or replicated at any time. Stateful services are reduced to a minimum.",
"categories": ["dataManagement", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.DATA_AGGREGATE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "5.4" }, { "key": "Scholl2019", "section": "6 “Design Stateless Services That Scale Out" }, { "key": "Goniwada2021", "section": "3 Be Smart with State Principle, 5 Stateless Services" }],
"measures": ["ratioOfStateDependencyOfEndpoints", "ratioOfStatefulComponents", "ratioOfStatelessComponents", "degreeToWhichComponentsAreLinkedToStatefulComponents"]
},
"specializedStatefulServices": {
"name": "Specialized stateful services",
"description": "For stateful components, that means components that do require durable disk space on the infrastructure that they run on, specialized software or frameworks are used that can handle distributed state by replicating it over several components or component instances while still ensuring consistency requirements for that state.",
"categories": ["dataManagement", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.STORAGE_BACKING_SERVICE, ENTITIES.DATA_AGGREGATE],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "5.4" }, { "key": "Ibryam2020", "section": "11 “Stateful Service”" }],
"measures": []
},
"looseCoupling": {
"name": "Loose coupling",
"description": "In cloud-native applications communication between components is loosely coupled in time, location, and language to achieve greater independence.",
"categories": ["businessDomain", "networkCommunication"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT],
"sources": [],
"measures": []
},
"asynchronousCommunication": {
"name": "Asynchronous communication",
"description": "Asynchronous links (e.g. based on messaging backing services) are preferred for the communication between components. That way, components are decoupled in time meaning that not all linked components need to be available at the same time for a successful communication. Additionally, callers do not await a response.",
"categories": ["networkCommunication", "businessDomain"],
"relevantEntities": [ENTITIES.LINK, ENTITIES.ENDPOINT, ENTITIES.REQUEST_TRACE, ENTITIES.BROKER_BACKING_SERVICE,],
"applicableEntities": [ENTITIES.LINK, ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "4.2" }, { "key": "Scholl2019", "section": "6 Prefer Asynchronous Communication" }, { "key": "Richardson2019", "section": "3.3.2, 3.4 Using asynchronous messaging to improve availability" }, { "key": "Indrasiri2021", "section": "3 Service Choreography Pattern" }, { "key": "Ruecker2021", "section": "9 Asynchronous Request/Response (Use asynchronous communication to make services more robust)" }, { "key": "Goniwada2021", "section": "4 Asynchronous Nonblocking I/O" }],
"measures": ["numberOfAsynchronousEndpointsOfferedByAService", "numberOfSynchronousOutgoingLinks", "numberOfAsynchronousOutgoingLinks", "ratioOfAsynchronousOutgoingLinks", "degreeOfAsynchronousCommunication", "asynchronousCommunicationUtilization"]
},
"communicationPartnerAbstraction": {
"name": "Communication partner abstraction",
"description": "Communication via links is not based on specific communication partners (specific components) but abstracted based on the content of communication. An example is event-driven communication where events are published to channels without the publisher knowing which components receive events and events can therefore also be received by components which are created later in time.",
"categories": ["networkCommunication"],
"relevantEntities": [ENTITIES.LINK, ENTITIES.BROKER_BACKING_SERVICE, ENTITIES.ENDPOINT, ENTITIES.REQUEST_TRACE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.LINK, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Richardson2019", "section": "6 Event-driven communication" }, { "key": "Ruecker2021", "section": "8: Event-driven systems “event chains emerge over time and therefore lack visibility." }],
"measures": ["eventSourcingUtilizationMetric"]
},
"persistentCommunication": {
"name": "Persistent communication",
"description": "Links persist messages which have been sent (e.g. based on messaging backing services). That way, components are decoupled, because components need not yet exist at the time a message is sent, but can still receive a message. Communication can also be repeated, because persisted messages can be retrieved again.",
"categories": ["networkCommunication"],
"relevantEntities": [ENTITIES.LINK, ENTITIES.BROKER_BACKING_SERVICE, ENTITIES.ENDPOINT],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.LINK, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Indrasiri2021", "section": "5 Event Sourcing Pattern: Log-based message brokers" }],
"measures": ["serviceInteractionViaBackingService", "eventSourcingUtilizationMetric"]
},
"usageOfExistingSolutionsForNonCoreCapabilities": {
"name": "Usage of existing solutions for non-core capabilities",
"description": "For non-core capabilities readily available solutions are used. This means solutions which are based on a standard or a specification, are widely adopted and ideally open source so that their well-functioning is ensured by a broader community. Non-core capabilities include interface technologies or protocols for endpoints, infrastructure technologies (for example container orchestration engines), and software for backing services. That way capabilities don't need to self-implemented and existing integration options can be used.",
"categories": ["cloudInfrastructure", "applicationAdministration"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.BACKING_SERVICE, ENTITIES.STORAGE_BACKING_SERVICE, ENTITIES.BROKER_BACKING_SERVICE, ENTITIES.PROXY_BACKING_SERVICE, ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE],
"sources": [{ "key": "Reznik2019", "section": "9 Avoid Reinventing the Wheel" }, { "key": "Adkins2020", "section": "12 Frameworks to Enforce Security and Reliability" }],
"measures": []
},
"standardization": {
"name": "Standardization",
"description": "By using standardized technologies within components, for interfaces, and especially for the infrastructure, backing services and other non-business concerns, reusability can be increased and the effort to develop additional functionality which integrates with existing components can be reduced.",
"categories": ["applicationAdministration"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.ENDPOINT, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": []
},
"componentSimilarity": {
"name": "Component similarity",
"description": "The more similar components are, the easier it is for developers to work on an unfamiliar component. Furthermore, similar components can be more easily integrated and maintained in the same way. Similarity considers mainly the libraries and technologies used for implementing service logic and service endpoints, as well as their deployment.",
"categories": ["applicationAdministration"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE, ENTITIES.INFRASTRUCTURE],
"sources": [{ "key": "Reznik2019", "section": "9 Reference Architecture" }],
"measures": []
},
"automatedMonitoring": {
"name": "Automated Monitoring",
"description": "Cloud-native applications enable monitoring at various levels (business functionalities in services, backing-service functionalities, infrastructure) in an automated fashion to enable observable and autonomous reactions to changing system conditions.",
"categories": ["applicationAdministration", "businessDomain", "networkCommunication", "dataManagement"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.BACKING_SERVICE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.SERVICE, ENTITIES.INFRASTRUCTURE],
"sources": [{ "key": "Goniwada2021", "section": "3 High Observability Principle" }],
"measures": ["ratioOfInfrastructureNodesThatSupportMonitoring", "ratioOfComponentsThatSupportMonitoring"]
},
"consistentCentralizedLogging": {
"name": "Consistent centralized logging",
"description": "Logging functionality, specifically the automated collection of logs, is concentrated in a centralized backing service which combines and stores logs from the components of a system. The logs are kept consistent regarding their format and level of granularity. In the backing service also log analysis functionalities are provided, for example by also enabling a correlation of logs from different components.",
"categories": ["applicationAdministration", "dataManagement"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.BACKING_DATA, ENTITIES.BACKING_SERVICE, ENTITIES.LINK],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "11.1" }, { "key": "Scholl2019", "section": "6 Use a Unified Logging System" }, { "key": "Scholl2019", "section": "6 Common and Structured Logging Format" }, { "key": "Richardson2019", "section": "11.3.2 Applying the Log aggregation pattern" }, { "key": "Reznik2019", "section": "10 Observability" }, { "key": "Garrison2017", "section": "7 Monitoring and Logging" }, { "key": "Adkins2020", "section": "15 Design your logging to be immutable" }, { "key": "Arundel2019", "section": "15 Logging" }, { "key": "Bastani2017", "section": "13 Application Logging" }, { "key": "Bastani2017", "section": "13 Audit Events (capture events for audits, like failed logins etc)" }, { "key": "Ruecker2021", "section": "11 Custom Centralized Monitoring" }, { "key": "Goniwada2021", "section": "19 One Source of Truth" }],
"measures": ["ratioOfComponentsOrInfrastructureNodesThatExportLogsToACentralService"]
},
"consistentCentralizedMetrics": {
"name": "Consistent centralized metrics",
"description": "Metrics gathering and calculation functionality for monitoring purposes is concentrated in a centralized component which combines, aggregates and stores metrics from the components of a system. The metrics are kept consistent regarding their format and support multiple levels of granularity. In the backing service also metric analysis functionalities are provided, for example by also enabling correlations of metrics.",
"categories": ["applicationAdministration", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.BACKING_DATA, ENTITIES.BACKING_SERVICE, ENTITIES.LINK],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "11.2" }, { "key": "Scholl2019", "section": "6 Tag Your Metrics Appropriately" }, { "key": "Richardson2019", "section": "11.3.4 Applying the Applications metrics pattern" }, { "key": "Garrison2017", "section": "7 Monitoring and Logging, Metrics Aggregation" }, { "key": "Reznik2019", "section": "10 Observability" }, { "key": "Arundel2019", "section": "15 Metrics help predict problems" }, { "key": "Arundel2019", "section": "15 Logging" }, { "key": "Bastani2017", "section": "13 Metrics" }, { "key": "Arundel2019", "section": "16 The RED Pattern (common metrics you should have for services" }, { "key": "Arundel2019", "section": "16 The USE Pattern (common metrics for resources" }, { "key": "Goniwada2021", "section": "19 One Source of Truth" }],
"measures": ["ratioOfComponentsOrInfrastructureNodesThatExportMetrics", "ratioOfComponentsOrInfrastructureNodesThatEnablePerformanceAnalytics"]
},
"distributedTracingOfInvocations": {
"name": "Distributed tracing of invocations",
"description": "For request traces that span multiple components in a system, distributed tracing is enabled so that traces based on correlation IDs are captured automatically and stored in a backing service where they can be analyzed and problems within request traces can be clearly attributed to single components.",
"categories": ["applicationAdministration", "networkCommunication"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.BACKING_SERVICE, ENTITIES.REQUEST_TRACE],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "11.3" }, { "key": "Scholl2019", "section": "6 Use Correlation IDs" }, { "key": "Richardson2019", "section": "11.3.3 AUsing the Distributed tracing pattern" }, { "key": "Garrison2017", "section": "7 Debugging and Tracing" }, { "key": "Reznik2019", "section": "10 Observability" }, { "key": "Arundel2019", "section": "15 Tracing" }, { "key": "Bastani2017", "section": "13 Distributed Tracing" }, { "key": "Ruecker2021", "section": "11 Observability and Distributed Tracing Tools (Use Distributed Tracing)" }, { "key": "Goniwada2021", "section": "19 One Source of Truth" }],
"measures": ["distributedTracingSupport"]
},
"healthAndReadinessChecks": {
"name": "Health and readiness Checks",
"description": "All components in a system offer health and readiness checks so that unhealthy components can be identified and communication can be restricted to happen only between healthy and ready components. Health and readiness checks can for example be dedicated endpoints of components which can be called regularly to check a component. That way, also an up-to-date holistic overview of the health of a system is enabled.",
"categories": ["applicationAdministration"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.ENDPOINT],
"applicableEntities": [ENTITIES.COMPONENT, ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Implement Health Checks and Readiness Checks" }, { "key": "Ibryam2020", "section": "4 Health Probe" }, { "key": "Richardson2019", "section": "11.3.1 Using the Health check API pattern" }, { "key": "Garrison2017", "section": "7 State Management" }, { "key": "Arundel2019", "section": "5 Liveness Probes" }, { "key": "Arundel2019", "section": "5 Readiness Probes" }, { "key": "Bastani2017", "section": "13 Health Checks" }, { "key": "Indrasiri2021", "section": "1 Why container orchestration?, Health monitoring" }, { "key": "Goniwada2021", "section": "4 Fail Fast, 16 Health Probe" }],
"measures": ["ratioOfServicesThatProvideHealthEndpoints"]
},
"automatedInfrastructureProvisioning": {
"name": "Automated infrastructure provisioning",
"description": "Infrastructure provisioning should be automated based on component requirements which are either stated explicitly or inferred from the component which should be deployed. The infrastructure and tools used should require only minimal manual effort. Ideally it should be combined with continuous delivery processes so that no further interaction is needed for a component deployment.",
"categories": ["cloudInfrastructure", "applicationAdministration"],
"relevantEntities": [ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.INFRASTRUCTURE],
"sources": [{ "key": "Reznik2019", "section": "10 Automated Infrastructure" }, { "key": "Goniwada2021", "section": "5 Automation" }],
"measures": []
},
"useInfrastructureAsCode": {
"name": "Use infrastructure as code",
"description": "The infrastructure requirements and constraints of a system are defined (coded) independently of the actual runtime in a storable format. That way a defined infrastructure can be automatically provisioned repeatedly and ideally also on different underlying infrastructures (cloud providers) based on the stored infrastructure definition. Infrastructure provisioning and configuration operations are not performed manually via an interface of a cloud provider.",
"categories": ["cloudInfrastructure", "applicationAdministration"],
"relevantEntities": [ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.INFRASTRUCTURE],
"sources": [{ "key": "Scholl2019", "section": "6 Describe Infrastructure Using Code" }, { "key": "Goniwada2021", "section": "16 Declarative Deployment, 17 What Is Infrastructure as Code?" }],
"measures": ["linesOfCodeForDeploymentConfiguration"]
},
"dynamicScheduling": {
"name": "Dynamic scheduling",
"description": "Resource provisioning to deployed components is dynamic and automated so that every component is ensured to have the resources it needs and only that many resources are provisioned wich are really needed at the same time. This requires dynamic adjustments to resources to adapt to changing environments. This capability should be part of the used infrastructure.",
"categories": ["applicationAdministration", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.INFRASTRUCTURE],
"sources": [{ "key": "Reznik2019", "section": "10 Dynamic Scheduling" }, { "key": "Garrison2017", "section": "7 Resource Allocation and Scheduling" }, { "key": "Ibryam2020", "section": "6 Automated Placement" }, { "key": "Indrasiri2021", "section": "1 Why container orchestration?; Resource Management" }, { "key": "Indrasiri2021", "section": "1 Why container orchestration?; Automatic provisioning" }, { "key": "Goniwada2021", "section": "16 Automated Placement" }],
"measures": []
},
"serviceIndependence": {
"name": "Service independence",
"description": "Services are as independent as possible throughout their lifecycle, that means development, operation, and evolution. Changes to one service have a minimum impact on other services.",
"categories": ["businessDomain", "networkCommunication", "cloudInfrastructure", "applicationAdministration", "dataManagement"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.LINK, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.SERVICE],
"sources": [{ "key": "Goniwada2021", "section": "3 Decentralize Everything Principle (Decentralize deployment, governance)" }],
"measures": []
},
"lowCoupling": {
"name": "Low coupling",
"description": "The coupling in a system is low in terms of links between components. Each link represents a dependency and therefore decreases service independence.",
"categories": ["businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.ENDPOINT, ENTITIES.DATA_AGGREGATE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.SERVICE],
"sources": [],
"measures": ["numberOfLinksPerComponent", "numberOfConsumedEndpoints", "incomingOutgoingRatioOfAComponent", "ratioOfOutgoingLinksOfAService", "couplingDegreeBasedOnPotentialCoupling", "interactionDensityBasedOnComponents", "interactionDensityBasedOnLinks", "serviceCouplingBasedOnEndpointEntropy", "systemCouplingBasedOnEndpointEntropy", "modularityQualityBasedOnCohesionAndCoupling", "combinedMetricForIndirectDependency", "servicesInterdependenceInTheSystem", "indirectInteractionDensity", "averageNumberOfDirectlyConnectedServices", "numberOfComponentsThatAreLinkedToAComponent", "numberOfComponentsAComponentIsLinkedTo", "numberOfLinksBetweenTwoServices", "aggregateSystemMetricToMeasureServiceCoupling", "numberOfComponentsAComponentIsLinkedToRelativeToTheTotalAmountOfComponents", "degreeOfCouplingInASystem", "serviceCouplingBasedOnDataExchangeComplexity", "simpleDegreeOfCouplingInASystem", "directServiceSharing", "transitivelySharedServices", "ratioOfSharedNonExternalComponentsToNonExternalComponents", "ratioOfSharedDependenciesOfNonExternalComponentsToPossibleDependencies", "degreeOfDependenceOnOtherComponents", "averageSystemCoupling", "couplingOfServicesBasedOnUsedDataAggregates", "couplingOfServicesBasedServicesWhichCallThem", "couplingOfServicesBasedServicesWhichAreCalledByThem", "couplingOfServicesBasedOnAmountOfRequestTracesThatIncludeASpecificLink", "couplingOfServicesBasedTimesThatTheyOccurInTheSameRequestTrace"]
},
"functionalDecentralization": {
"name": "Functional decentralization",
"description": "Business functionality is decentralized over the system as a whole to separate unrelated functionalities from each other and make components more independent.",
"categories": ["businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.ENDPOINT, ENTITIES.REQUEST_TRACE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": ["conceptualModularityQualityBasedOnDataAggregateCohesionAndCoupling", "cyclicCommunication", "numberOfSynchronousCycles", "relativeImportanceOfTheService", "extentOfAggregationComponents", "systemCentralization", "densityOfAggregation", "aggregatorCentralization", "dataAggregateConvergenceAcrossComponents", "serviceCriticality", "ratioOfCyclicRequestTraces", "numberOfPotentialCyclesInASystem"]
},
"limitedRequestTraceScope": {
"name": "Limited request trace scope",
"description": "A request that requires the collaboration of several services is still limited to as few services as possible. Otherwise, the more services are part of a request trace the more dependent they are on each other.",
"categories": ["businessDomain", "networkCommunication"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.ENDPOINT, ENTITIES.REQUEST_TRACE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": ["maximumLengthOfServiceLinkChainPerRequestTrace", "maximumNumberOfServicesWithinARequestTrace", "numberOfRequestTraces", "averageComplexityOfRequestTraces", "requestTraceComplexity", "requestTraceLength", "numberOfCyclesInRequestTraces"]
},
"logicalGrouping": {
"name": "Logical grouping",
"description": "Services are logically grouped so that services which are related (for example by having many links or processing the same data aggregates) are in the same group, but services which are more independent are separated in different groups. That way a separation can also be achieved on the network and infrastructure level by separating service groups more strictly, such as having different subnets for such logical groups or not letting different groups run on the same infrastructure. Potential impacts of a compromised or misbehaving service can therefore be reduced to the group to which it belongs but other groups are ideally unaffected.",
"categories": ["cloudInfrastructure", "applicationAdministration", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.REQUEST_TRACE, ENTITIES.NETWORK],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Use Namespaces to Organize Services in Kubernetes" }, { "key": "Arundel2019", "section": "5 Using Namespaces" }, { "key": "Indrasiri2021", "section": "1 Why container orchestration?; Componentization and isolation" }],
"measures": []
},
"backingServiceDecentralization": {
"name": "Backing service decentralization",
"description": "Different backing services are assigned to different components. That way, a decentralization is achieved. For example, instead of one message broker for a whole system, several message brokers can be used, each for a group of components that are interrelated. A problem in one messaging broker has an impact on only those components using it, but not on components having separate message brokers.",
"categories": ["applicationAdministration", "cloudInfrastructure", "dataManagement"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.BACKING_SERVICE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.SERVICE, ENTITIES.BACKING_SERVICE],
"sources": [{ "key": "Indrasiri2021", "section": "4 Decentralized Data Management (decentralized data leads to higher service independence while centralized data leads to higher consistency.)" }, { "key": "Indrasiri2021", "section": "4 Data Service Pattern (As having a negative impact because multiple services should not access the same data);" }, { "key": "Ruecker2021", "section": "2 Different Workflow Engines for different services" }, { "key": "Goniwada2021", "section": "5 Distributed State, Decentralized Data" }],
"measures": ["degreeOfStorageBackendSharing", "ratioOfStorageBackendSharing", "sharedStorageBackingServiceInteractions", "databaseTypeUtilization", "numberOfServiceConnectedToStorageBackingService"]
},
"addressingAbstraction": {
"name": "Addressing abstraction",
"description": "In a link from one component to another the specific addresses for reaching the other component is not used, but instead an abstract address is used. That way, the specific addresses of components can be changed without impacting the link between components. This can be achieved for example through service discovery where components are addressed through abstract service names and specific addresses are resolved through service discovery which can be implemented in the infrastructure or a backing service.",
"categories": ["networkCommunication"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.BACKING_SERVICE, ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.LINK, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "8.3" }, { "key": "Ibryam2020", "section": "12 Service Discovery" }, { "key": "Richardson2019", "section": "Using service discovery" }, { "key": "Garrison2017", "section": "7 Service Discovery" }, { "key": "Indrasiri2021", "section": "3 Service Registry and Discovery Pattern" }, { "key": "Bastani2017", "section": "7 Routing (Use service discovery with support for health checks and respect varying workloads)" }, { "key": "Indrasiri2021", "section": "3 Service Abstraction Pattern (Use an abstraction layer in front of services (for example Kubernetes Service))" }, { "key": "Goniwada2021", "section": "4 Service Discovery" }],
"measures": ["serviceDiscoveryUsage"]
},
"sparsity": {
"name": "Sparsity",
"description": "The more sparse a system is, the less components there are which need to be operated and maintained by the developers of a system. This covers all types of components, such as services, backing services, storage backing services, and also the infrastructure.",
"categories": ["applicationAdministration", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.ENDPOINT, ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM],
"sources": [],
"measures": ["averageNumberOfEndpointsPerService", "numberOfDependencies", "numberOfVersionsPerService", "concurrentlyAvailableVersionsComplexity", "serviceSupportForTransactions", "numberOfComponents"]
},
"operationOutsourcing": {
"name": "Operation outsourcing",
"description": "By outsourcing the operation of infrastructure and components to a cloud provider or other vendor, the operation is simplified because responsibility is transferred. Furthermore, costs can be made more flexible because providers and vendors can provide a usage-based pricing.",
"categories": ["applicationAdministration", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE],
"sources": [],
"measures": ["ratioOfProviderManagedComponentsAndInfrastructure"]
},
"managedInfrastructure": {
"name": "Managed infrastructure",
"description": "Infrastructure such as basic computing, storage or network resources, but potentially also software infrastructure (for example a container orchestration engine) is managed by a cloud provider who is responsible for a stable functioning and up-to-date functionalities. The more infrastructure is managed, the more operational responsibility is transferred. This will also be reflected in the costs which are then calculated more on usage-based pricing schemes.",
"categories": ["applicationAdministration", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": []
},
"managedBackingServices": {
"name": "Managed backing services",
"description": "Backing services that provide non-business functionality are operated and managed by vendors who are responsible for a stable functioning and up-to-date functionalities. Operational responsibility is transferred which is also reflected in the costs which are then calculated more on usage-based pricing schemes.",
"categories": ["applicationAdministration", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.BACKING_SERVICE, ENTITIES.BROKER_BACKING_SERVICE, ENTITIES.PROXY_BACKING_SERVICE, ENTITIES.STORAGE_BACKING_SERVICE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Use Managed Databases and Analytics Services" }, { "key": "Arundel2019", "section": "15 Don't build your own monitoring infrastructure (Use an external monitoring service)" }, { "key": "Bastani2017", "section": "10 managed and automated messaging system (operating your own messaging system increases operational overhead, better use a system managed by a platform)" }],
"measures": []
},
"replication": {
"name": "Replication",
"description": "Business logic and needed data is replicated at various points in a system so that latencies can be minimized and requests can be distributed for fast request handling.",
"categories": ["applicationAdministration", "dataManagement", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.DATA_AGGREGATE, ENTITIES.DEPLOYMENT_MAPPING, ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT],
"sources": [],
"measures": []
},
"serviceReplication": {
"name": "Service replication",
"description": "Services and therefore their provided functionalities are replicated across different locations so that the latency for accesses from different locations is minimized and the incoming load can be distributed among replicas.",
"categories": ["applicationAdministration", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.SYSTEM, ENTITIES.SERVICE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.SERVICE, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": ["amountOfRedundancy", "serviceReplicationLevel", "medianServiceReplication", "smallestReplicationValue"]
},
"horizontalDataReplication": {
"name": "Horizontal data replication",
"description": "Data is replicated horizontally, that means duplicated across several instances of a storage backing service so that a higher load can be handled and replicas closer to the service where data is needed can be used to reduce latency.",
"categories": ["applicationAdministration", "dataManagement"],
"relevantEntities": [ENTITIES.STORAGE_BACKING_SERVICE, ENTITIES.DATA_AGGREGATE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE, ENTITIES.STORAGE_BACKING_SERVICE ],
"sources": [{ "key": "Scholl2019", "section": "6 Use Data Partitioning and Replication for Scale" }, { "key": "Goniwada2021", "section": "4 Data Replication" }],
"measures": ["storageReplicationLevel"]
},
"verticalDataReplication": {
"name": "Vertical data replication",
"description": "Data is replicated vertically, that means across a request trace so that it is available closer to where a request initially comes in. Typically caching is used for vertical data replication.",
"categories": ["applicationAdministration", "dataManagement"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.DATA_AGGREGATE, ENTITIES.REQUEST_TRACE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE, ENTITIES.STORAGE_BACKING_SERVICE ],
"sources": [{ "key": "Scholl2019", "section": "6 Use Caching" }, { "key": "Bastani2017", "section": "9 Caching (Use an In-Memory cache for queries to relieve datastore from traffic; replication into faster data storage)" }, { "key": "Indrasiri2021", "section": "4 Caching Pattern" }],
"measures": ["ratioOfCachedDataAggregates", "dataReplicationAlongRequestTrace"]
},
"shardedDataStoreReplication": {
"name": "Sharded data store replication",
"description": "Data storage is sharded, that means data is split into several storage backing service instances by a certain strategy so that requests can be distributed across shards to increase performance. One example strategy could be to shard data geographically, that means user data from one location is stored in one shard while user data from another location is stored in a different shard. One storage backing service instance is then less likely to be overloaded with requests, because the number of potential requests is limited by the amount of data in that instance.",
"categories": ["applicationAdministration", "dataManagement"],
"relevantEntities": [ENTITIES.STORAGE_BACKING_SERVICE, ENTITIES.DATA_AGGREGATE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE, ENTITIES.STORAGE_BACKING_SERVICE ],
"sources": [{ "key": "Indrasiri2021", "section": "4 Data Sharding Pattern" }, { "key": "Goniwada2021", "section": "4 Data Partitioning Pattern" }],
"measures": ["dataShardingLevel"]
},
"enforcementOfAppropriateResourceBoundaries": {
"name": "Enforcement of appropriate resource boundaries",
"description": "The resources required by a component are predictable as precisely as possible and specified accordingly for each component in terms of lower and upper boundaries. Resources include CPU, memory, GPU, or Network requirements. This information is used by the infrastructure to enforce these resource boundaries. Thereby it is ensured that a component has the resources available that it needs to function properly, that the infrastructure can optimize the amount of allocated resource, and that components are not negatively impacted by defective components which excessively consume resources.",
"categories": ["applicationAdministration", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Define CPU and Memory Limits for Your Containers" }, { "key": "Arundel2019", "section": "5 Resource Limits" }, { "key": "Ibryam2020", "section": "2 Defined Resource requirements" }, { "key": "Arundel2019", "section": "5 Resource Quotas (limit maximum resources for a namespace)" }, { "key": "Goniwada2021", "section": "3 Runtime Confinement Principle, 6 Predictable Demands" }],
"measures": []
},
"built-InAutoscaling": {
"name": "Built-in autoscaling",
"description": "Horizontal up- and down-scaling of components is automated and built into the infrastructure on which components run. Horizontal scaling means that component instances are replicated when the load increases and components instances are removed when load decreases. This autoscaling is based on rules which can be configured according to system needs.",
"categories": ["applicationAdministration", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Use Platform Autoscaling Features" }, { "key": "Ibryam2020", "section": "24 Elastic Scale" }, { "key": "Bastani2017", "section": "13 Autoscaling" }, { "key": "Indrasiri2021", "section": "1 Why container orchestration?; Scaling" }, { "key": "Goniwada2021", "section": "5 Elasticity in Microservices" }],
"measures": []
},
"infrastructureAbstraction": {
"name": "Infrastructure abstraction",
"description": "The used infrastructure such as physical hardware, virtual hardware, or software platform is abstracted by clear boundaries to enable a clear differentiation of responsibilities for operating and managing infrastructure. For example, when a managed container orchestration system is used, the system is operable on that level of abstraction meaning that the API of the orchestration system is the boundary. Problems with underlying hardware or VMs are handled transparently by the provider.",
"categories": ["applicationAdministration", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE],
"sources": [{ "key": "Bastani2017", "section": "14 Service Brokers (make use of service brokers as an additional level of abstraction to automatically add or remove backing services)" }, { "key": "Goniwada2021", "section": "3 Location-Independent Principle" }],
"measures": []
},
"cloudVendorAbstraction": {
"name": "Cloud vendor abstraction",
"description": "The managed infrastructure and backing services used by a system and provided by a cloud vendor are based on unified or standardized interfaces so that vendor specifics are abstracted and a system could potentially be transferred to a another cloud vendor offering the same unified or standardized interfaces.",
"categories": ["applicationAdministration", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.INFRASTRUCTURE, ENTITIES.COMPONENT],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE],
"sources": [ { "key": "Indrasiri2021", "section": "1 Dynamic Management; Multicloud support" }],
"measures": ["servicePortability"]
},
"configurationManagement": {
"name": "Configuration management",
"description": "Configuration values which are specific to an environment are managed separately in a consistent way. Through this, components are more portable across environments and configuration can change independently from components.",
"categories": ["applicationAdministration", "dataManagement"],
"relevantEntities": [ENTITIES.BACKING_DATA, ENTITIES.INFRASTRUCTURE, ENTITIES.COMPONENT],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": []
},
"isolatedConfiguration": {
"name": "Isolated configuration",
"description": "Following DevOps principles, environment-specific configurations are separated from component artifacts (e.g. deployment units) and provided by the environment in which a cloud-native application runs. This enables adaptability across environments (also across testing and production environments)",
"categories": ["applicationAdministration", "dataManagement"],
"relevantEntities": [ENTITIES.BACKING_DATA, ENTITIES.INFRASTRUCTURE, ENTITIES.COMPONENT],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "6.2 The app's configuration layer" }, { "key": "Ibryam2020", "section": "18" }, { "key": "Scholl2019", "section": "6 Never Store Secrets or Configuration Inside an Image" }, { "key": "Adkins2020", "section": "14 Treat Configuration as Code" }, { "key": "Indrasiri2021", "section": " Decoupled Configurations" }],
"measures": ["configurationExternalization"]
},
"configurationStoredInSpecializedServices": {
"name": "Configuration stored in specialized services",
"description": "Configuration values are stored in specialized backing services and not only environment variables for example. That way, changing configurations at runtime is facilitated and can be enabled by connecting components to such specialized backing services and checking for updated configurations at runtime. Additionally, configurations can be stored once, but accessed by different components.",
"categories": ["applicationAdministration", "dataManagement"],
"relevantEntities": [ENTITIES.BACKING_DATA, ENTITIES.INFRASTRUCTURE, ENTITIES.COMPONENT, ENTITIES.BACKING_SERVICE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.SERVICE, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Ibryam2020", "section": "19 Configuration Resource" }, { "key": "Richardson2019", "section": "11.2 “Designing configurable services" }, { "key": "Arundel2019", "section": "10 ConfigMaps" }, { "key": "Bastani2017", "section": "2 Centralized, Journaled Configuration" }, { "key": "Bastani2017", "section": "2 Refreshable Configuration" }],
"measures": []
},
"contract-BasedLinks": {
"name": "Contract-based links",
"description": "Contracts are defined for the communication via links so that changes to endpoints can be evaluated by their impact on the contract and delayed when a contract would be broken. That way consumers of endpoints can adapt to changes when necessary without suddenly breaking communication via a link due to a changed endpoint.",
"categories": ["networkCommunication", "businessDomain"],
"relevantEntities": [ENTITIES.LINK, ENTITIES.ENDPOINT, ENTITIES.COMPONENT],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Bastani2017", "section": "4 Consumer-Driven Contract Testing (Use contracts for APIs to test against)" }],
"measures": []
},
"standardizedSelf-containedDeploymentUnit": {
"name": "Standardized self-contained deployment unit",
"description": "The components are deployed as standardized self-contained units so that the same artifact can reliably be installed and run in different environments and on different infrastructure.",
"categories": ["cloudInfrastructure", "applicationAdministration"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Reznik2019", "section": "10 Containerized Apps" }, { "key": "Adkins2020", "section": "7 Use Containers (smaller deployments, separated operating system, portable);" }, { "key": "Indrasiri2021", "section": "1 Use Containerization and Container Orchestration" }, { "key": "Garrison2017", "section": "7 Application Runtime and Isolation" }, { "key": "Goniwada2021", "section": "3 Deploy Independently Principle (deploy services in independent containers), Self-Containment Principle, 5 Containerization" }],
"measures": []
},
"immutableArtifacts": {
"name": "Immutable artifacts",
"description": "Infrastructure and components of a system are defined and described in its entirety at development time so that artifacts are immutable at runtime. This means upgrades are introduced at runtime through replacement of components instead of modification. Furthermore components do not differ across environments and in case of replication all replicas are identical to avoid unexpected behavior.",
"categories": ["applicationAdministration"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.DEPLOYMENT_MAPPING, ENTITIES.INFRASTRUCTURE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Don't Modify Deployed Infrastructure" }, { "key": "Indrasiri2021", "section": "1 Containerization" }, { "key": "Goniwada2021", "section": "3 Process Disposability Principle, Image Immutability Principle" }],
"measures": ["numberOfDeploymentTargetEnvironments"]
},
"guardedIngress": {
"name": "Guarded ingress",
"description": "Ingress communication, that means communication coming from outside of a system, needs to be guarded. It should be ensured that access to external endpoints is controlled by components offering these external endpoints. Control means for example that only authorized access is possible, maliciously large load is blocked, or secure communication protocols are ensured.",
"categories": ["networkCommunication", "applicationAdministration"],
"relevantEntities": [ENTITIES.ENDPOINT, ENTITIES.EXTERNAL_ENDPOINT, ENTITIES.COMPONENT, ENTITIES.PROXY_BACKING_SERVICE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Implement Rate Limiting and Throttling" }, { "key": "Adkins2020", "section": "8 Throttling (Delaying processing or responding to remain functional and decrease traffic from individual clients) (should be automated, part of graceful degradation)" }, { "key": "Adkins2020", "section": "8 Load shedding (In case of traffic spike, deny low priority requests to remain functional) (should be automated, part of graceful degradation)" }, { "key": "Goniwada2021", "section": "5 Throttling " }],
"measures": ["ratioOfComponentsWhoseIngressIsProxied"]
},
"distribution": {
"name": "Distribution",
"description": "Components are distributed across locations and data centers for better availability, reliability, and performance.",
"categories": ["dataManagement", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": ["componentDensity", "numberOfServiceHostedOnOneInfrastructure"]
},
"physicalDataDistribution": {
"name": "Physical data distribution",
"description": "Storage Backing Service instances where Data aggregates are persisted are distributed across physical locations (e.g. availability zones of a cloud vendor) so that even in the case of a failure of one physical location, another physical location is still useable.",
"categories": ["dataManagement", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING, ENTITIES.DATA_AGGREGATE, ENTITIES.STORAGE_BACKING_SERVICE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.STORAGE_BACKING_SERVICE, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Scholl2019", "section": "6 Keep Data in Multiple Regions or Zones" }, { "key": "Indrasiri2021", "section": "4 Data Sharding Pattern: Geographically distribute data" }],
"measures": ["numberOfAvailabilityZonesUsed"]
},
"physicalServiceDistribution": {
"name": "Physical service distribution",
"description": "Components are distributed through replication across physical locations (e.g. availability zones of a cloud vendor) so that even in the case of a failure of one physical location, another physical location is still useable.",
"categories": ["cloudInfrastructure"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": ["numberOfAvailabilityZonesUsed"]
},
"seamlessUpgrades": {
"name": "Seamless upgrades",
"description": "Upgrades of services do not interfere with availability. There are different strategies, like rolling upgrades, to achieve this which should be provided as a capability by the infrastructure.",
"categories": ["applicationAdministration", "cloudInfrastructure", "networkCommunication", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.INFRASTRUCTURE, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": []
},
"rollingUpgradesEnabled": {
"name": "Rolling upgrades enabled",
"description": "The infrastructure on which components are deployed provides the ability for rolling upgrades. That means upgrades of components can be performed seamlessly in an automated manner. Seamlessly means that upgrades of components do not necessitate planned downtime.",
"categories": ["applicationAdministration", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.INFRASTRUCTURE, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "7.2" }, { "key": "Scholl2019", "section": "6 Use Zero-Downtime Releases" }, { "key": "Ibryam2020", "section": "3 Declarative Deployment" }, { "key": "Reznik2019", "section": "10 Risk-Reducing Deployment Strategies" }, { "key": "Arundel2019", "section": "13 Rolling Updates" }, { "key": "Indrasiri2021", "section": "1 Why container orchestration?; Rolling upgrades" }],
"measures": ["rollingUpdateOption"]
},
"automatedInfrastructureMaintenance": {
"name": "Automated infrastructure maintenance",
"description": "The used infrastructure should automate regular maintenance tasks as much as possible in a way that the operation of components is not impacted by these tasks. Such tasks include updates of operating systems, standard libraries, and middleware managed by the infrastructure, but also certificate regeneration.",
"categories": ["cloudInfrastructure", "applicationAdministration"],
"relevantEntities": [ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Reznik2019", "section": "10 Automated Infrastructure" }, { "key": "Goniwada2021", "section": "5 Automation" }],
"measures": []
},
"autonomousFaultHandling": {
"name": "Autonomous fault handling",
"description": "Services expect faults at different levels and either handle them or minimize their impact by relying on the capabilities of cloud environments.",
"categories": ["networkCommunication", "cloudInfrastructure"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.ENDPOINT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM,ENTITIES.SERVICE, ENTITIES.INFRASTRUCTURE, ENTITIES.REQUEST_TRACE],
"sources": [],
"measures": []
},
"invocationTimeouts": {
"name": "Invocation timeouts",
"description": "For links between components, timeouts are defined to avoid infinite waiting on a service that is unavailable and a timely handling of problems.",
"categories": ["networkCommunication"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.ENDPOINT],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.SERVICE, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Indrasiri2021", "section": "3 Resilient Connectivity Pattern: Time-out" }, { "key": "Richardson2019", "section": "3.2.3 Handling partial failures using the Circuit Breaker pattern" }, { "key": "Goniwada2021", "section": "5 Timeout" }],
"measures": []
},
"retriesForSafeInvocations": {
"name": "Retries for safe invocations",
"description": "Links that are safe to invoke multiple times without leading to unintended state changes, are automatically retried in case of errors to transparently handle transient faults in communication. That way faults can be prevented from being propagated higher up in a request trace.",
"categories": ["networkCommunication"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.ENDPOINT],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "9.1" }, { "key": "Scholl2019", "section": "6 Handle Transient Failures with Retries" }, { "key": "Scholl2019", "section": "6 Use a Finite Number of Retries" }, { "key": "Bastani2017", "section": "12 Isolating Failures and Graceful Degradation: Use retries" }, { "key": "Indrasiri2021", "section": "3 Resilient Connectivity Pattern: Retry" }, { "key": "Ruecker2021", "section": "9 Synchronous Request/Response (Use retries in synchronous communications)" }, { "key": "Ruecker2021", "section": "9 The Importance of Idempotency (Communication which is retried needs idempotency)" }, { "key": "Goniwada2021", "section": "Idempotent Service Operation, Retry, 5 Retry " }],
"measures": ["numberOfLinksWithRetryLogic"]
},
"circuitBreakedCommunication": {
"name": "Circuit breaked communication",
"description": "For links a circuit breaker implementation is used which avoids unnecessary communication and therefore waiting time if a communication is known to fail. Instead the circuit breaker immediately returns an error response of a default response, is possible, while periodically retrying communication in the background.",
"categories": ["networkCommunication"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.LINK, ENTITIES.ENDPOINT],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Davis2019", "section": "10.1" }, { "key": "Scholl2019", "section": "6 Use Circuit Breakers for Nontransient Failures" }, { "key": "Richardson2019", "section": "3.2.3 Handling partial failures using the Circuit Breaker pattern" }, { "key": "Bastani2017", "section": "12 Isolating Failures and Graceful Degradation: circuit breaker" }, { "key": "Indrasiri2021", "section": "3 Resilient Connectivity Pattern: Circuit breaker" }, { "key": "Goniwada2021", "section": "4 Circuit Breaker" }],
"measures": ["numberOfLinksWithComplexFailover"]
},
"automatedRestarts": {
"name": "Automated restarts",
"description": "When a component is found to be unhealthy, that means not functioning as expected, it is directly and automatically restarted. Ideally this capability is provided by the infrastructure on which a component is running.",
"categories": ["cloudInfrastructure", "applicationAdministration"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE, ENTITIES.DEPLOYMENT_MAPPING],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.INFRASTRUCTURE],
"sources": [ { "key": "Bastani2017", "section": "13 automatic remediation" }, { "key": "Indrasiri2021", "section": "1 Why container orchestration?; High availability" }, { "key": "Goniwada2021", "section": "5 Self-Healing" }],
"measures": []
},
"api-BasedCommunication": {
"name": "API-based communication",
"description": "All endpoints that are offered by a service are part of a well-defined and documented API. That means, the APIs are based on common principles, are declarative instead of imperative, and are documented in a standardized or specified format (such as the OpenAPI specification). Communication only happens via endpoints that are part of such APIs and can be both synchronous or asynchronous.",
"categories": ["networkCommunication", "businessDomain"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.ENDPOINT, ENTITIES.LINK],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.SERVICE, ENTITIES.ENDPOINT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Reznik2019", "section": "9 Communicate Through APIs" }, { "key": "Adkins2020", "section": "6 Understandable Interface Specifications (Use Interface specifications for understandability" }, { "key": "Bastani2017", "section": "6 Everything is an API (Services are integrated via APIs)" }, { "key": "Indrasiri2021", "section": "2 Service Definitions in Synchronous Communication (Use a service definition for each service);" }, { "key": "Indrasiri2021", "section": "2 Service Definition in Asynchronous Communication (Use schemas to define message formats);" }, { "key": "Goniwada2021", "section": "3 API First Principle" }],
"measures": []
},
"consistentlyMediatedCommunication": {
"name": "Consistently mediated communication",
"description": "By mediating communication through additional components, there is no direct dependence on the other communication partner and additional operations can be performed to manage the communication, such as load balancing, monitoring, or the enforcement of policies. By using centralized mediation approaches, such as Service Meshes, management actions can be performed universally and consistently across the components of an application.",
"categories": ["networkCommunication"],
"relevantEntities": [ENTITIES.COMPONENT, ENTITIES.ENDPOINT, ENTITIES.LINK, ENTITIES.BACKING_SERVICE, ENTITIES.PROXY_BACKING_SERVICE],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
"sources": [{ "key": "Indrasiri2021", "section": "3 Sidecar Pattern, Service Mesh Pattern, Service Abstraction Pattern (Proxy communication with services to include service discovery and load balancing)" }, { "key": "Davis2019", "section": "10.3" }, { "key": "Richardson2019", "section": "11.4.2" }],
"measures": ["serviceMeshUsage"]
}
} satisfies { [productFactorKey: string]: ProductFactorSpec }
const productFactorKeys = Object.freeze(productFactors);
export type ProductFactorKey = keyof typeof productFactorKeys;
type ImpactSpec = {
impactedFactor: ProductFactorKey | QualityAspectKey,
sourceFactor: ProductFactorKey,
impactType: "positive" | "negative"
}
const impacts = [
{ "impactedFactor": "secretsManagement", "sourceFactor": "secretsStoredInSpecializedServices", "impactType": "positive" },
{ "impactedFactor": "confidentiality", "sourceFactor": "dataEncryptionInTransit", "impactType": "positive" },
{ "impactedFactor": "confidentiality", "sourceFactor": "secretsManagement", "impactType": "positive" },
{ "impactedFactor": "secretsManagement", "sourceFactor": "isolatedSecrets", "impactType": "positive" },
{ "impactedFactor": "integrity", "sourceFactor": "accessRestriction", "impactType": "positive" },
{ "impactedFactor": "accessRestriction", "sourceFactor": "leastPrivilegedAccess", "impactType": "positive" },
{ "impactedFactor": "accessRestriction", "sourceFactor": "accessControlManagementConsistency", "impactType": "positive" },
{ "impactedFactor": "accountability", "sourceFactor": "accountSeparation", "impactType": "positive" },
{ "impactedFactor": "authenticity", "sourceFactor": "authenticationDelegation", "impactType": "positive" },
{ "impactedFactor": "modularity", "sourceFactor": "serviceOrientation", "impactType": "positive" },
{ "impactedFactor": "serviceOrientation", "sourceFactor": "limitedFunctionalScope", "impactType": "positive" },
{ "impactedFactor": "limitedFunctionalScope", "sourceFactor": "limitedDataScope", "impactType": "positive" },
{ "impactedFactor": "limitedFunctionalScope", "sourceFactor": "limitedEndpointScope", "impactType": "positive" },
{ "impactedFactor": "limitedFunctionalScope", "sourceFactor": "commandQueryResponsibilitySegregation", "impactType": "positive" },
{ "impactedFactor": "simplicity", "sourceFactor": "commandQueryResponsibilitySegregation", "impactType": "negative" },
{ "impactedFactor": "serviceOrientation", "sourceFactor": "separationByGateways", "impactType": "positive" },
{ "impactedFactor": "seamlessUpgrades", "sourceFactor": "separationByGateways", "impactType": "positive" },
{ "impactedFactor": "availability", "sourceFactor": "seamlessUpgrades", "impactType": "positive" },
{ "impactedFactor": "modularity", "sourceFactor": "isolatedState", "impactType": "positive" },
{ "impactedFactor": "replaceability", "sourceFactor": "isolatedState", "impactType": "positive" },
{ "impactedFactor": "elasticity", "sourceFactor": "isolatedState", "impactType": "positive" },
{ "impactedFactor": "isolatedState", "sourceFactor": "mostlyStatelessServices", "impactType": "positive" },
{ "impactedFactor": "testability", "sourceFactor": "mostlyStatelessServices", "impactType": "positive" },
{ "impactedFactor": "isolatedState", "sourceFactor": "specializedStatefulServices", "impactType": "positive" },
{ "impactedFactor": "modularity", "sourceFactor": "looseCoupling", "impactType": "positive" },
{ "impactedFactor": "looseCoupling", "sourceFactor": "asynchronousCommunication", "impactType": "positive" },
{ "impactedFactor": "looseCoupling", "sourceFactor": "communicationPartnerAbstraction", "impactType": "positive" },
{ "impactedFactor": "analyzability", "sourceFactor": "communicationPartnerAbstraction", "impactType": "negative" },
{ "impactedFactor": "faultTolerance", "sourceFactor": "persistentCommunication", "impactType": "positive" },
{ "impactedFactor": "simplicity", "sourceFactor": "usageOfExistingSolutionsForNonCoreCapabilities", "impactType": "positive" },
{ "impactedFactor": "reusability", "sourceFactor": "standardization", "impactType": "positive" },
{ "impactedFactor": "standardization", "sourceFactor": "componentSimilarity", "impactType": "positive" },
{ "impactedFactor": "analyzability", "sourceFactor": "automatedMonitoring", "impactType": "positive" },
{ "impactedFactor": "automatedMonitoring", "sourceFactor": "consistentCentralizedLogging", "impactType": "positive" },
{ "impactedFactor": "accountability", "sourceFactor": "consistentCentralizedLogging", "impactType": "positive" },
{ "impactedFactor": "automatedMonitoring", "sourceFactor": "consistentCentralizedMetrics", "impactType": "positive" },
{ "impactedFactor": "automatedMonitoring", "sourceFactor": "distributedTracingOfInvocations", "impactType": "positive" },
{ "impactedFactor": "automatedMonitoring", "sourceFactor": "healthAndReadinessChecks", "impactType": "positive" },
{ "impactedFactor": "automatedRestarts", "sourceFactor": "healthAndReadinessChecks", "impactType": "positive" },
{ "impactedFactor": "availability", "sourceFactor": "healthAndReadinessChecks", "impactType": "positive" },
{ "impactedFactor": "modifiability", "sourceFactor": "automatedInfrastructureProvisioning", "impactType": "positive" },
{ "impactedFactor": "installability", "sourceFactor": "automatedInfrastructureProvisioning", "impactType": "positive" },
{ "impactedFactor": "modifiability", "sourceFactor": "useInfrastructureAsCode", "impactType": "positive" },
{ "impactedFactor": "adaptability", "sourceFactor": "useInfrastructureAsCode", "impactType": "positive" },
{ "impactedFactor": "reusability", "sourceFactor": "useInfrastructureAsCode", "impactType": "positive" },
{ "impactedFactor": "recoverability", "sourceFactor": "useInfrastructureAsCode", "impactType": "positive" },
{ "impactedFactor": "modifiability", "sourceFactor": "serviceIndependence", "impactType": "positive" },
{ "impactedFactor": "serviceIndependence", "sourceFactor": "lowCoupling", "impactType": "positive" },
{ "impactedFactor": "serviceIndependence", "sourceFactor": "functionalDecentralization", "impactType": "positive" },
{ "impactedFactor": "serviceIndependence", "sourceFactor": "limitedRequestTraceScope", "impactType": "positive" },
{ "impactedFactor": "serviceIndependence", "sourceFactor": "logicalGrouping", "impactType": "positive" },
{ "impactedFactor": "serviceIndependence", "sourceFactor": "backingServiceDecentralization", "impactType": "positive" },
{ "impactedFactor": "modifiability", "sourceFactor": "addressingAbstraction", "impactType": "positive" },
{ "impactedFactor": "replaceability", "sourceFactor": "addressingAbstraction", "impactType": "positive" },
{ "impactedFactor": "simplicity", "sourceFactor": "sparsity", "impactType": "positive" },
{ "impactedFactor": "simplicity", "sourceFactor": "operationOutsourcing", "impactType": "positive" },
{ "impactedFactor": "operationOutsourcing", "sourceFactor": "managedInfrastructure", "impactType": "positive" },
{ "impactedFactor": "operationOutsourcing", "sourceFactor": "managedBackingServices", "impactType": "positive" },
{ "impactedFactor": "resourceUtilization", "sourceFactor": "dynamicScheduling", "impactType": "positive" },
{ "impactedFactor": "timeBehaviour", "sourceFactor": "replication", "impactType": "positive" },
{ "impactedFactor": "replication", "sourceFactor": "serviceReplication", "impactType": "positive" },
{ "impactedFactor": "availability", "sourceFactor": "serviceReplication", "impactType": "positive" },
{ "impactedFactor": "replication", "sourceFactor": "horizontalDataReplication", "impactType": "positive" },
{ "impactedFactor": "replication", "sourceFactor": "verticalDataReplication", "impactType": "positive" },
{ "impactedFactor": "analyzability", "sourceFactor": "verticalDataReplication", "impactType": "negative" },
{ "impactedFactor": "availability", "sourceFactor": "verticalDataReplication", "impactType": "positive" },
{ "impactedFactor": "replication", "sourceFactor": "shardedDataStoreReplication", "impactType": "positive" },
{ "impactedFactor": "resourceUtilization", "sourceFactor": "enforcementOfAppropriateResourceBoundaries", "impactType": "positive" },
{ "impactedFactor": "availability", "sourceFactor": "enforcementOfAppropriateResourceBoundaries", "impactType": "positive" },
{ "impactedFactor": "availability", "sourceFactor": "built-InAutoscaling", "impactType": "positive" },
{ "impactedFactor": "elasticity", "sourceFactor": "built-InAutoscaling", "impactType": "positive" },
{ "impactedFactor": "adaptability", "sourceFactor": "infrastructureAbstraction", "impactType": "positive" },
{ "impactedFactor": "adaptability", "sourceFactor": "cloudVendorAbstraction", "impactType": "positive" },
{ "impactedFactor": "reusability", "sourceFactor": "cloudVendorAbstraction", "impactType": "positive" },
{ "impactedFactor": "adaptability", "sourceFactor": "configurationManagement", "impactType": "positive" },
{ "impactedFactor": "configurationManagement", "sourceFactor": "isolatedConfiguration", "impactType": "positive" },
{ "impactedFactor": "configurationManagement", "sourceFactor": "configurationStoredInSpecializedServices", "impactType": "positive" },
{ "impactedFactor": "adaptability", "sourceFactor": "contract-BasedLinks", "impactType": "positive" },
{ "impactedFactor": "installability", "sourceFactor": "standardizedSelf-containedDeploymentUnit", "impactType": "positive" },
{ "impactedFactor": "replaceability", "sourceFactor": "immutableArtifacts", "impactType": "positive" },
{ "impactedFactor": "availability", "sourceFactor": "guardedIngress", "impactType": "positive" },
{ "impactedFactor": "availability", "sourceFactor": "distribution", "impactType": "positive" },
{ "impactedFactor": "distribution", "sourceFactor": "physicalDataDistribution", "impactType": "positive" },
{ "impactedFactor": "distribution", "sourceFactor": "physicalServiceDistribution", "impactType": "positive" },
{ "impactedFactor": "seamlessUpgrades", "sourceFactor": "rollingUpgradesEnabled", "impactType": "positive" },
{ "impactedFactor": "availability", "sourceFactor": "automatedInfrastructureMaintenance", "impactType": "positive" },
{ "impactedFactor": "recoverability", "sourceFactor": "automatedInfrastructureMaintenance", "impactType": "positive" },
{ "impactedFactor": "faultTolerance", "sourceFactor": "autonomousFaultHandling", "impactType": "positive" },
{ "impactedFactor": "autonomousFaultHandling", "sourceFactor": "invocationTimeouts", "impactType": "positive" },
{ "impactedFactor": "autonomousFaultHandling", "sourceFactor": "retriesForSafeInvocations", "impactType": "positive" },
{ "impactedFactor": "autonomousFaultHandling", "sourceFactor": "circuitBreakedCommunication", "impactType": "positive" },
{ "impactedFactor": "recoverability", "sourceFactor": "automatedRestarts", "impactType": "positive" },
{ "impactedFactor": "interoperability", "sourceFactor": "api-BasedCommunication", "impactType": "positive" },
{ "impactedFactor": "testability", "sourceFactor": "api-BasedCommunication", "impactType": "positive" },
{ "impactedFactor": "interoperability", "sourceFactor": "consistentlyMediatedCommunication", "impactType": "positive" },
{ "impactedFactor": "timeBehaviour", "sourceFactor": "consistentlyMediatedCommunication", "impactType": "negative" },
{ "impactedFactor": "analyzability", "sourceFactor": "consistentlyMediatedCommunication", "impactType": "positive" }
] satisfies ImpactSpec[]
type MeasureSpec = {
name: string,
calculation: string,
sources: string[],
applicableEntities: `${ENTITIES}`[],
aggregateOf?: string
}
const measures = {
"ratioOfEndpointsSupportingSsl": {
"name": "Ratio of endpoints that support SSL",
"calculation": "Endpoints that support SSL / Endpoints that do not support SSL",
"sources": ["Ntentos2022"],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
},
"ratioOfExternalEndpointsSupportingTls": {
"name": "Ratio of external endpoints that support TLS",
"calculation": "External Endpoints that support TLS / All External Endpoints",
"sources": ["new"],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT],
},
"ratioOfSecuredLinks": {
"name": "Ratio of secured links",
"calculation": "Links secured by SSL / All links",
"sources": ["Zdun2023", "Zdun2023a"],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.REQUEST_TRACE],
},
"ratioOfEndpointsThatSupportTokenBasedAuthentication": {
"name": "Ratio of endpoints that support token-based authentication ",
"calculation": "Endpoints supportin tokens / All endpoints",
"sources": ["Ntentos2022", "Zdun2023", "Zdun2023a"],
"applicableEntities": [ENTITIES.SYSTEM, ENTITIES.COMPONENT, ENTITIES.REQUEST_TRACE],
},
"ratioOfEndpointsThatSupportApiKeys": {