Skip to content

Commit c68f2a7

Browse files
authored
Merge pull request #149 from itsallcode/story/115-Passdown_specification_items
Story/115 passdown specification items
2 parents 5000055 + 20a9e8c commit c68f2a7

19 files changed

Lines changed: 393 additions & 87 deletions

.circleci/config.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,3 @@ jobs:
3535

3636
- store_test_results:
3737
path: target/surefire-reports
38-

doc/design.md

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ Since the specification item IDs inherently look similar, load tests need to sho
8787
## Importers
8888
For each specification artifact type OFT uses an importer. The importer uses the specification artifact as data source and reads specification items from it.
8989

90-
## Import Event Listeners
90+
## Import Event Listener
9191
Importers emit events if they find parts of a [specification item](#specification-item) in the artifact they are importing.
9292

9393
### Specification List Builder
@@ -336,7 +336,7 @@ Needs: impl, itest
336336
### Internal Data Structures
337337

338338
#### Specification Item
339-
`dsn~specification-item~2`
339+
`dsn~specification-item~3`
340340

341341
A `SpecificationItem` consists of the following parts:
342342

@@ -351,10 +351,16 @@ A `SpecificationItem` consists of the following parts:
351351
* Depends (List of `SpecificationItemId`, optional)
352352
* Needs (List of `String`, optional)
353353
* Tags (List of `String`, optional)
354+
* Forwards (`boolean`, internal)
355+
356+
Comment:
357+
358+
See `req~forwarding_needed_coverage~1` for an explanation of the "forwards" fields meaning.
354359

355360
Covers:
356361

357362
* `req~specification-item~2`
363+
* `req~forwarding_needed_coverage~1`
358364

359365
Needs: impl, utest
360366

@@ -395,13 +401,13 @@ Needs: impl, utest
395401
A requirement ID has the following format
396402

397403
requirement-id = type "~" id "~" revision
398-
404+
399405
type = 1*ALPHA
400-
406+
401407
id = id-fragment *("." id-fragment)
402-
408+
403409
id-fragment = ALPHA *(ALPHA / DIGIT / "_" / "-")
404-
410+
405411
revision = 1*DIGIT
406412

407413
Rationale:
@@ -435,6 +441,7 @@ Markdown titles show up in the outline and are a natural way of defining a requi
435441
Covers:
436442

437443
* `req~markdown-standard-syntax~1`
444+
* `req~markdown-outline-readable~1`
438445

439446
Needs: impl, utest
440447

@@ -444,9 +451,9 @@ Needs: impl, utest
444451
In Markdown specification item references have the following format:
445452

446453
reference = (plain-reference / url-style-link)
447-
454+
448455
plain-reference = requirement-id
449-
456+
450457
url-style-link = "[" link-text "]" "(" "#" requirement-id ")"
451458

452459
Covers:
@@ -461,9 +468,9 @@ Needs: impl, utest
461468
The Markdown Importer supports the following format for links that cover a different specification item.
462469

463470
covers-list = covers-header 1*(LINEBREAK covers-line)
464-
471+
465472
covers-header = "Covers:" *WSP
466-
473+
467474
covers-line = *WSP "*" *WSP reference
468475

469476
Only one traced reference per line is supported. Any optional text after the reference is ignored if it is separated by at least one whitespace character
@@ -484,9 +491,9 @@ Needs: impl, utest
484491
The Markdown Importer supports the following format for links to a different specification item which the current depends on.
485492

486493
depends-list = depends-header 1*(LINEBREAK depends-line)
487-
494+
488495
depends-header = "Depends:" *WSP
489-
496+
490497
depends-line = *WSP "*" *WSP reference
491498

492499
Only one traced reference per line is supported. Any optional text after the reference is ignored if it is separated by at least one whitespace character
@@ -522,6 +529,30 @@ Covers:
522529

523530
Needs: impl, utest
524531

532+
#### Markdown Artifact Forwarding Notation
533+
`dsn~md.artifact-forwarding-notation~1`
534+
535+
The Markdown Importer supports forwarding required coverage from one artifact type to one or more different artifact types using the following notation.
536+
537+
artifact-need-redirection = skipped-artifact-type *WSP "-->" *WSP target-artifact-list
538+
*WSP ":" *WSP original-requirement-id
539+
540+
skipped-artifact-type = artifact-type
541+
542+
target-artifact-list = artifact-type *("," *WSP artifact-type)
543+
544+
original-requirement-id = requirement-id
545+
546+
The following example shows an architectural specification item that forwards the needed coverage directly to the detailed design and an integration test.
547+
548+
arch --> dsn, itest : req~skip-this-requirement~1
549+
550+
Covers:
551+
552+
* `req~artifact-type-forwarding-in-markdown~1`
553+
554+
Needs: impl, utest
555+
525556
### Elektrobit Markdown-style Structures
526557

527558
#### Markdown "Needs" List

doc/system_requirements.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,21 @@ Tags are a way to label an artifact intended for grouping.
183183

184184
Needs: dsn
185185

186+
#### Forwarding Needed Coverage
187+
`req~forwarding_needed_coverage~1`
188+
189+
OFT allows users to forward needed coverage from one artifact type to one or more different types.
190+
191+
Rationale:
192+
193+
Often a system requirement does not affect the high-level architecture. In this case it is convenient for the architect to hand it down to lower levels directly.
194+
195+
Covers:
196+
197+
* [feat~markdown-import~1](#markdown-import)
198+
199+
Needs: dsn
200+
186201
### Supported Formats
187202

188203
#### Markdown
@@ -211,6 +226,8 @@ Covers:
211226
Needs: dsn
212227

213228
##### Markdown Outline Readable
229+
`req~markdown-outline-readable~1`
230+
214231
The Markdown outline -- a table of contents created from the heading structure by various Markdown editors -- must be human readable.
215232

216233
Rationale:
@@ -238,6 +255,21 @@ Covers:
238255

239256
Needs: dsn
240257

258+
##### Artifact Type Forwarding in Markdown
259+
`req~artifact-type-forwarding-in-markdown~1`
260+
261+
The Markdown format features a compact way to forward a requirement from the artifact type that was originally required to one or more different artifact types.
262+
263+
Rationale:
264+
265+
Often a system requirement does not affect the high-level architecture. In this case it is convenient for the architect to hand it down to lower levels directly.
266+
267+
Covers:
268+
269+
* [feat~markdown-import~1](#markdown-import)
270+
271+
Needs: dsn
272+
241273
#### Coverage Tags
242274

243275
Developers add coverage tags as comments to the source code to indicate where certain specification items are covered.

doc/user_guide.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<head><link href="oft_spec.css" rel="stylesheet"></link></head>
22

3-
![oft-logo](../src/main/resources/openfasttrack_logo.svg)
3+
![oft-logo](../src/main/resources/openfasttrace_logo.svg)
44

55
# OpenFastTrace (OFT) User Guide
66

@@ -235,6 +235,18 @@ Requirements should be accompanied by a rationale in all cases where the reason
235235

236236
Needs: dsn
237237

238+
### Delegating Requirement Coverage
239+
240+
Consider a situation where you are responsible for the high-level software architecture of your project. You define the component breakdown, the interfaces and the interworking of the components. You get your requirements from a system requirement specification, but it turns out many of those incoming requirements are at a detail level that does not require design decisions on inter-component-level but rather affects the internals of a single component.
241+
242+
In those cases it would be a waste of time to repeat the original requirement in your architecture just to hand them down to the detailed design of a component. Instead what you need is a fast way to express "yes, I read that requirement and I am sure it does not need design decisions in the high-level architecture."
243+
244+
To achieve this OFT features a shorthand notation for delegating the job of covering a specification item to one or more different artifact types.
245+
246+
In the following example a requirement in the system requirement specification (artifact type `req`) stated that the web user interface of your product should use the corporate design. This clearly does not require an architectural decision (`arch`), so you forward it directly to the detailed design (`dsn`) level.
247+
248+
arch --> dsn : req~web-ui-uses-corporate-design~1
249+
238250
### Distributing the Detailing Work
239251

240252
In projects of a certain size you always reach the point where a single team is not enough to process the workload. As a consequence is the teams must find a way to distribute the work. A popular approach is splitting the architecture into components that are as independent as possible. Each team is then responsible for one or more distinct components. While the act of assigning the work should never be done inside of the specification, at least the specification can prepare criteria on which to split the work.
@@ -449,4 +461,4 @@ Editor / IDE | Syntax highl. | Previ
449461
[Eclipse](https://eclipse.org) with WikiText plug-in | y | y | y | y
450462
[Eclipse](https://eclipse.org) with GMF plug-in | | y | |
451463
[Vim](https://www.vim.org/) | y | | |
452-
464+
[Visual Studio Code](https://code.visualstudio.com/) | y | y | y |

oft

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#!/bin/sh
2+
script_path=$(dirname "$(readlink -f "$0")")
3+
version=$(grep -zo '<version>.*</ver.*\n.*<name>OpenFastTrace' pom.xml | sed -e's/[^0-9.]//g')
4+
5+
java -jar "$script_path/target/openfasttrace-$version.jar" $@

src/main/java/org/itsallcode/openfasttrace/core/SpecificationItem.java

Lines changed: 45 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828

2929
import javax.annotation.Generated;
3030

31-
// [impl->dsn~specification-item~2]
31+
// [impl->dsn~specification-item~3]
3232
public class SpecificationItem
3333
{
3434
private final SpecificationItemId id;
@@ -42,6 +42,7 @@ public class SpecificationItem
4242
private final List<SpecificationItemId> dependOnIds;
4343
private final List<String> needsArtifactTypes;
4444
private final List<String> tags;
45+
private final boolean forwards;
4546

4647
private SpecificationItem(final Builder builder)
4748
{
@@ -57,6 +58,7 @@ private SpecificationItem(final Builder builder)
5758
this.dependOnIds = builder.dependOnIds;
5859
this.needsArtifactTypes = builder.neededArtifactTypes;
5960
this.tags = builder.tags;
61+
this.forwards = builder.forwards;
6062
}
6163

6264
/**
@@ -194,6 +196,15 @@ public List<String> getTags()
194196
return this.tags;
195197
}
196198

199+
/**
200+
* @return <code>true</code> if this specification item forwards needed
201+
* coverage
202+
*/
203+
public boolean isForwarding()
204+
{
205+
return this.forwards;
206+
}
207+
197208
@Generated(value = "org.eclipse.Eclipse")
198209
@Override
199210
public final int hashCode()
@@ -204,14 +215,15 @@ public final int hashCode()
204215
result = prime * result + ((this.coveredIds == null) ? 0 : this.coveredIds.hashCode());
205216
result = prime * result + ((this.dependOnIds == null) ? 0 : this.dependOnIds.hashCode());
206217
result = prime * result + ((this.description == null) ? 0 : this.description.hashCode());
218+
result = prime * result + (this.forwards ? 1231 : 1237);
207219
result = prime * result + ((this.id == null) ? 0 : this.id.hashCode());
208220
result = prime * result + ((this.location == null) ? 0 : this.location.hashCode());
209221
result = prime * result
210222
+ ((this.needsArtifactTypes == null) ? 0 : this.needsArtifactTypes.hashCode());
211-
result = prime * result + ((this.tags == null) ? 0 : this.tags.hashCode());
212223
result = prime * result + ((this.rationale == null) ? 0 : this.rationale.hashCode());
213-
result = prime * result + ((this.title == null) ? 0 : this.title.hashCode());
214224
result = prime * result + ((this.status == null) ? 0 : this.status.hashCode());
225+
result = prime * result + ((this.tags == null) ? 0 : this.tags.hashCode());
226+
result = prime * result + ((this.title == null) ? 0 : this.title.hashCode());
215227
return result;
216228
}
217229

@@ -276,6 +288,10 @@ else if (!this.description.equals(other.description))
276288
{
277289
return false;
278290
}
291+
if (this.forwards != other.forwards)
292+
{
293+
return false;
294+
}
279295
if (this.id == null)
280296
{
281297
if (other.id != null)
@@ -309,17 +325,6 @@ else if (!this.needsArtifactTypes.equals(other.needsArtifactTypes))
309325
{
310326
return false;
311327
}
312-
if (this.tags == null)
313-
{
314-
if (other.tags != null)
315-
{
316-
return false;
317-
}
318-
}
319-
else if (!this.tags.equals(other.tags))
320-
{
321-
return false;
322-
}
323328
if (this.rationale == null)
324329
{
325330
if (other.rationale != null)
@@ -331,25 +336,29 @@ else if (!this.rationale.equals(other.rationale))
331336
{
332337
return false;
333338
}
334-
if (this.title == null)
339+
if (this.status != other.status)
335340
{
336-
if (other.title != null)
341+
return false;
342+
}
343+
if (this.tags == null)
344+
{
345+
if (other.tags != null)
337346
{
338347
return false;
339348
}
340349
}
341-
else if (!this.title.equals(other.title))
350+
else if (!this.tags.equals(other.tags))
342351
{
343352
return false;
344353
}
345-
if (this.status == null)
354+
if (this.title == null)
346355
{
347-
if (other.status != null)
356+
if (other.title != null)
348357
{
349358
return false;
350359
}
351360
}
352-
else if (!this.status.equals(other.status))
361+
else if (!this.title.equals(other.title))
353362
{
354363
return false;
355364
}
@@ -372,6 +381,7 @@ public static class Builder
372381
private final List<SpecificationItemId> dependOnIds;
373382
private final List<String> neededArtifactTypes;
374383
private final List<String> tags;
384+
private boolean forwards;
375385

376386
/**
377387
* Create a new instance of type {@link SpecificationItem.Builder}
@@ -616,5 +626,20 @@ public SpecificationItem build()
616626
}
617627
return new SpecificationItem(this);
618628
}
629+
630+
/**
631+
* Set to <code>true</code> if this specification item forwards needed
632+
* coverage
633+
*
634+
* @param forwards
635+
* <code>true</code> if the specification item forwards
636+
* needed coverage
637+
* @return this builder instance
638+
*/
639+
public Builder forwards(final boolean forwards)
640+
{
641+
this.forwards = forwards;
642+
return this;
643+
}
619644
}
620645
}

src/main/java/org/itsallcode/openfasttrace/importer/ImportEventListener.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,14 @@ public interface ImportEventListener
147147
* the location
148148
*/
149149
public void setLocation(Location location);
150-
}
150+
151+
/**
152+
* Set to <code>true</code> if the specification item forwards needed
153+
* coverage
154+
*
155+
* @param forwards
156+
* <code>true</code> if the specification item forwards needed
157+
* coverage
158+
*/
159+
public void setForwards(boolean forwards);
160+
}

0 commit comments

Comments
 (0)