Flaws in concept definitions

This document lists and explains common flaws in concept definitions.

Flaws in concept boundaries. These flaws address the way in which functionality is divided up amongst concepts.

  • Conflation. The concept conflates two different aspects of functionality, that could be separated into two concepts without causing fragmentation. Example: a concept includes both user authentication and user profiling. Often conflation is the result of an object-oriented point of view in which all functionality associated with some object type is mistakenly put in a single concept. Example: a concept that manages information about users that includes not only authentication but also karma points that are accrued as a measure of good behavior (and are completely unrelated to authentication and easily separated from it). Sometimes conflation is more subtle and subjective, and simplicity may argue for a single concept but a more rigorous separation of concerns for two. Example: authentication of users and session management can be easily separated into two concepts, and doing so allows each to be reused without the other (authentication of special requests without sessions, for example) and prevents coupling of design decisions (the use of passwords for authentication and the use of session tokens for sessions, which should be independent). Nevertheless, a concept that includes both authentication and sessioning (with actions to register for an account, then login and logout) is simpler to understand and not unreasonable.
  • Fragmentation. A single aspect of functionality is split across two concepts, resulting in needless duplication of state and excessive synchronization. Example: the functionality of a shopping cart is split into a concept that handles additions of items to the cart, and a separate concept that manages checkout. A cause of this is a misunderstanding that different temporal phases in functionality deserve different concepts. Example: registering for an account is a distinct activity phase from logging in, but both are part of authentication and share essential state (usernames and passwords) so cannot be profitably separated. Sometimes this is plausible, when the phases are very distinct and involve different kinds of users, and may be separately reused. Example: separate concepts for creating surveys and collecting user responses can make sense, because the activities are elaborate in their own right, independently reusable (a concept for creating and editing surveys could have a pedagogical use even without answers being collected, and a concept for collecting answers could be used for different kinds of surveys with differences in how questions are structured).

Violations of modularity. These flaws address egregious violations of the principles of modularity in concept design.

  • Data dependence on another concept. The concept may imply (for example in the definition of an action) that a property of an external individual that is defined in another concept is dereferenced by this concept. This misunderstands the idea of individuals in concept design, which are always represented only by their identities, and associated with properties by the states of each concept, with those properties never accessible outside. Novices may make this mistake because they think of individuals as composite objects with fields that can be accessed. Example: a user authentication concept defines a state that assigns a username to each user; a concept that manages social media posts defines a state that assigns a user as an author to a post; the specification of the posting concept erroneously refers to the username of the author, which is not accessible in that concept.
  • Function calls to another concept. Concepts never have calls from the internals of one concept to the interface of another; all coordination is external, with synchronizations defining how actions of one concept are coordinated with actions of another. This is the only way that data can flow from one concept to another, and the only way that an action occurrence in one concept can cause an action occurrence in another. Example: a user authentication concept mentions that the effect of registering for an account includes notifying the user using a notifying concept. This could be specified as a sync associated with the concept, but any intimation that there is a direct call (for example mentioning such a call in the specification of the registering action) is mistaken and violates concept independence.
  • Reference to the system or to other concepts. Concepts should be independent and standalone, so that they can be reused in different contexts. It is therefore a mistake to reference the role that the concept plays in the larger system or the existence of other concepts. This is especially true in the definitions of states and actions. Example: in a user authentication concept intended for use in a social media app, the purpose should be to authenticate users and not to 'authenticate users when the create or edit posts'; the action for registering should not say something like 'registers a user of the social media app'. There are three important exceptions to this rule. First, the notes section of a concept is expected to include information about the role of the concept in the system and its relationship to other concepts (although preferably such notes should be clearly delineated from notes that are about the concept in isolation). Second, sometimes a concept's purpose is rather application specific and careful referencing of some application details may be helpful in explaining it. Third, the operational principle is often easier to understand and more compelling if it presumes the existence of actions from other concepts (although preferably it makes clear that these actions are external). Example: the operational principle of a notifying concept may say that 'after a user registers interest in a type of event, if an event of that type occurs, which is conveyed to the concept by the update action, then a notify action occurs, which causes the user to be receive a communication about the event (through a sync with a communication concept)'.

