要求交換フォーマット(ReqIF)を調べてみた。(5)
ReqIFの内部構造を解説しようと思ったが、これはReqIFの仕様書にある14枚のクラス図をじっくり眺めれば大体のことは理解できるだろう。むしろ、そのReqIFモデルが具体的にどんなReqIFフォーマットのXML文書に展開されるかを示したほうが、理解の近道だと思う。以下も参照のこと。
- (1) ReqIFの3つのユースケース
- (2) ReqIFの8つの機能
- (3) ReqIFの再利用性、RIFとの差異
- (4) ReqIF/RIFの動向
- (5) ReqIFフォーマットの構造 (※この記事)
- (6) ReqIFでの代替IDとアクセス制限
【0】ReqIFルートの構造
ReqIFのXML交換文書は以下のような構造になる。XML Schemaでの表現は厳密なのだろうが、直感的でなくイメージしにくい。ReqIF文書のインスタンスとして具体例をベースにしたほうが理解しやすい。ReqIF文書はthe-header、core-content、tool-extensionsの3つのセクション(仮にセクションと呼ぶことにする)で構成される。
詳細は仕様書内のReqIFモデルを参照しながら確認のこと。the-headerは必須だが、tool-extensionsはオプションだ。core-contentは、勿論必須である。req-if-contentがさらに6つのセクションで構成されることをまず把握しておいてほしい。datatypes、spec-types、spec-objects、spec-relations、specifications、relation-groupsの6つだ。この部分について詳細を後述していく。
<?xml version="1.0" encoding="Shift_JIS"?> <req-if xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.omg.org/spec/ReqIF/20110401/reqif.xsd" xsi:schemaLocation="http://www.omg.org/spec/ReqIF/20110401/reqif.xsd reqif.xsd" lang=""> <the-header> <!-- the-header,req-if-headerは必ず1つ必要である。 --> <req-if-header identifier="REQIF-tacohachi-000001"> <creation-time>2011-09-11T00:00:00</creation-time> <req-if-version>REQIF1.0</req-if-version> <req-if-tool-id/> <title>サンプルReqIFフォーマット</title> <comment>ReqIFフォーマットを具体的なファイルイメージで解説しています。</comment> </req-if-header> </the-header> <core-content> <req-if-content> <!-- core-content,req-if-contentは必ず1つ必要である。 --> <!-- 【1】datatypes: 属性値の型を定義する --> <datatypes/> <!-- 【2】spec-types: 仕様要素の型を定義する --> <spec-types/> <!-- 【3】spec-objects: 要求を記述する --> <spec-objects/> <!-- 【4】spec-relations: 要求間の関係を記述する --> <spec-relations/> <!-- 【5】specifications: 要求仕様(階層表現)を記述する --> <specifications/> <!-- 【6】relation-groups: 要求仕様間の関係を記述する --> <relation-groups/> </req-if-content> </core-content> <tool-extensions> <!-- tool-extensionsはオプションであり、必要なら1つのみを記述可能である。 --> <tool-extension/> </tool-extensions> </req-if>
【1】datatypesセクション「属性値の型を定義する」
ReqIF文書のcore-content内のdatatypesセクションは以下のように記述される。datatypesには属性値の型を定義する。ReqIFはデフォルトで、整数型、実数型、論理型、文字列型、日付型が用意されている。以下の例では、明示的な文字列型(サイズや定義名を固有なものに変更したもの)と列挙型(要求ステータスを表現するもの)を定義してみた。
ここで定義した型は要求の属性(SpecAttribute)で参照される。DatatypeのID(identifier)はローカルでユニークであればいい。用いられる型は、文書内にすべて抽出しておくことができる。
<!-- 【1】datatypes: 属性値の型を定義する --> <datatypes> <datatype-definition-string identifier="string-type" long-name="文字列" max-length="65535" /> <datatype-definition-enumeration identifier="status-type" long-name="ステータス"> <specified-values> <enum-value identifier="New"> <properties> <embedded-value key="0" other-content="新規"/> </properties> </enum-value> <enum-value identifier="Accepted"> <properties> <embedded-value key="1" other-content="受理"/> </properties> </enum-value> <enum-value identifier="Declined"> <properties> <embedded-value key="2" other-content="拒否"/> </properties> </enum-value> </specified-values> </datatype-definition-enumeration> </datatypes>
【2】spec-typesセクション「仕様要素の型を定義する」
ReqIF文書のcore-contentセクション内のspec-typesセクションは以下のように記述される。spec-typesでは仕様要素の型を定義する。仕様要素と呼んでいるものの型(SpecType)には、{ SpecificationType, SpecObjectType, SpecRelationType, RelationGroupType } の4つがある。特に重要となるのは要求の型(SpecObjectType)の属性定義である。つまり、いわゆる要求にどんな属性があるかの定義だからだ。
各型(SpecType)に設定されるID(identifier)はローカルでユニークであればいい。用いられる型は文書内にすべて抽出しておくことができる。
例として「機能要求」という要求オブジェクトの型を定義してみた。このオブジェクトには、要求ID、要求件名、要求内容、要求者、登録日(日付型)、ステータス(列挙型)、権限(論理型)という属性を定義してみた。文字列型と列挙型は【1】で明示的に定義したものを利用している。
要求オブジェクトの型(SpecObjectType)としては、非機能要求を定義してもいい。ただし、SpecObjectTypeは構造上SpecAttributeが異なるものに対して定義することが有効だ。機能要求も非機能要求もカラムが同じもので十分であれば、あえて分離して定義する必要はないだろう。むしろ、SpecObjectTypeを継承した定義が可能であるといいのだが、ReqIFではできないようだ。たとえば、「基本要求」定義しておいて、それを継承して「機能要求」と「非機能要求」を定義しておきたいなどだ。これはできない。これを代替するには、仕様の型(SpecificationType)を利用することになる。
<!-- 【2】spec-types: 仕様要素の型を定義する --> <spec-types> <!--【2-1】SpecificationTypeの定義 --> <!-- 例として2階層で表現できる仕様を「節項(clause)」などと命名して おくといった定義をあげておく。また、章を単位をしてSpecification としてまとめる案もあるだろう。 SpecificationTypeで具体的な各章を表現することも可能だ。 自由度があるため、いろいろな使われ方ができる。 --> <specification-type identifier="chapter" long-name="章"> <spec-attributes/> </specification-type> <specification-type identifier="clause" long-name="節項"> <spec-attributes/> </specification-type> <!--【2-2】SpecObjectTypeの定義 --> <spec-object-type identifier="functional-req" long-name="機能要求"> <spec-attributes> <!-- 要求(SpecObject)には必ず全世界ユニークなIDをidentifierと して付与する必要がある。しかし、これは利用者が認識しづら い暗号的なものになってしまう。なので、利用者が識別しやす いローカルなIDを要求属性として持つことが一般的である。 --> <attribute-definition-string identifier="ID" long-name="要求ID"> <type> <datatype-definition-string-ref>string-type </datatype-definition-string-ref> </type> </attribute-definition-string> <attribute-definition-string identifier="subject" long-name="要求件名"> <type> <datatype-definition-string-ref>string-type </datatype-definition-string-ref> </type> </attribute-definition-string> <attribute-definition-string identifier="content" long-name="要求内容"> <type> <datatype-definition-string-ref>string-type </datatype-definition-string-ref> </type> </attribute-definition-string> <attribute-definition-string identifier="requester" long-name="要求者"> <type> <datatype-definition-string-ref>string-type </datatype-definition-string-ref> </type> </attribute-definition-string> <attribute-definition-date identifier="requested-date" long-name="登録日"/> <!-- 以下の例で列挙型の「要求ステータス」という属性を定義してみた。 --> <attribute-definition-enumeration identifier="request-status" long-name="要求ステータス" multi-valued="false"> <type> <datatype-definition-enumeration-ref>status-type </datatype-definition-enumeration-ref> </type> </attribute-definition-enumeration> <!-- 以下の例で「編集権限」という属性は利用者は変更できないように 定義してみた。 --> <attribute-definition-boolean identifier="is-editable" long-name="編集権限" is-editable="false" /> </spec-attributes> </spec-object-type> <!--【2-3】SpecRelationTypeの定義 --> <!-- 抽象的には以下のような関係を定義しておくべきだろう。 もっと具体化されたものでもよい。 --> <spec-relation-type identifier="depend" long-name="依存"> <!-- BはAに依存する --> <spec-attributes/> </spec-relation-type> <spec-relation-type identifier="XOR" long-name="排他"> <!-- AとBは排他的 --> <spec-attributes/> </spec-relation-type> <!--【2-4】RelationGroupTypeの定義 --> <!-- 仕様(Specification)間の関係であり、Relationと同様に親子、参照、XOR といった定義もありえる。仕様間のトレーサビリティの定義にも使える。 RelationGroupをどのように活用するかは、要求(SpecObject)や仕様 (Specification)の粒度による。要求(SpecObject)が非常に細かい場合、 仕様(Specification)が一般の個々の要求程度の場合がある。その場合、 RelationGroupをあたかも仕様のように定義することも可能である。 --> <relation-group-type identifier="CRS-SRSトレーサビリティ"> <spec-attributes/> </relation-group-type> </spec-types>
【3】spec-objectsセクション「要求を記述する」
ReqIF文書のcore-content内のspec-objectsセクションは以下のように記述される。要求そのもののインスタンスを記述する部分である。定義した要求属性に沿って記述する。ここでは個々の要求を記述するだけであり、要求間の関係、階層関係などはまだ表現しない。
要求(SpecObject)のidentifierは全世界ユニークなIDが望ましい。例では適当なそれらしいIDを添えておいた。この全世界ユニークなIDはどこで付与すべきものだろうか。WORD/EXCELなどのレガシーとReqIF対応の要求記述ツールとの間での文書交換を考えてみる。ReqIF対応の要求記述ツールでは当然、ユニークIDを付与する機能が備わる。しかし、レガシーのWORD/EXCELなどから要求記述ツールにインポートしようとした場合、ReqIF対応の文書交換ツール(ReqIFツールと呼ばれる)を介してReqIFフォーマットに変換する必要がある。このシナリオにおいて、ReqIFツールでユニークIDを付与することも可能だし、ReqIFツールを素通りして要求記述ツール内の機能でユニークIDを付与することも可能である。
ReqIFではツール間の往復のシナリオ(round-trip)が考慮されている。これを実現するためには、WORD/EXCELやその他のレガシーツールと、ReqIFツールとの間で文書交換が必要であり、ReqIFツールでもユニークIDが発行できる方がいいのかもしれない。ReqIF対応の要求記述ツールやReqIFツールで出力されたReqIF文書では、要求(SpecObject)には何らかのユニークIDが付与されており、round-tripではそれを使い回す必要がある。
<!-- 【3】spec-objects: 要求を記述する --> <spec-objects> <spec-object identifier="SO-tacohachi-000001"> <!-- 全世界ユニークなID --> <type> <spec-object-type-ref>functional-req</spec-object-type-ref> </type> <values> <attribute-value-string the-value="REQ-0001"> <!-- ローカルな任意のID --> <definition> <attribute-definition-string-ref>ID </attribute-definition-string-ref> </definition> </attribute-value-string> <attribute-value-string the-value="中国語対応"> <definition> <attribute-definition-string-ref>subject </attribute-definition-string-ref> </definition> </attribute-value-string> <attribute-value-string the-value="情報は中国語でも表示できること。"> <definition> <attribute-definition-string-ref>content </attribute-definition-string-ref> </definition> </attribute-value-string> <attribute-value-string the-value="たこはち"> <definition> <attribute-definition-string-ref>requester </attribute-definition-string-ref> </definition> </attribute-value-string> <attribute-value-date the-value="2011/08/23T10:23:45"> <definition> <attribute-definition-date-ref>requested-date </attribute-definition-date-ref> </definition> </attribute-value-date> <attribute-value-enumeration the-value="Accepted"> <definition> <attribute-definition-enumeration-ref>request-status </attribute-definition-enumeration-ref> </definition> </attribute-value-enumeration> </values> </spec-object> <!-- 以下、要求の数だけ繰り返される。 --> <spec-object identifier="SO-tacohachi-000002"> <type> <spec-object-type-ref>functional-req</spec-object-type-ref> </type> <values> <attribute-value-string the-value="REQ-0002"> <definition> <attribute-definition-string-ref>ID </attribute-definition-string-ref> </definition> </attribute-value-string> <attribute-value-string the-value="中国語入力"> <definition> <attribute-definition-string-ref>subject </attribute-definition-string-ref> </definition> </attribute-value-string> <attribute-value-string the-value="中国語でも入力できないといけない。"> <definition> <attribute-definition-string-ref>content </attribute-definition-string-ref> </definition> </attribute-value-string> <attribute-value-string the-value="ぬるはち"> <definition> <attribute-definition-string-ref>requester </attribute-definition-string-ref> </definition> </attribute-value-string> <attribute-value-date the-value="2011/09/04T16:33:00"> <definition> <attribute-definition-date-ref>requested-date </attribute-definition-date-ref> </definition> </attribute-value-date> </values> </spec-object> </spec-objects>
SpecObjectは要求そのものを表現しており、ReqIFにおいてもっとも重要な部分である。しかし、spec-objectのXMLをじっくり眺めて欲しい。ReqIFのフォーマットでは、どうしても気になる点が2点ほどある。補足しておきたい。これら2点は、要求記述ツール固有の拡張として柔軟に対応していいものなのか、それが許されない厳格なものなのかは、まだ見極めができていない。
まず1つ目は、属性値としての日本語の文字列がXMLの属性(attribute)で格納されることだ。これは問題が生じるかもしれない。非常に扱いにくい。attributeではなく要素(element)として表現される方が適切だったと思われる。なぜこのような判断になったのか、後日調べてみたい。ちなみに古いRIFでは要素(element)で表現されていた。この状況では、単純なテキスト以外はすべてXHTMLで表現することになると思われる。改行1つ(<br/>)でさえ含めることができないのだ。現状では、文字列型はほとんど用いられずに、XHTML型(XhtmlContent)を多用することになるだろう。要素(element)で表現してよいといった柔軟な拡張が必要かもしれない。
もう1点は、属性参照の記述<definition>が非常に冗長になることだ。いちいちdefinitionで対応するカラムを指定しているが、省略できるようにして欲しかった。必ずカラムの順に並べるなら、definitionは省略していいとか、せめてdefinitionは要素(element)でなく、属性(attribute)で表現できるとかにならなかったのか。単に冗長なのが嫌いで、ファイルサイズが大きくなることが嫌いなだけなのだが、そういった人は多いはずだ。
【4】spec-relationsセクション「要求間の関係を記述する」
ReqIF文書のcore-content内のspec-relationsセクションは以下のように記述される。SpecRelationは2つの要求(SpecObject)間の関係を示すものなので、SpecRelationの型が重要となる。型としてはXOR(一方が成立すると他方が成立しない)、OR(どちらかが成立すればいい)、AND(両方とも成立しなければならない)の3つは、一般に必要といえるだろう。
また、SpecRelationでは、階層関係を定義することもできる。要求の階層化はSpecHierarchyでできるので不要かもしれないが、SpecRelationでも表現できるのだ。紛らわしいところだ。どのように使い分けるかがガイドされるべきだろう。要求記述ツールがアウトライン形式で階層化しながら作成できるか、SysMLの要求ダイアグラムのようにベタで要求を作成し、後から関係付けるかの差異によると思われる。後者のSysMLの要求ダイアグラムなどではSpecRelationで「階層化」の関係を示す方が有効となるだろう。以下の例では、2つの要求間に階層関係があることを示してみた。
SpecRelationのID(identifier)は特に重要ではない。ローカルにユニークであればいい。重要なのはSpecRelationの型の方である。用いられる型は、文書内ですべて抽出しておくことができる。
<!-- 【4】spec-relations: 要求間の関係を記述する --> <spec-relations> <spec-relation identifier="SR-tacohachi-000001"> <source> <spec-object-ref>SO-tacohachi-000001</spec-object-ref> </source> <target> <spec-object-ref>SO-tacohachi-000002</spec-object-ref> </target> <type> <spec-relation-type-ref>depend</spec-relation-type-ref> </type> </spec-relation> </spec-relations>
【5】specificationsセクション「要求仕様(階層表現)を記述する」
ReqIF文書のcore-content内のspecificationsセクションは以下のように記述される。Specificationで文書としての階層構造が表現できる。例では、章(レベル1)と節項(レベル2と3)を分離して定義してみた。分離せずに1つのツリーで書いても勿論いい。要求仕様(Specification)間の関係をSpecRelationGroupでどのように扱いたいかによって、Specificationの定義の仕方が変わってくる。
節(レベル2)とか項(レベル3)といった固定の深さやレベルで統一して仕様内容を記述する構成でないと非常に扱いにくいだろう。勿論、深さは自由でいいのだが、粒度を統一してそのかたまりをSpecificationとして括りだすことが、実際の利用では有効となるだろう。でないと、何と何、どのレベルとどのレベルでトレーサビリティを取るかが決めにくいのだ。一般には、節とか項といったレベルだろうと思われる。逆説的に言えば、何をSpecificationの単位とすべきかの判断は、その仕様としての一定のかたまりで、他とのトレーサビリティを図りたい単位であると言える。細かすぎてもいけないし、大雑把すぎてもいけない。ReqIFはそれらをガイドしてくれるものではない。
要求仕様(Specification)のID(identifier)は全世界ユニークなIDが望ましいとされている。しかし、多くの場合、ローカルにユニークであれば十分である。重要なのはSpecificationの型の方である。用いられる型は、文書内ですべて抽出しておくことができる。
以下の例では、アクセス権限も例示しておいた。アクセス権限の指定には3つのやり方がある。詳細は後日としたい。以下の例では、「要求内容」という属性以外は編集できないように設定している。
<!-- 【5】specifications: 要求仕様(階層表現)を記述する --> <specifications> <specification identifier="SS-tacohachi-000001" long-name="2.1"> <type> <specification-type-ref>clause</specification-type-ref> </type> <children> <spec-hierarchy identifier="SH-tacohachi-000001" long-name="2.1.1"> <children> <!-- "(1)"にはアクセス制御がある。要求内容以外は編集できない。--> <spec-hierarchy identifier="SH-tacohachi-000002" long-name="(1)" is-editable="false"> <object> <spec-object-ref>SO-tacohachi-000002</spec-object-ref> </object> <editable-atts> <attribute-definition-string-ref>content </attribute-definition-string-ref> </editable-atts> </spec-hierarchy> </children> <object> <spec-object-ref>SO-tacohachi-000001</spec-object-ref> </object> </spec-hierarchy> </children> </specification> </specifications>
【6】relation-groupsセクション「要求仕様間の関係を記述する」
最後のセクションだ。ReqIF文書のcore-content内のrelation-groupsセクションは以下のように記述される。RelationGroupは、要求仕様(Specification)間に関係がある場合に利用する。
1つの要求文書内では、せいぜい仕様間のXOR(一方が成立すると他方が成立しない)、OR(どちらかが成立すればいい)、AND(両方とも成立しなければならない)の関係くらいだろう。しかし、それが要求仕様(Specification)というかたまりに対して必要な場面は多くはないだろう。1つの要求文書内では、要求の階層化の方が重要だからだ。
一方、1つの要求文書に複数の要求文書(システム要求/顧客要件とシステム要件/成果物要件)に相当するものがマージされて出力されるような場合がある。実は、統合的な要求記述ツールでは、当然、これらが同時に扱えるのだ。この場合には、RelationGroupが有効である。仕様間のトレーサビリティが重要となるからだ。要求を扱う際の最大のテーマでもあるCRS-SRSトレーサビリティの関係もRelationGroupで表現可能である。以下では例示していないので【2-4】RelationGroupTypeの定義に戻って参照してほしい。
要求関係グループ(RelationGroup)のID(identifier)は特に重要ではない。重要なのはRelationGroupの型の方である。用いられる型は文書内にすべて抽出しておくことができる。
<!-- 【6】relation-groups: 要求仕様間の関係を記述する --> <relation-groups> <!-- 割愛 --> </relation-groups>
以上だ。