Open stanislaw opened 5 years ago
Here is a screenshot.
See also #295 for concepts of using Markdown files with YAML blocks instead of YAML files. (Though that issue was still considering one .md file per item.)
I am also currently evaluation doorstop and have been thinking along similar lines. In our case, an improved GUI would probably not help. A single file instead of multiple files (yaml or markdown) it would probably help getting people to consider using doorstop.
However, I was approaching this slightly differently. The original rationale for what I am going to outline has to do with how external references (for example to test cases) are handled. Ideally, I would want to be able to treat linkage to test cases and tests in exactly the way how requirements are treated. However, external references don't give me that.
If I were able to embed the equivalent of the yaml file into the test code and somehow make doorstep understand that doorstep information is embedded in another file, I could link back to a test case, which in turn can then be linked to requirements.
From a user's perspective, this could then look like
$ doorstop add REQ –to mysourcefile.c
The command implementation would probably have to create a REQ to file mapping somewhere (e.g. in the respective .doorstop.yml file) and possibly require a unique ID/identifier for the case where multiple documents are stored in the same file. For usability doorstop could maybe copy the yaml block into the clipboard such that it can be added easily to mysourcefile.c
This would then allow for the original use-case raised in this ticket of storing the requirements information in either a single or multiple markdown files assuming #295 is implemented.
Besides this, it would also allow for embedding requirements within code and/or test code as needed and would allow tracing requirements back to code, if needed.
There would probably be some wrinkles around the comment format (which is language dependent) and may need some pre-processing of the content to get the doc from the source file into doorstop. There could also be potential problems with doorstop remove (if you wanted the capability to purge the requirements text in the source file completely).
I don't understand the doorstop code enough to figure out how disruptive this would be, but conceptually this does not sound too bad.
Any thoughts?
$ doorstop add REQ –to mysourcefile.c
To complement your description, could you please provide an example of how the mysourcefile.c
starts to look like after this command is applied?
To complement your description, could you please provide an example of how the mysourcefile.c starts to look like after this command is applied?
This is where things obviously become language dependent and to some degree coding standard dependent. As a first step (aka without allowing Markdown) it would look like the following assuming standard C comment practice
/*
* doorstop: REQ002
* active: true
* derived: false
* header: ''
* level: 1.1
* links:
* - REQ001: a6048621617c0e253c37c7d158263379
* normative: true
* ref: ''
* reviewed: dd1d3e174eb51a5046662b86e8121b90
* text: |
* My requirements text
*/
Note that you need a REQ identifier (the first line of the comment in the block, as you could otherwise not find the correct requirement in the source file)
Other languages and file formats may have different commenting paradigms, which would have to be supported. Such as #
or \\
. Most of these can probably be handled in the following way
doorstop: REQ002
- normally the yaml filename gives you that information*/
in the case of C). At that point you have what is now in the yaml file
This area probably needs a bit more thought, as this may imply a set of config settings that trigger different rules based on file extension.
With the markdown idea as laid out in #295 this may look like
/*
* doorstop: REQ002
* active: true
* derived: false
* header: ''
* level: 1.1
* links:
* - REQ001: a6048621617c0e253c37c7d158263379
* normative: true
* ref: ''
* reviewed: dd1d3e174eb51a5046662b86e8121b90
* ...
* ### My requirements text
* With a more *detailed* description using [Markdown syntax]
* (https://www.markdownguide.org/basic-syntax/).
*/
It may also make sense to omit attributes with default values such as header, level, normative which may not be used to minimize what's in the source file. But in this case, the corresponding defaults probably need to be saved in the respective .doorstop.yml file
Taking the same example as before this time in a markdown file with default/unneeded settings removed it would look like
---
doorstop: REQ002
active: true
derived: false
links:
- REQ001: a6048621617c0e253c37c7d158263379
reviewed: dd1d3e174eb51a5046662b86e8121b90
...
### My requirements text
With a more *detailed* description using [Markdown syntax]
(https://www.markdownguide.org/basic-syntax/).
Note that in this case we can't easily identify the end of the requirements description as we basically took this from the comment capability.
A more radical approach would be to implement a more abstract interface that allows you to put custom parsers in place, which parse what's in the text block and just copy it into the correct data structure in doorstop. That would allow implementing the actual format say in doxygen or kern-doc style, which is probably more natural in the code vs. the above.
Given that the above functionality is not in place, this may altogether be more flexible and not that much extra work. Dealing with stripping the comments could also be done in a similar way, possibly avoiding the need for config settings.
AFAICT from the code this functionality is fairly isolated to _load() and _dump() in base.py
This approach is not suitable for our use case (automotive development): we would use doorstop for all requirements specifications, verification specifications and validation specifications, at vehicle, system, hardware and software levels. The code itself is mostly autogenerated from Simulink.
This approach is not suitable for our use case (automotive development): we would use doorstop for all requirements specifications, verification specifications and validation specifications, at vehicle, system, hardware and software levels. The code itself is mostly autogenerated from Simulink.
My proposal would be that
$ doorstop add REQ
would work as now and
$ doorstop add REQ –to specific-markup-file.md
or $ doorstop add REQ –to specific-markup-file.yaml
would allow for storing multiple requirements in a single markdown or yaml file.
It would in addition allow for storing requirements in source code (with extra implementation work). This may not be necessary though, if the reference functionality is improved as suggested by https://github.com/doorstop-dev/doorstop/pull/395
With this in mind: would this approach be suitable?
@larskurth You could simplify your logic even further
$ doorstop add REQ
if REQ is a folder:
# Use existing folder logic
else if REQ.md exists:
# Add to existing REQ.md file
I was considering how to migrate a specification from Word to Doorstop when I had an idea for this RFC:
Basically, look at the current output from doorstop publish --markdown PREFIX ./PREFIX.md
(excluding child and parent links) and consider that as the data file to hold a document's text. UIDs are tagged in curly braces. Each UID tag (say {#REQ-001}
) in the REQ.md
file would have its own YAML file (in this case REQ-001.yml
).
The YAML sidecar file would have the remaining metadata such as links
, normative
, reviewed
, etc.
I'm not sure where to draw the boundary between Doorstop items in this idea. At paragraph breaks would be straightforward, or until encountering the next UID tag. But if a user wants several paragraphs in an item, it may need some more markup, maybe a horizontal rule.
This is sort of how requirements management works in the Word files I've encountered: each "shall" gets a unique number in square brackets, and if you want any other metadata, it's in a requirements traceability table appended to the end of the .docx
file.
I agree that sometimes it is annoying to have all requirements file-based, especially when building up a new specification or when reviewing.
However, I think that this should remain the foundation of doorstop, because this also keeps the core of doorstop simple and less vulnerable to errors. For me it is outrageous important to have a core application which works well and is not error-prone.
Principally, the core application shall not do more than versioning, tracing and validation. Maybe it has already too much functionality. I really like that concept that each requirement is a stand-alone file, because this integrates perfectly with file-based version control systems. You directly get the history of a requirement out-of-the-box.
Whatever we need further, build it on top. Like this, everyone can decide by himself, on which level her/his project shall be based on.
So, at the moment there is the GUI
and the export
/ import
solutions built on top. This already works well I think. You can view / edit all requirements of a document at once and re-import it again.
For me it is rather the question of structuring a document, which is not properly solved. I need an extra file only for each headline? This is the thing which really annoys me. I think that this is the root of why this issue has been filed.
I would like to combine these worlds by keeping the requirements file-based, but allowing the user to define a "structure-of-a-document" or "outline-of-a-document", which allows defining the headlines and how the requirements shall be embedded into the document. I think that the .doorstop.yml
files are predestined for this purpose. This is no "on-top" solution, but I think that we need to get rid of the additional YML files, which are only for structuring and giving titles, even if the functionality has been added recently (and it has added a lot of value for very little effort, but it is not comfortable for the user).
I like the idea that the structure of the document is independent of its content. Often the restructuring of documents is not done, because it means a lot of effort and is error-prone, nobody takes the effort and risk to restructure a document, which often results into "difficult-to-understand" documents. And with the version control system you can even simply comprehend how the structure of a document has changed (without the "noise" of content changes).
I imagined something like this. Let's say we have a .doorstop.yml
, which additionally contains the outline of the document in its text
attribute. The references to the requirements are simply markdown links. Besides the outline, you can insert whatever you want, like a use case diagram or further explanations.
settings:
digits: 3
parent: ''
prefix: REQ
sep: '-'
header: |
Software Requirement Specification
reviewed: ''
text: |
# Purpose
Why do I need this document, what is it for?
# Scope
What is the border of consideration?
# Use Cases
` ` `plantuml
@startuml
left to right direction
actor User
actor Admin
rectangle ATM {
User --> (Withdraw Money)
User --> (Deposit Money)
User --> (Check Balance)
(Withdraw Money) .> (Reduce Balance) : include
(Deposit Money) .> (Rise Balance) : include
(Withdraw Money) ..> (Select Account) : include
(Deposit Money) ..> (Select Account) : include
(Check Balance) ..> (Select Account) : include
Admin --> (Refill Money)
Admin --> (Receive Low Fill Level Notification)
}
@enduml
` ` `
# Requirements
## Select Account
- [REQ-000.yml](REQ-000.yml)
## Withdraw Money
- [REQ-001.yml](REQ-001.yml)
- [REQ-002.yml](REQ-002.yml)
## Deposit Money
- [REQ-003.yml](REQ-003.yml)
- [REQ-004.yml](REQ-004.yml)
## Balance
- [REQ-005.yml](REQ-005.yml)
- [REQ-006.yml](REQ-006.yml)
## Refill Money
- [REQ-007.yml](REQ-007.yml)
- [REQ-008.yml](REQ-008.yml)
## Low Fill Level Notification
- [REQ-009.yml](REQ-009.yml)
And for example a file REQ-000.yml:
active: true
derived: false
links: ''
ref: ''
reviewed: 3bc2aa8c304c71e390e8fabb660995f0
text: |
The ATM shall demand the user to select a bank account before
the user can progress with an operation on that bank account.
The user shall insert a valid bank card and input the pin number.
The ATM shall disallow the selection, if the user provided an
invalid bank card or an invalid pin number.
Then it may look like this:
I agree mostly with @tangoalx but I would simply have a list of items to create the outline and levels. Leave all content in each individual file to keep traceability.
settings:
digits: 3
parent: ''
prefix: REQ
sep: '-'
header: |
Software Requirement Specification
reviewed: ''
text: |
# REQ-002
REQ-004
REQ-001
## REQ-070
Content of each paragraph/heading can be controlled and traced by each individual file. But the re-ordering of the document is done easily in the .doorstop.yml
file. Also, I think that the level
attribute will be unneeded if this is implemented.
This is the issue is related to the previous issue #400. The background for the following proposal can be found there.
This way the levels are ensured by the markdown level headers, no need for
level:
anymore.Creating a new Item
To create a new item you simply create a new
#...#
header and write some statement. Then you call a commanddoorstop resolve
which automatically creates a UID and adds the meta-information. Also, it does the validation of the whole document's meta info for any issues.No GUI work needed
Having this approach implemented, we don't have to implement any new GUI interfaces because our programmer's IDEs already support markdown and the outlines nicely.
The only problem I see here is the visual redundancy of the meta-information in the markdown file. One solution is to simply auto-collapse all the meta-info by default. I see that Atom has a plugin for collapsing all of the comments in a file when it is opened. Maybe other IDEs have this too.
Pros and Cons
Pros
doorstop resolve
and existingdoorstop *
commands are your friend.Cons
Please let me know what you think? I would be happy to implement a POC based on this concept.