Flaws in overall structure. These flaws are internal to the concept (not involving other concepts) but are not specific to any particular concept part.

  • Mixing of parts. Concept definitions are broken into parts, each with their own role. If a definition mixes these, it can become hard to understand and information is hard to find. The purpose of the concept should not include information that belongs to the operational principle, by describing a scenario. Example: the purpose of a user authentication concept talks about users registering and then authenticating. The operational principle should not encroach on the purpose by explaining why something happens. Example: the operational principle of a karma tracking concept mentions that when a user receives karma points this is to reward them for good behavior. The operational principle should not encroach on the state declarations or action definitions. Example: the operational principle of a user authentication concept should not say that after a user registers, their username and password are stored, since the definition of the registering action would cover that; the operational principle of a notifying concept can say that a user can add multiple communication channels and then select one as a default, but should not duplicate the state declaration saying that users have zero or more communication channels.
  • A class, not a concept. Some novices are confused about the difference between concepts, which define aspects of functionality, and entities in a data model, which define a set of individuals and their relationships to others (across all aspects of functionality). Symptoms of this confusing include: the concept lacking any interesting behavior (with an operational principle that may have just CRUD actions); conflation of functionality (see above); a state declaration that describes a single object; a concept name that corresponds to an entity or object class rather than some functionality; a purpose that has little substance and may just talk about representing or managing some objects. Example: a concept called User whose purpose is 'to manage users'; whose operational principle involves creating users, setting their properties and looking them up'; whose state is a collection of attributes that conflate aspects of functionality (username, displayname, karma, etc).

Flaws in the concept name.

  • Conveys an object or object type, not functionality. A concept name that does not indicate what kind of functionality is supported is not helpful. Example: in an online bookstore, calling a concept Book would not tell you anything about what it does; in contrast, names like BookInventory or BookCatalog suggest more (respectively tracking how many instances of a given book are on hand, and helping users find books based on their details). One strategy is to try and use gerunds as names. Regular nouns can be reasonable names too, especially when they describe activities, but they should preferably not coincide with the names of individual types. Example: in a restaurant reservation system, Reservation is a reasonable name but would conflict with the same word used to define the type individuals that are created when users make reservations. (Note: in my book, Essence of Software, I did this frequently, assuming that the names of concepts and types could be disambiguated by context. In retrospect this was a mistake as it causes confusion, especially to novices who haven't fully grasped that concepts aren't objects.)

Flaws in the purpose.

  • Vague or superficial purposes. Defining the purpose of a concept can be very challenging, but is very rewarding. And not having a compelling purpose can be a symptom of not really understanding why the concept is needed at all. Example: the purpose of the Trash concept (as introduced by Apple in the early 1980s) is not, as many explanations suggest, to ease deletion of items, but the very opposite: to prevent complete deletion and to support undeletion.
  • Not distinguishing concept from others. The purpose needs to justify the concept at hand, and so it should distinguish this concept from others. Therefore a purpose that could equal well apply to other concepts, and particularly that does not justify the behavioral design of the concept at hand, is insufficient. Example: a styling concept that lets users associate formatting styles with elements and then update the styles so that all elements are reformatted consistently is fundamentally different from a concept that simply lets users apply a predefined style to an element but does not propagate changes to the style to the elements. So the purpose needs to capture this, by saying something like 'supports consistent styling and restyling of sets of elements' rather than just 'eases the application of styles to elements'. Example: a concept for access tokens should not have a purpose that just mentions authenticating access, since the key point of access tokens is to allow a user to delegate access to multiple parties.
  • Overloading. A concept should have one purpose, and not more than one (since they are likely to be in conflict with one another). Example: the purpose of a reaction concept in a social media app should not be both to convey an emotional response to the author of a post and to rank posts by popularity and to collect user preferences for recommendations. These are all valid purposes, but belong to separate concepts (which might be synchronized so that a single request from a user causes actions in multiple concepts to occur related to these different functions).

