Subject: [I2nsf] Post 2b: Background Information on PCIMe (Modeler Details)

From: John Strassner <[email-masked]>
Date: Fri, 11 Dec 2015 14:07:52 -0800

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