[I2nsf] Post 2b: Background Information on PCIMe (Modeler Details)
John Strassner <strazpdj@gmail.com> Fri, 11 December 2015 22:08 UTC
Return-Path: <strazpdj@gmail.com>
X-Original-To: i2nsf@ietfa.amsl.com
Delivered-To: i2nsf@ietfa.amsl.com
Received: from localhost (ietfa.amsl.com [127.0.0.1]) by ietfa.amsl.com (Postfix) with ESMTP id F3DA11A9085 for <i2nsf@ietfa.amsl.com>; Fri, 11 Dec 2015 14:08:02 -0800 (PST)
X-Virus-Scanned: amavisd-new at amsl.com
X-Spam-Flag: NO
X-Spam-Score: -0.599
X-Spam-Level:
X-Spam-Status: No, score=-0.599 tagged_above=-999 required=5 tests=[BAYES_05=-0.5, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, FREEMAIL_FROM=0.001, HTML_MESSAGE=0.001, SPF_PASS=-0.001] autolearn=ham
Received: from mail.ietf.org ([4.31.198.44]) by localhost (ietfa.amsl.com [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id J6XoTIdwJpCM for <i2nsf@ietfa.amsl.com>; Fri, 11 Dec 2015 14:07:53 -0800 (PST)
Received: from mail-vk0-x235.google.com (mail-vk0-x235.google.com [IPv6:2607:f8b0:400c:c05::235]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by ietfa.amsl.com (Postfix) with ESMTPS id 53FC41A6F12 for <i2nsf@ietf.org>; Fri, 11 Dec 2015 14:07:53 -0800 (PST)
Received: by vkca188 with SMTP id a188so124939773vkc.0 for <i2nsf@ietf.org>; Fri, 11 Dec 2015 14:07:52 -0800 (PST)
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=mime-version:date:message-id:subject:from:to:content-type; bh=pMDklw7bqbZLe5AubpQnq6MgcUEtzbYoX3OpE3gW1LY=; b=UhNILAhCMrVAtvBbFLWAGj89Be7sCxK9jWJnwaIVK9PMfUZmFXxJb3jy483GTaZgDe KjNzcvfD4Nk3DLMJdOHaoZJwB4ZCpm+B2YCwBRNFLNckMVFmC2RSII/tITyFSNrzBHHl G6/s3PL/12ZDYNZ5TNbtj8CzJZpEn9Dr3+OU4Cyn5/ZQoKr3marJU1Nnkx+mH9S5cCAu hs+pf4DaVLINJh/qnmWyaQIwGr9wWnKxFE54T7Ri+VgUIohDhVaziuuOgN9UHtCinwIM uAFslUO2wwWRzdahi3j+lL8C00LOV9OJpN9We7Lrr2shnBXfXCKukbze/byZPLe+CKW+ lA6w==
MIME-Version: 1.0
X-Received: by 10.31.4.208 with SMTP id 199mr14565997vke.110.1449871672439; Fri, 11 Dec 2015 14:07:52 -0800 (PST)
Received: by 10.103.40.131 with HTTP; Fri, 11 Dec 2015 14:07:52 -0800 (PST)
Date: Fri, 11 Dec 2015 14:07:52 -0800
Message-ID: <CAJwYUrFk2foU46VpxvEqsBiuUo_y_jEMSvoACDGD2vt==PS7tg@mail.gmail.com>
From: John Strassner <strazpdj@gmail.com>
To: i2nsf@ietf.org
Content-Type: multipart/alternative; boundary="001a1142a4d2017a6b0526a68e07"
Archived-At: <http://mailarchive.ietf.org/arch/msg/i2nsf/LWIqvz3cGDRr15e2Oy9tP36WhRs>
Subject: [I2nsf] Post 2b: Background Information on PCIMe (Modeler Details)
X-BeenThere: i2nsf@ietf.org
X-Mailman-Version: 2.1.15
Precedence: list
List-Id: "*I2NSF: Interface to Network Security Functions mailing list*" <i2nsf.ietf.org>
List-Unsubscribe: <https://www.ietf.org/mailman/options/i2nsf>, <mailto:i2nsf-request@ietf.org?subject=unsubscribe>
List-Archive: <https://mailarchive.ietf.org/arch/browse/i2nsf/>
List-Post: <mailto:i2nsf@ietf.org>
List-Help: <mailto:i2nsf-request@ietf.org?subject=help>
List-Subscribe: <https://www.ietf.org/mailman/listinfo/i2nsf>, <mailto:i2nsf-request@ietf.org?subject=subscribe>
X-List-Received-Date: Fri, 11 Dec 2015 22:08:03 -0000
The I2NSF framework draft mentions PCIM (RFC3060) and PCIMe (RFC3460) as possible candidates for guiding the policy structure that can be mapped to the Capability Layer's "Subject-Object-Action-Function" paradigm. This note provides a brief analysis of the suitability of PCIMe for this task. Attributes in PCIM and PCIMe do not obey standard coding conventions of nonCapThenCap, they are CapThenCap. Please note that I name attributes in the traditional nonCapThenCap manner in the following discussion. Finally, sorry for the length of this note, but RFC3460 is a 93-page document, and even more complex than PCIM. Therefore, I have tried to keep this as brief as possible by splitting it into two, called Post 2a and Post 2b. This post (2a) gives a high-level overview, and is intended for non-modelers. Post 2b adds detail to post 2a, and is intended for modelers. If you need more explanation on anything, please do not hesitate to ask! 1. Focus of PCIMe PCIMe was built to accomplish two things: 1) EXTEND PCIM into areas that were being worked on at the time (e.g., header filtering), and 2) DEPRECATE parts of PCIM based on early experience Note that PCIMe is still tightly tied to the DMTF CIM. For an overview of what this means in modeling terms, please see section 5 of Post 1: Background Information on PCIM. 1.1. EXTENSION In general, extensions should not cause a problem. One important exception is when generalization (introduction of a new superclass) is used, and properties are added to the newly introduced superclass. This means that prior implementations will not have either the new class or its properties. One important example is the PolicySet class, which is the new parent of PolicyRule and PolicyGroup. PolicySet introduces two attributes - one is new (so existing implementations won't have it), and one is MOVED from another class (which will cause different problems). One area that will cause always problems is the unfortunate implementation of relationships. Remember that in PCIM and CIM, ALL associations, aggregations, and compositions are implemented as classes, which means that associations also are subject to inheritance. Furthermore, PCIMe, PCIM, and CIM use the strange practice of overriding keys. Not only should keys NOT be used in an information model (they are technology-specific), but this is poor practice from a relational algebra point-of-view. 1.2. DEPRECATION Deprecation is sometimes unavoidable. In general, such changes are not backwards-compatible. Note that PCIMe does not include in its class definitions annotations as to why a particular element was deprecated. 2. SUMMARY: main drawbacks of using PCIMe Note that the current CIM Policy Model (2.44.1) is significantly different than either PCIM or PCIMe. PCIM is based on CIM 2.4; PCIMe is based on CIM 2.5. PCIMe is NOT backwards compatible with PCIM in all areas. Note also that many of the deprecated items in 2.4 and 2.5 still exist in 2.44.1, though some have been removed. 2.1. Critical Problems These are in addition to those pointed out in Post 1. All items from post 1 are repeated; those bullets with additional information are marked with asterisks (***). 2.1.1. PolicyRule Problems - There is no way to properly aggregate PolicyRules into PolicyGroups (PolicySetComponent is recursive, so it can be used to aggregates homogeneous, but not heterogeneous, objects *** Nested policy rules (also called sub-rules) are no different than making a method call to another PolicyAction; this would greatly simplify implementation and understanding. Specifically: *** since the parent's rules are executed before any of the sub- rules are executed, this has the exact same effect as making a call to another PolicyAction; the PolicyEvent and PolicyCondition clauses of the sub-rule do not exist *** Optimization of sub-rules is implementation-dependent; if any sub-rule has side effects, then interoperability is broken - There is no mechanism to make use of the executionStrategy attribute, since neither errors nor events are defined - There is no mechanism that can prevent side effects caused by the evaluation of conditions - There is no mechanism that can prevent side effects caused by the execution of actions 2.1.2. Role Problems - Using attributes (i.e., policyRoles) to associate a PolicyRule to a resource is broken. This is what associations, aggregations, and compositions are for. *** Worse, the mechanism for aggregating roles is **backwards** in PCIMe. A PolicyRoleCollection aggregates ManagedElement objects. Instead, ManagedElement objects have different responsibilities (i.e., roles), so the aggregation should be reversed. - Worse yet, there is no mechanism for ensuring that the same System, which provides scoping, is used for the ManagedElement object as is for the PolicyRoleCollection object *** Finally, there is no mechanism for role inheritance to be sanitized. Specifically, in PCIMe, both PolicyRules and PolicyGroups are, in effect, containers that can have policyRoles; there is no mechanism to either remove duplications, remove role conflicts, or perform other aspects of role engineering *** Finally, note that the DMTF CIM model has deprecated the policyRole attribute in the PolicySet class. 2.1.3. Conditions and Actions *** There is no reason to define the SimplePolicyCondition and CompoundPolicyCondition classes *** this requires an additional aggregation *** the only difference between these classes is an attribute that specifies whether the clause is in DNF or CNF (note that the additional classes mandate a new aggregation as well) *** There is no reason to define the SimplePolicyAction and CompoundPolicyAction classes *** this requires an additional aggregation *** while SimplePolicyAction has no attributes and CompoundPolicyAction has two, both attributes SHOULD be moved to the Action class, since they are applicable to both classes 2.1.4. Variables *** There is no reason to have both a PolicyImplicitVariable and a PolicyExplicitVariable class, as they are performing the same semantic function 2.1.5. Additional Problems These are so important that they are repeated from Post 1: - There is no way to uniquely identify instances of the same object - There is no concept of error or exception handling - There is no concept of the subject or the target of a policy - Adding a new type of policy (e.g., declarative or functional) will cause a major rewrite of the entire model - There is no approach to detecting and solving policy conflicts 2.2. Major Problems 2.2.1. Abstraction Problems - The "levels of abstraction" (domain- and device-level policies) have no mechanisms defined in the model to support them (see Post 2b) *** The PolicyComponent aggregation, defined on Policy, means that ANY SUBCLASS can aggregate itself. This is clearly broken, even if the aggregation is optional, since implementations will never know in advance if it is being implemented or not. In addition, this aggregation does not make sense for the majority of the classes defined in PCIM (e.g., what does it mean for a PolicyVariable to aggregate itself?). (see Post 2b) *** Scoping has no mechanisms to ensure that the PolicyRule and the resource to which it applies are in the same namespace. *** First, this is represented using weak relationships (a relational algebra construct), which should not be used in information models. *** Second, this requires two relationships (one for PolicyGroup and a different one for PolicyRule) to be used. *** Third, the PCIMe implementation uses overriding of keys (!) to implement these aggregations. 2.2.2. PolicyRule Problems *** The "first-match" decision strategy is powerful, but deceptive: if the PolicySet is a PolicyGroup, then the first-match criterion (for termination) will match if ANY one or more contained PolicyRules OR PolicyGroups match - The notion of "rooted" vs. "unrooted" PolicySets defeats the purpose of having a decisionStrategy attribute *** There is no mechanism to ensure that priority attribute values are unique within a PolicySet (or PolicySetInSystem); this leads to non-deterministic behavior - Different classes are required to associate each condition with a PolicyRule - Different classes are required to associate each action with a PolicyRule 2.2.3. Condition and Action Problems *** Both simple and compound policy conditions use the canonical form {variable MATCH value}; however, there is no object that represents the different semantics for MATCH, and hence, the MATCH operator is overloaded and ambiguous (e.g., is a shallow or deep equality match desired) *** CompoundPolicyConditions are very expensive, as each Boolean condition clause must be aggregated using a unique aggregation - This also applies to CompoundPolicyActions *** Building a Boolean condition clause is complex and requires too many aggregations; e.g., a simple PolicyCondition requires: *** one PolicyConditionInPolicyRule to associate the condition clause with the PolicyRule *** one PolicyVariableInSimplePolicyCondition aggregation to associate the variable used to the condition clause *** n ExpectedPolicyValuesForVariable associations to associate the allowed value range(s) to the variable *** one PolicyValueInSimplePolicyCondition aggregation to associate the value used to the condition clause *** The above is more complex when PolicyConditions are nested, as well as when CompoundPolicyConditions are used; in both cases, the number of associations and aggregations multiply - The above two points apply equally to PolicyActions 2.2.4. Miscellaneous Problems *** The associations PolicyInSystem, PolicyGroupInSystem, and PolicyRuleInSystem are superfluous; modern software techniques like introspection or reflection do the same things in more powerful ways. *** Filters are too difficult to construct (an object is defined for each filter, and each such object requires an aggregation to add it to another object) 2.3. Minor Problems - PolicyRule has an attribute named "mandatory" whose semantics are ambiguous depending on the values of other attributes - The class CompoundFilterCondition defines one additional attribute; this is insufficient to standardize how filtering conditions should be structured - Copying the attributes sequencedActions and executionStrategy in both PolicyRule and CompoundPolicyAction does not make sense *** All ImplicitPolicyVariable subclasses have no mechanism to enforce their allowed value types except an association, and that association has no attributes or OCL constraints to enforce the value types (in other words, the enforcement is by looking at class names or attribute values) - The ReusablePolicyContainer class does not define any useful attributes for policy-based management Finally, note that the DMTF CIM model has deprecated the mandatory attribute in the PolicyRule class. 3. PCIMe Class Hierarchy The PCIMe Class Hierarchy is still a CA (condition-action) model, as shown below (changes are briefly noted in parentheses): ManagedElement (abstract) | +---Policy (abstract) | | | +---PolicySet (abstract, new) | | | | | +---PolicyGroup (MOVED to here) | | | | | +---PolicyRule (MOVED to here) | | | +---PolicyCondition (abstract) | | | | | +---PolicyTimePeriodCondition | | | | | +---VendorPolicyCondition | | | | | +---SimplePolicyCondition (NEW) | | | | | +---CompoundPolicyCondition (NEW) | | | | | +---PolicyFilterCondition (NEW) | | | +---PolicyAction (abstract) | | | | | +---VendorPolicyAction | | | | | +---SimplePolicyAction (NEW) | | | | | +---CompoundPolicyAction (NEW) | | | | +---PolicyVariable (abstract, NEW) | | | | | +---PolicyExplicitVariable (NEW) | | | | | +---PolicyImplicitVariable (abstract, NEW) | | | | | +---(NEW SUBCLASSES) | | | +---PolicyValue (abstract, NEW) | | | | | +---(NEW SUBCLASSES) | | | +---Collection (Abstract, NEW*) | | | | | +---PolicyRoleCollection (NEW) | | | +---ManagedSystemElement (abstract, NEW*) | | | | | +---LogicalElement (abstract, NEW*) | | | | | | | +---System (abstract, NEW*) | | | | | | | | | ... (deprecated PolicyRepository with ReusablePolicyContainer, NEW*) | | | | | | | +---FilterEntryBase (abstract, NEW*) | | | | | | | | | +---IpHeadersFilter (NEW)* | | | | | | | | | +---8021Filter (NEW*) | | | | | | | | +---FilterList (NEW*) Note that RFC3460 says that the classes marked by NEW* are not new, as they are defined in the CIM. However, they ARE new to PCIMe, so I have marked them as NEW*. The rest of this section adds detail to Post 2a. The main STRUCTURAL changes in the class hierarchy are: 1) Introduce a new superclass (PolicySet) to parent PolicyRule and PolicyGroup (NOT backwards-compatible, see 3.1) 2) Change how PolicyRules and PolicyGroups are aggregated (see 3.2) 3) Change PolicyRule prioritization (see 3.3) 4) Change PolicyRule execution (see 3.4) 5) Change PolicyRules (covered in Section 2 above) 6) Extend PolicyCondition with two new concrete classes (SimplePolicyCondition and CompoundPolicyCondition) (covered in Section 2 above) 7) Extend PolicyAction with two new concrete classes (SimplePolicyAction and CompoundPolicyAction) (covered in Section 2 above) 8) Change how policyRoles are Represented and Used (covered in Section 2 above) 9) Introduce PolicyVariable (covered in Section 2 above) 10) Introduce PolicyValue (covered in Section 2 above) 11) More about PolicyRoleCollection (see 3.5) These will be described in the following subsections. 3.1. Introduce a new superclass (PolicySet) This change has several problems; the most important are described below. 3.1.1. PolicySet Structure This change was done to define a common parent for the PolicyRule and PolicyGroup classes. This change is NOT backwards-compatible: a) It moves the policyRoles attribute from PolicyRule to PolicySet, which breaks existing implementations b) The priority attribute is moved from PolicyRule to two different relationships (both of which break existing implementations): 1. The PolicySetInSystem association (which is implemented as an association class) 2. The PolicySetComponent aggregation (which is also implemented as an association class) c) It introduces a new attribute (policyDecisionStrategy) that applies to both PolicyRule and PolicyGroup; existing implementations will not have this attribute and will break 3.1.2. Unique Naming >From a code robustness perspective, software elements (classes, attributes, relationships) should be uniquely named; there is no good reason to duplicate the name "priority" here. Unfortunately, this is a systemic problem in the DMTF CIM. Semantically, it is strange to see the same property applied to an association as well as an aggregation, since these are very different types of relationships. 3.1.3. Evaluation of PolicyRules The justification for adding the new attribute policyDecisionStrategy to PolicySet (Section 3.2.3, page 7 of PCIMe) is incorrect. First, this attribute may not directly affect how priority is used, since its purpose is to define how rules are evaluated (first matching or not). Second, there is no mechanism specified to enable the combination of this attribute and the priority attribute (both in PolicySet) to **deterministically** specify how a rule is evaluated (i.e., while the text "...PolicySetComponent.Priority MUST have a unique value when compared with others defined for the same aggregating PolicySet" is present, no UML mechanism, such as OCL, is defined to enforce this text). 3.1.4. Moving policyRoles from PolicyRule to PolicySet The rationale for this change is to expand the use of this attribute. Since PCIMe is trying to fix grouping (PolicyRules can contain PolicyRules, and PolicyGroups can contain PolicyRules or PolicyGroups), then at first glance, it makes sense to move this attribute to PolicySet, so both PolicyRule and PolicyGroup can benefit from it. Unfortunately, the role-object pattern [1] was invented for this purpose (almost two decades ago). Furthermore, this would solve the problem stated in 3.2.4 (page 8) of "...there is no mechanism in PCIM for assigning roles to resources" in a much more elegant fashion. Note that the DMTF CIM model has deprecated this attribute. 3.2. Change How PolicyRules and PolicyGroups are Aggregated The previous section alluded to the changes in grouping in PCIMe. PCIM had two aggregations (PolicyRuleInPolicyGroup and PolicyGroupInPolicyGroup); the first enabled PolicyRules to be aggregated by a PolicyGroup, while the second enabled PolicyGroups to be aggregated by a PolicyGroup. These have now both been replaced by a single recursive aggregation (PolicySetComponent) on PolicySet. This is broken! PolicySetComponent means that any subclass of PolicySet can recursively aggregate itself (so, you get PolicyRules aggregated by a PolicyRule, and PolicyGroups aggregated by a PolicyGroup). You do NOT get the ability for a PolicyGroup to aggregate a PolicyRule!!! This is mandatory for any policy implementation - otherwise, PolicyGroups cannot contain a PolicyRule! 3.3. Change PolicyRule prioritization PolicySetComponent defines the priority attribute (it was moved from PolicyRule). From 3.2 above, this means that you can NOT prioritize which set of PolicyRules are in which set of PolicyGroups (e.g., Gold vs. Silver might want different flow actions, even though the PolicyRules are the same). 3.4. Change PolicyRule execution A new attribute (policyDecisionStrategy) is defined for PolicySet. It is a uint16, which is used to define 2 values: first-match and all-match. Given that there are only 2 values, this should be a Boolean, not a 16-bit unsigned integer! Second, the firstMatching == TRUE value means that the first PolicyRule whose conditions matched should be executed, and then execution stops (even if other PolicyRules are there waiting to be executed). Clearly, this only works if the priority attribute is also used. Unfortunately, this falls well short of controlling execution context. For example, what happens if a PolicyRule fails to execute properly? 3.5. PolicyRoleCollection The purpose of this class is to define a collection of resources that are associated with a particular role. The process, however, is cumbersome and fragile: a) Define appropriate PolicyRules b) Define appropriate values for each policyRole (inherited) attribute of affected PolicyRules (these are used to represent a resource having that role that the PolicyRule applies to) c) Define appropriate PolicyGroups d) Define appropriate values for each policyRole (inherited) attribute of affected PolicyGroups (these are used to represent a resource having that role that the PolicyGroup applies to) e) Define the PolicyRoleCollection class f) Instantiate its policyRoles attribute, and populate it with the same values as the above g) Tie the PolicyCollection class to the set of PolicyRule classes with the same role using the PolicySetInRoleCollection aggregation (note: one aggregation is required for EACH reference. Aggregations are not easily handled in YANG; more on that later). The obvious problem with the tedious procedure is that the policyRole attribute in PolicyRoleCollection is a **string**. Thus, if someone gives a resource the same name as another resource, this fails to identify which resource is being referred to. If someone forgets to assign a role to that resource, this also fails. If someone gives the same role name to multiple PolicyRules and/or PolicyGroups, this fails. It is also unclear how Boolean combinations of different policyRoles work. Finally, note that the DMTF CIM model has deprecated the policyRole attribute in the PolicySet class. 4. Relationships PCIMe uses the same approach as PCIM with respect to associations and aggregations (no compositions are defined): implement them as a class. The impact to building YANG data models will be discussed in a future post. For now, YANG is hierarchical, which corresponds to composition. Aggregation and association are very different models. This section is not in Post 2a. 4.1. Changes to the PolicyComponent Hierarchy The following relationships are changed in PCIMe: - PolicyRuleInPolicyGroup is DEPRECATED - PolicyGroupInPolicyGroup is DEPRECATED - PolicyConditionStructure is NEW - PolicyConditionInPolicyRule is MOVED to be a subclass of PolicyConditionStructure - PolicyConditionInPolicyCondition is NEW - PolicyActionStructure is NEW - PolicyActionInPolicyRule is MOVED to be a subclass of PolicyActionStructure - PolicyActionInPolicyAction is NEW - PolicyVariableInSimplePolicyCondition is NEW - PolicyValueInSimplePolicyCondition is NEW - PolicyVariableInSimplePolicyAction is NEW - PolicyValueInSimplePolicyAction is NEW - PolicySetInSystem is NEW - PolicyRuleInSystem is MOVED to be a subclass of PolicySetInSystem - PolicyRGroupnSystem is MOVED to be a subclass of PolicySetInSystem - ReusablePolicy is NEW - PolicyConditionInPolicyRepository is DEPRECATED - PolicyActionInPolicyRepository is DEPRECATED - ExpectedPolicyValuesForVariable is NEW - PolicyRoleCollectionInSystem is NEW - ContainedDomain is NEW - PolicyRepositoryInPolicyRepository is DEPRECATED - EntriesInFilterList is NEW - MemberOfCollection is NEW - ElementInPolicyRoleCollection is NEW 5. Comments on the Philosophy of Changing an Information Model, used by CIM/PCIM/PCIMe This is a **theory** section; please skip unless you want to understand the model in more detail. This section is not in Post 2a. If you have made it this far :-) then you will no doubt have looked at RFC3460. Please now refer to section 3.1 "How to Change an Information Model" on page 6. ALL FOUR RECOMMENDATIONS WILL BREAK MODELS IF EXTREME CARE IS NOT TAKEN. 5.1 Background - Software Architecture In software design, there are a set of fundamental principles that should be used to guide implementations. These include, but are not limited to: 1) the Liskov Substitution Principle [2] 2) the Single Responsibility Principle [3] 3) the Open-Closed Principle [4] 4) software contracts [4] 5.1.1. The Liskov Substitution Principle (LSP) This principle states that if A is a subclass of B, then objects instantiated from class B may be replaced with objects instantiated from class A WITHOUT ALTERING ANY OF THE DESIRED SEMANTICS OF THE PROGRAM. This is often called Strong Behavioral Subclassing (or Subtyping). Note that it is **strong** because it defines semantic substitution of types; the use of simple syntactical substitution fails. For the paranoid (i.e., me), one can ensure semantic correctness with things like software contracts [4]. 5.1.2. The Single Responsibility Principle (SRP) This principle states that every class should have responsibility over one, and only one, part of the functionality provided by the program. More specifically, there should only be one function in the specification of the class that causes it to change. This is routinely violated (e.g., Martin's example of a class that compiles and prints a report). Furthermore, the responsibility should be encapsulated within that class, and that services it provides should support that responsibility, and only that responsibility. In particular, this avoids the (systemic and far too prevalent) problem of changing one class, but breaking other parts of the system. It also enables the function of each class to be related back to a specific requirement. 5.1.3. The Open-Closed Principle (OCP) This principle states that software entities should be open for extension, but closed for modification. For example, the software entity can allow its behavior to be extended without modifying its source code. The difference between open and closed is that once a class has one or more clients, it is closed for modification, since changes to it will adversely affect the classes that use it. 5.1.4. Software Contracts A software contract is a mechanism to specify semantics abstractly. For any interaction, one or more of the following three mechanisms are required to specify the semantics of the interaction: - pre-conditions (e.g., the conditions imposed on the rest of the system before a method can execute) - post-conditions (e.g., the conditions guaranteed to the rest of the system after a method has executed) - invariants (e.g., consistency constraints maintained throughout the method execution) 5.2. The guidance "Properties may be added to existing classes" This is a really BAD idea. This violates at least the SRP and the OCP; in some cases, it will also violate the LSP. More importantly, if you have already generated data models from an information model, this causes regeneration of those data models. It can be thought of as changing the schema, which typically causes recompilation and redeployment. There are more robust ways to do this (e.g., the decorator pattern or the adapter pattern, depending on what, exactly, you would like to do). 5.3. The guidance about Deprecation There are many valid reasons to deprecate software elements. Some include: - the feature or function is insecure - the feature or function is buggy - the feature or function will be removed in a future release The obvious problem with deprecation is that it tends to break implementations that are using the deprecated features. While deprecation is sometimes necessary, it should be documented in the code, not somewhere else (e.g., as Eclipse API deprecation recommends). Unfortunately, this is not followed in PCIMe. For example, the priority attribute is deprecated in PolicyRule in PCIMe. Section 6.3 says: Priority DEPRECATED FOR PolicySetComponent.Priority AND FOR PolicySetInSystem.Priority which, to a non-modeler, looks like it is being replaced by two attributes that unfortunately have the name (which in itself is bad). It would be much more useful to note that the priority attribute is being deprecated for an attribute of the same name, but the attribute is moved to two different association classes. The high-level problem with deprecation in PCIMe is that it effectively rewrites most of PCIM. This is because deprecation is used as a general redesign mechanism (e.g., moving attributes from one class to another or to a relationship, or adding to existing classes; both break backwards-compatibility). Some features that were deprecated (e.g., PolicyRepository) frankly don't matter, as the definition was poor and needed augmentation anyway. Other features that were deprecated (e.g., replacing the two aggregations PolicyGroupInPolicyGroup and PolicyRuleInPolicyGroup with the single aggregation PolicySetComponent, or refactoring the priority attribute) will break existing implementations, even if they are better options. 5.4. The guidance about generalization. PCIMe says: "Classes may be inserted into the inheritance hierarchy above existing classes, and properties from the existing classes may then be "pulled up" into the new classes. The net effect is that the existing classes have exactly the same properties they had before, but the properties are inherited rather than defined explicitly in the classes." This violates the LSP, SRP, and OCP. It breaks implementations, and the statement is incorrect if the affected classes are all concrete; this also breaks data models. 5.5. The guidance about specialization. PCIMe says "New subclasses may be defined below existing classes". While this is true in general, care must be taken to obey the LSP, SRP, and OCP, or implementations will suffer. 6. References [1] Gamma, E., Helm, R., Johnson, R., Vlissides, J., "Design Patterns - Elements of Reusable Object-Oriented Software", Addison-Wesley, 1994, ISBN 0-201-63361-2 [2] Liskov, B.H., Wing, J.M., "A Behavioral Notion of subtyping", ACM Transactions on Programming languages and Systems, 16 (6): 1811 - 1841, 1994 [3] Martin, R.C., "Agile Software Development, Principles, Patterns, and Practices", Prentice-Hall, 2002 ISBN: 0-13-597444-5 [4] Meyer, B., "Object-Oriented Software Construction", 2nd edition, Prentice Hall, 1997 ISBN: 0-13-629155-4
- [I2nsf] Post 2b: Background Information on PCIMe … John Strassner