Flaws in the operational principle.

  • Omits setup actions. The operational principle should be a complete scenario, including whatever actions are needed to set up the state. Example: the operational principle of concept for role based access control should not start with assigning roles to users, but should include the initial creation of the roles themselves.
  • Inadequate scope. There must be enough actions and individuals to demonstrate fulfillment of the purpose. Example: for an upvoting concept, the principle must describe a scenario involving multiple users and items. Saying something like 'after a user upvotes an item, the upvote count has increased by one' does not explain how the concept helps in the purpose (of ranking items by popularity). Example: for a styling concept, to demonstrate how the concept fulfills the purpose of maintaining consistency, the principle has to describe an updating to a style that has been previously applied to multiple elements, not just one.
  • Includes unhappy paths. The operational principle defines the archetypal scenario and does not need to include unhappy paths. Example: a reserving concept need not include canceling of reservations. Sometimes, however, an action that at first sight might be regarded as falling this category turns out to be essential to the purpose of the concept, and should be included. Example: in an access token concept, the principle should mention revoking tokens, since the ability to revoke tokens individually is a key part of the concept design and serves the purpose of delegating to potentially untrustworthy parties.
  • Includes error cases. The operational principle defines the archetypal scenario and does not need to describe how errors are handled. Example: the principle of a user authentication concept need not describe what happens if a user registers with a username that is already taken.

Flaws in the state.

  • Singleton scope. The state of a concept is almost never about a single individual. A common misunderstanding is to view a concept as if it were an object-oriented class, and to define the state as a list of fields of a single object, when instead the state should have introduced a set of individuals with a relation for each field. Example: a user authentication concept defines the state as having components such as a username and password. The action to authenticate a user will require looking up the username to find a matching user, and so the state must be defined as a set of users, each with a username and password.
  • Reference vs. object. Those with a programming background are sometimes confused about the way in which individuals are represented in concepts. An individual is always just an identity, so the 'value' or 'content' of an individual will be an identifier. The relations of the state will map this identifier to the identifers representing other individuals (or to primitive values). So unlike in some programming languages, there is no distinction between references to individuals and the individuals themselves.
  • Making identifiers explicit. Because every individual has an identity, there is no need to declare an identifier explicitly for any individual. In some concepts, however, the creation and use of identifers is an important part of the functionality and should be defined explicitly. Example: in a social security system, there will be a concept that manages the creation and uniqueness of social security numbers. Example: a concept for URL shortening will generate identifiers that form the shortened URLs.
  • Not sufficient to support actions. The state must be sufficiently rich to support the actions that are defined. So an action should never refer implicitly or explicitly to state components that have not been declared. Example: in an upvoting concept, if the upvoting action is described as not permitting double voting, then the state must include not only the number of votes that each item has received, but also which user voted for which item.
  • Not enough keys for relations. The state may require that two different individuals are keys for a mapping to some other individual, but is declared so that only one key is mapped. The easiest fix is to introduce a new set of individuals representing a relationship. Example: a concept for managing salaries has a relation that maps employees to their salaries, but this does not account for the fact that an employee can work for several companies at the same time, so the correct mapping is from both employee and company to salary. The fix is to introduce a new individual type (say of jobs), and then an employee has a set of jobs, each with an associated salary and company.
  • Vague declarations. Some informality in state declarations may be acceptable in the early stages of development of a concept, but is likely to be problematic if left unclarified. Example: the state says that a file is associated with 'a version history', without explaining what this means (a sequence of version numbers? of versions of the file? maybe a tree rather than a sequence?).
  • Redundant state components. The state should not include redundancies of the sort that would be typical in an implementation because they might be thought to allow more efficient queries. The relations that appear in state declarations are semantically directional, but this does not imply that they can only be navigated in one direction. Example: in a concept for reserving tables in restaurants, the state may define a set of Reservations with a User that introduces an implicitly named relation user from reservations to users; it would be a mistake to also declare a relation in the other direction, for example by writing a set of Users with a set of Reservations, introducing the transpose relation reservations from a user to their reservations. The reason is that an action or query can refer to the reservations of a user without this reverse relation needing to be defined. Aside from being redundant, the additional relation would also impose an invariant that would have to be maintained (either by updating one relation whenever the other is updated, or by declaring an invariant and stating that it is implicitly maintained). Note that it is not redundant to declare a relation that maps to some set of individuals, and then to declare that set of individuals separately: the relation declaration serves to define the range of the relation, and the set declaration that follows serves to define a general set of individuals and to associate relations with them. Example: the state might declare a set of Users with a set of Accounts, which says that each user can have multiple accounts, and then declare a set of Accounts with a username String, which introduces the set of all accounts (independently of the accounts of a single user) and associates a username with each account.

