Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ __IMPORTANT NOTICE:__ The contents of this repository currectly reflect a __DRAF
1. [Event Structure](./eiffel-syntax-and-usage/event-structure.md)
1. [The Meta Object](./eiffel-syntax-and-usage/the-meta-object.md)
1. [The Links Object](./eiffel-syntax-and-usage/the-links-object.md)
1. User Examples
1. The Eiffel Vocabulary
1. [EiffelActivityTriggeredEvent](./eiffel-vocabulary/EiffelActivityTriggeredEvent.md)
1. [EiffelActivityCanceledEvent](./eiffel-vocabulary/EiffelActivityCanceledEvent.md)
Expand All @@ -37,6 +36,9 @@ __IMPORTANT NOTICE:__ The contents of this repository currectly reflect a __DRAF
1. EiffelTestExecutionRecipeCollectionCreated
1. EiffelAnnouncementEvent
1. EiffelConfigurationChangedEvent
1. Usage Examples
1. [Confidence Level Joining](./usage-examples/confidence-level-joining.md)
1. [Delivery Interface](./usage-examples/delivery-interface.md)
1. Implementations
1. [Event Persistence](./implementations/event-persistence.md)
1. [Event Aggregation and Analysis](./implementations/event-aggregation-and-analysis.md)
Expand Down
1 change: 1 addition & 0 deletions usage-examples/confidence-level-joining.gliffy

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions usage-examples/confidence-level-joining.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
# Confidence Level Joining Example
This example illustrates how [EiffelConfidenceLevelModifiedEvent](../eiffel-vocabulary/EiffelConfidenceLevelModifiedEvent.md) can be used to capture and summarize a larger body of lower level results, such as test suite verdicts, effectively _joining_ multiple flows in the continuous integration and delivery system.