Flaws in the actions.

  • Missing actions. Actions are missing that should have been included. These might be actions for setting up the state or for creating individuals that other actions require as inputs; actions for undoing or compensating for other actions; actions associated with terminating or ending a service. Examples: a concept for templating omits actions for creating templates; a concept for reserving conference rooms omits an action to cancel a reservation; a concept includes creating an account but no action for deleting it.
  • Redundant actions. The collection of actions should be as small as possible while being sufficiently expressive to cover user behaviors. Just because a user might make a request in different forms does not mean that a separate action is required in each case, because synchronizations can be used to link a single user action to multiple concept actions. Example: an authentication concept has an action to allow a user to change their password, which takes the user individual as an argument. One might be tempted to include an additional action that has the username as an argument instead, but such an action would not be needed since the concept already allows the user to be obtained from the username (via the state, and probably also by a defined query).
  • Disjunctive specifications. An action should not have a variety of unrelated effects depending on the state and the action's arguments. A sure sign of this flaw is a 'disjunctive' specification saying 'this happens or this happens or this happens', or that lists multiple cases or has complex if-statements in it. Another symptom is optional arguments that result in different behavior, or worse, flag arguments, which, especially in combination, cause a blowup in the number of cases to consider. Example: in a styling concept, an action to define a new style includes an existing style as an optional argument, allowing a style to be defined either as a top-level style or as a child of an existing style; instead, two distinct actions should be defined for the two cases. Example: an action to make a reservation allows an optional argument of an existing reservation, with the intended behavior being that if a reservation is included, the new reservation should replace the previous one. This is an incoherent and needlessly complicated action; having separate actions to cancel and reserve is enough.
  • Missing precondition. There should be no implicit preconditions that must hold to allow the action occur; any preconditions must be explicitly stated. Example: in a reserving concept whose state has an invariant that each reservation has a unique slot (so no slot is reserved twice), an action to create a reservation for a slot cannot implicitly assume that the slot is not already reserved but should specify this as a precondition.
  • Precondition appears as a case in the postcondition. An occurrence of an action should mean something, so it is usually undesirable to specify an action that has no effect despite executing successfully. This can happen when an if-condition is used in the postcondition rather than a precondition, which would prevent the action from happening. Example: in a reserving concept whose state has an invariant that each reservation has a unique slot (so no slot is reserved twice), an action to create a reservation for a slot should not have a postcondition that says that if the slot is already reserved, nothing happens, since the successful execution of the action might suggest that a reservation has been made; instead the constraint should be in a precondition.
  • Error handling not needed. In a design-level concept definition, an action need not specify error outcomes. Example: in a user authentication concept, the action for registering a new user can just have a precondition saying that the username is unique and that the username and password are well formed. In a concept specification intended for generating code, it would be appropriate to include a refuses case that raises an informative error instead, but this complication can be omitted in the interests of succinctness and focus in a design-level spec.
  • Queries presented as actions. Actions that never update the state and that are executed to obtain information from the state are better viewed as queries, which are marked with an underscore at the beginning of their name, and which have a returns clause rather than a pre/postcondition. Example: in a reserving concept, one might want to obtain the reservation for a particular slot. Since the state is regarded as visible, it is not necessary to define this specially, but if one wanted to emphasize this particular state lookup, one could define a query for it. Note that in some cases an action may not update the state but its occurrence may still be considered to be important in the behavior of the concept, and in that case, an action would be suitable. Example: in a user authentication concept, the step in which a user is authenticated by successfully matching username and password would be appropriately represented as an action, despite having no effect on the state. This is because being authenticated is a significant event. Contrast this with, for example, a query for extracting the author of a social media post, which is likely to be performed repeatedly in an implementation (for example, whenever the post is displayed), but which does not correspond to an event of significance to any stakeholder.

Inadequate notes. The notes of a concept provide background justifications, discussions of design variants and other options considered, concerns about the design as given, and so on. The concept definition provides a useful place to centralize ongoing work related to the design of the concept. A desire to keep the concept definition clean and simple is admirable, but should not lead to reluctance to use the notes section expansively. Concept designers should bear in mind especially the important role that concepts have in bridging between different teams and different professional specialties. Readers from other teams and specialties may lack the background and assumptions that motivated the concept, so it is a good idea to include notes for these. Each note can be given a short title so that it can be skipped by readers with more background.