A JSON array of all events used in this example can be found [here](https://github.com/Ericsson/eiffel-examples/blob/master/flows/confidence-level-join/events.json).

## Introduction
A common use case in continuous integration and delivery systems is to join many separate (and disparate) tests into a larger entity, providing a stamp of approval to the item under test. In Eiffel, such stamps are provided by [EiffelConfidenceLevelModifiedEvent](../eiffel-vocabulary/EiffelConfidenceLevelModifiedEvent.md). This not only serves the purpose of raising the level of abstraction, thereby facilitating analysis and release decisions, but also provides a pragmatic extension point of the production pipeline: an external listener (e.g. a product looking to integrate the item under test) is not interested in tracking individual test case results, particularly as they may well change over time or even from execution to execution, but simply wants to know "Is this artifact good enough for me to pick up?".

## Event Graph
![alt text](./confidence-level-joining.png "Event Graph of Confidence Level Joining Example")

## Event-by-Event Explanation
### ArtC1
The [EiffelArtifactCreatedEvent](../eiffel-vocabulary/EiffelArtifactCreatedEvent.md) is central in this example. It declares that a new artifact has been created, and (largely via links) documents how and from what it was built. At the time of this event we still know very little about the artifact: it has unique coordinates (its GAV), but where to fetch it or whether it is any good remains to be seen.

### CDef1
An [EiffelCompositionDefinedEvent](../eiffel-vocabulary/EiffelCompositionDefinedEvent.md) detailing a composition of items (such as source code revisions and other artifacts), from which the artifact declared by __ArtC1__ was built. The elements of the composition, the reason for defining the composition et cetera are excluded in this example.

### EDef1
An [EiffelEnvironmentDefinedEvent](../eiffel-vocabulary/EiffelEnvironmentDefinedEvent.md) describing the environment in which the artifact declared by __ArtC1__ was built.

### ArtP1
The [EiffelArtifactPublishedEvent](../eiffel-vocabulary/EiffelArtifactPublishedEvent.md) declaring that the created artifact now has been published, and consequently may be fetched. Since __ArtC1__ itself declares the GAV, the artifact _may_ be fetched using only that information (assuming a binary repository supporting this, such as Artifactory), but it is still recommended practice to explicitly declare when and where the artifact can be retrieved, in order to avoid outages or timing issues.

### ActT1, ActT2, ActS1, ActS2, ActF1, ActF2
A set of [EiffelActivityTriggeredEvent](../eiffel-vocabulary/EiffelActivityTriggeredEvent.md), [EiffelActivityStartedEvent](../eiffel-vocabulary/EiffelActivityStartedEvent.md), [EiffelActivityFinishedEvent](../eiffel-vocabulary/EiffelActivityFinishedEvent.md) reporting on the lifecycle of two independent activity executions being caused by the publication of the artifact. Note that the EiffelActivityStartedEvents and EiffelActivityFinishedEvents are "dead ends" in the graph: in this example, nothing occurs as a direct cause of the activity starting or finishing (although such a setup is, of course, entirely possible) and the work being done within the activity refers directly to the EiffelActivityTriggeredEvent as its context. This shows how, in one sense, this type of lifecycle events is superfluous: for the core functionality of this example it is perfectly possible to cut them out and let the EiffelTestCaseStartedEvents refer directly to __ArtP1__ as their cause. Activity events do provide important contextual information, however, as they allow monitoring of e.g. system performance, bottlenecks, queue times and execution durations. They also serve the purpose of clustering work; in this example, __ActT1__ and __ActT2__ may represent activities executed at wildly different times, at different locations and by different organizations.

### TCS1, TCS2, TCS3, TCS4
[EiffelTestCaseStartedEvents](../eiffel-vocabulary/EiffelTestCaseStartedEvent.md) declaring that, as part of their respective activities, test cases have been launched. In this example only a very small number of test cases are executed - in reality, these events tend to be very numerous. Note that the cause of the execution can be traced to __ArtC1__ via __links.context__ and __links.causes__. This is not enough to unambiguously identify the item under test, however: it is entirely conceivable that the immediate cause for executing the test is completely independent from the item under test. Consequently __links.iut__ is used to reference __ArtC1__ directly.

### TCF1, TCF2, TCF3, TCF4
[EiffelTestCaseFinishedEvents](../eiffel-vocabulary/EiffelTestCaseFinishedEvent.md) reporting the verdict of their respective test case executions.

### CLM1
The [EiffelConfidenceLevelModifiedEvent](../eiffel-vocabulary/EiffelConfidenceLevelModifiedEvent.md) that summarizes all of the test case executions under a single headline. Note that the algorithm for determining this confidence level may be simple or relatively complex, but an important point of the event is that this algorithm is evaluated close to those tests, affording separation of concerns for users (human or automated) who simply want to know whether the relevant tests worked, whichever those tests happened to be at that point in time. This way the nitty gritty details are abstracted away. It doesn't end there, however: while not included in this example, __CLM1__ may in turn be but a building block of subsequent, even higher level EiffelConfidenceLevelModifiedEvents.
Binary file added usage-examples/confidence-level-joining.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions usage-examples/delivery-interface.gliffy

Large diffs are not rendered by default.

60 changes: 60 additions & 0 deletions usage-examples/delivery-interface.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Delivery Interface Example
Eiffel messaging can favorably be used to implement software delivery interfaces between products and organizations. This is typically achieved by a system placing requirements on the events its constituent parts must use to communicate that they offer a new candidate for integration, and then driving that integration by reacting to those events. The Eiffel vocabulary offers considerable freedom in the level of detail of such interfaces - as always, an important principle is freedom in _what_ you communicate, but not in _how_ you communicate it. Consequently what is presented here is an example of the event usage a system may require from its constituent parts in order to ensure a satisfactory level of traceability; actual implementations may require more or less, but the essential building blocks are the same.

## Introduction
A prime concern in designing delivery interfaces is to ensure traceability across products, organizations and enterprises. From a traceability point of view the links of particular interest are typically content and quality related ones: what does this artifact contain, what has changed, has it been tested etc. Consequently this example focuses on those events and links; all causality links and activity events have been excluded. This does not mean that no such events and links may be used, however, but merely that they are not a required part of the delivery interface in this particular example.

In this example the [EiffelConfidenceLevelModifiedEvents](../eiffel-vocabulary/EiffelConfidenceLevelModifiedEvent.md) __CLM1__ and __CLM2__ are used to signal that a new candidate is considered good enough to be integrated (__ArtC1__ and __ArtC2__), while the remaining events provide context and meta-data.

A JSON array of all events used in this example can be found [here](https://github.com/Ericsson/eiffel-examples/blob/master/flows/delivery-interface/events.json).

## Event Graph
![alt text](./delivery-interface.png "Event Graph of Delivery Interface Example")

## Event-by-Event Explanation
### SCC1, SCC2, SCC3, SCS1, SCS2, SCS3
The [EiffelSourceChangeCreatedEvents](../eiffel-vocabulary/EiffelSourceChangeCreatedEvent.md) declare that changes have been made and describe what they entail, by referencing work items, requirements et cetera. This does not mean mean that the change has been merged onto the project mainline (or other relevant branch) - this is instead declared by The [EiffelSourceChangeSubmittedEvent](../eiffel-vocabulary/EiffelSourceChangeSubmittedEvent.md). The distinction between the two is important when working with review processes, private repositories and/or pull requests. If none of that is applicable, the two events are simply sent at once.

The structure of events shown in this example represents a common development branch, where changes are represented by __SCS1__, SCS2__ and __SCS3__. Each of these submitted changes references a EiffelSourceChangeCreatedEvent via __links.change__, and also points to the latest previously submitted version(s). This establishes an unbroken chain of source revisions along with a record of the process leading up to that submission.

### CDef1, CDef2, CDef3
[EiffelCompositionDefinedEvents](../eiffel-vocabulary/EiffelCompositionDefinedEvent.md) declaring that new compositions are available to be built. Note that in this example not every composition leads to the creation of a new artifact. In industrial practice this is a common phenomenon, for which there may be a number of reasons - often there simply isn't sufficient time or resources to build each individual change.

Note that EiffelCompositionDefinedEvents may reference any number of elements: often a composition doesn't just consist of the one source revision, but a large collection of sources, binaries and third party libraries.

### ArtC1, ArtC2
The [EiffelArtifactCreatedEvents](../eiffel-vocabulary/EiffelArtifactCreatedEvent.md) representing new versions of the built software.

### TCS1, TCS2, TCF1, TCF2
[EiffelTestCaseStartedEvents](../eiffel-vocabulary/EiffelTestCaseStartedEvent.md) and [EiffelTestCaseFinishedEvents](../eiffel-vocabulary/EiffelTestCaseFinishedEvent.md) representing one test execution per artifact (__ArtC1__ and __ArtC2__, respectively). Note that management of test cases per se is not within the scope of Eiffel, but like many events EiffelTestCaseStarted is able to reference external entities. Furthermore, it is assumed in this example that these externally managed test case descriptions in turn are able to reference any requirements they verify (which is arguably good practice in any context). With those references in place, these events can be used to answer the question "Which requirements have been verified in which version of the product, and what was the outcome?".

### CLM1, CLM2
[EiffelConfidenceLevelModifiedEvents](../eiffel-vocabulary/EiffelConfidenceLevelModifiedEvent.md) signaling that a new version of this component or part of the system is deemed ready for delivery. In this example, this is the event that the next tier of the system hierarchy reacts to, and proceeds to pick up the referenced artifact (__ArtC1__ and __ArtC2__, respectively) to integrate it.

## Traceability in Practice
Analysis of the events provided in this example (and the external data sources referenced by them) can, purely from a systems integration point of view, be used to answer the following questions:
* Which test cases have succeeded and/or failed for __ArtC2__, as opposed to __ArtC1__?
* When was a certain source change first delivered?
* When was a certain requirement/feature implementation first delivered?
* Which requirements have been verified in __ArtC2__, as opposed to __ArtC1__?
* What is the source code diff from __ArtC1__ to __ArtC2__?
* Which requirements, tasks and/or features have been implemented between __ArtC1__ and __ArtC2__.

Let's take a closer look at answering the last question by going through the process one step at a time.

1. Identify the two artifact versions to be compared. Depending on the use case, the versions to be compared can either be explicit or implicit: "I want to compare __ArtC2__ and __ArtC1__" or "I want to compare __ArtC2__ to its previous version". In the latter case, __links.previousVersions__ can be traced to the object of interest.
1. Build a list of constituent EiffelSourceChangeSubmittedEvents of the newer artifact (__ArtC2__):
1. Identify the composition of the artifact (__CDef3__).
1. Append any EiffelSourceChangeSubmittedEvents referenced via __links.elements__ (__SCS3__).
1. Recursively apply the process to any EiffelArtifactCreatedEvent or EiffelCompositionDefinedEvent referenced via __links.elements__ (none, in this example).
1. Repeat the process for the older artifact (__ArtC1__).
1. Identify the delta of EiffelSourceChangeSubmittedEvents between the two lists ({__SCS3__} and {__SCS1__}, respectively):
1. Remove any EiffelSourceChangeSubmittedEvents present in both lists (none, in this example).
1. Include any remaining EiffelSourceChangeSubmittedEvents in the newer list (__SCS3__).
1. Recursively follow __links.previousVersions__ of these events, including everything up until anything in the list of the old version (in this example, yielding __SCS2__).
1. Any events in the list of the old version not hit upon represent deletions.
1. The resulting delta is {__SCS3__, __SCS2__}.
1. For each EiffelSourceChangeSubmittedEvent in the list, follow __links.change__ to its corresponding EiffelSourceChangeCreatedEvent.then append to the final output all elements of their __data.issues__ arrays ({__Req2__, __Req1__, __Task1__}). Note that these objects contain a field describing the _transition_ of the issue (i.e. what happened to it as a consequence of the source change - was it completed or removed?); for more information, see [EiffelSourceChangeCreatedEvent](../eiffel-vocabulary/EiffelSourceChangeCreatedEvent.md).
1. Repeat the process for the list of deletions and append any issues thus discovered, but inverting the transition.

Following these steps we find that __Req2__, __Req1__ and __Task1__ were completed between __ArtC1__ and __ArtC2__. Furthermore, this information is propagated throughout the enterprise and persistently stored, regardless of the issue handling tools or processes used by the individual development unit.
Binary file added usage-examples/delivery-interface.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.