UMLモデリングを通して、一歩一歩作ってみる 「UMLモデリング練習帳アプリ」#1 CUIアプリ

# はじめに

たまには何か作ってみよう…ということで、今回はUMLを利用してモデルを作成しながら何かをほそぼそ作ってみようかと思います。
どこまで続くかわかりませんが細々と続けてみます。

# 作るものを考えましょう

ではざっくり作るものを考えましょう
せっかくなので、弊社に絡めたものにしたいと思います。
弊社では**「モデリング添削講座」**というサービスがあります。
上記はUMLモデリングスキルの向上を目的とした、通信添削講座です。

…ふと思って今回はこれを行うためのサービスが作れないかと考えてみることにしました。
その名も…**「UMLモデリング練習帳アプリ」**。

私自身もUMLでモデリングをするとき、そういった添削などを機械的にできないかと思うときがあります。
また、競技プログラミングも少しやるのですが、同じようにお題が出題され、モデリングスキルを競ったりする場が作れないかと思っています。
ということで、今回はそういったものを作ることを目指します。
ただし…いきなり仰々しいものは作らず、簡単なものを一歩ずつ作っていきます。

# まずは分析してみよう

では、今回作るべきものを分析しながら考えてみましょう。

## 概念

今回は、UMLモデル学習者がUMLモデルを作成し、与えられた問題に対して、作り切れたかを確認することを考えます。
背景として、UMLモデル学習者が大変お金がないので、商用のモデリングツールを使っておらずplantUMLというOSSのツールを使っていることとしました。
(ちなみに下記のファイルもplantUMLで作成したものです。)
plantUML https://plantuml.com/ja/

![conceptual model.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220327/4f54daa8-8e5e-b130-b9bf-f67b35914f6b.png)

```
[conceptual model.pu]
@startuml

/'
 クラスの宣言
 '/
class UMLモデル学習者
class UMLモデル
class スクリプトファイル
class 画像ファイル
enum 確認結果
enum OK
enum NG

/'
 UMLモデル学習者のメソッド、フィールドの宣言
 '/
UMLモデル学習者 : UMLモデルを作成する()
UMLモデル学習者 : UMLモデルを確認する()
UMLモデル : 確認結果

/'
 クラスの関係性
 '/
UMLモデル学習者 "1" -- "0..*" UMLモデル

UMLモデル <|-- スクリプトファイル
UMLモデル <|-- 画像ファイル

確認結果 <|-- OK
確認結果 <|-- NG

/'
 ノートの付与
 '/
note right of UMLモデル
    plantUMLで記述される
end note

note right of スクリプトファイル
    拡張子.pu
end note

note right of 画像ファイル
    拡張子.png
end note

@enduml
```

## ユースケース

それでは、そういった概念の中でどこをUMLモデリング練習帳アプリの範囲として開発していくか考えます。
まず、ユースケースを考えてみると、「UC1.UMLモデルを作成する」、「UC2.UMLモデルを確認する」の二つを考えることができました。
作成は、主にエディタであることを考えると、今回は「UC2.UMLモデルを確認する」を対象範囲とするのが良さそうです。

![usecase.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220327/dddd6d29-1c8f-b9db-f85b-67af7161b42a.png)


## ユースケースのシナリオ(シーケンス)

続いて、ユースケースのシナリオ（シーケンス）を検討していきます。

![UMLモデリング練習帳 シーケンス図.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220327/70248678-6dc0-8796-7421-446d1dd38ba1.png)

ただし、実際にUMLモデルを解析する機能は非常に難しく、このアプリにおける重大な設計課題です。
これについては改めて設計する必要がありますが今は置いておきます。
そのため、今回は作成したUMLモデルのスクリプトが、正解となるスクリプトと一言一句一致しているかどうかを確認することにします。

## ユースケースと機能

先ほどの分析結果からユースケースとアプリの機能の対応は以下となります。

<img width="615" alt="SnapCrab_NoName_2020-2-19_21-17-50_No-00.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220327/a6e88e5c-bea5-dfd5-ea7f-2939125f2a25.png">


# 作るものを決めよう

さて、作るべき機能が明確になったので作るもの決めていきましょう。
今回は、Pythonを開発言語として作ってみることにしました。
UIもこだわらず、まずはCUIで作ることにします。
ただし、UMLモデルを作成するものはplantUMLを利用することにしたため、JVMの環境が必要です。
ではどんな構成でプログラムを作成したらよいかを次に考えてみます。

## 配置

開発する機能は下記の二つなので、main.pyを「UMLモデリング練習帳アプリ」ということにしましょう。
- UMLモデル解析
- 確認結果を表示

pythonを利用することに決めましたが実際には、異なる仕組みを呼び出して利用する必要があります。
そのため、Pythonからshellスクリプトを用いてplantumlを利用するように実装します。
もちろん、plantumlはGraphvizを呼び出しているのでそれも忘れずに…。
ということで、実際には2ファイルのコードを実装することで実現できそうです。

![deployment.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/220327/0dbe01a1-fe0c-251a-775c-74044d6470a3.png)

## 実装

それでは実装していきます。
今回はかなりべた書き…。

```
[main.py]
#! /usr/bin/env python
# -*- coding: utf-8 -*-

import subprocess
import sys
import difflib as diff

args = sys.argv

# args[1] 作成UMLモデルファイル
# args[2] 解答UMLモデルファイル

# 1.UMLモデルを確認する

# 1.1.UMLモデル解析

with open(str(args[1]),"r") as f:
	submit = f.readlines()

with open(str(args[2]),"r") as f:
	answer = f.readlines()

# 1.2.解答結果表示

# 1.2.1.確認結果の出力

# 差分をunified形式で取得
diffs = list(diff.unified_diff(submit, answer, fromfile=str(args[1]), tofile=str(args[2])))

# 確認結果を表示
if len(diffs) == 0 :
    print("確認結果：OK")
else :
    print("確認結果：NG")
    
    # 差分をunified形式で表示
    print("-差分結果を表示します-")    
    for i in diffs:
	    print(i, end='')

# 1.2.2.画像ファイルの出力
completed_process = subprocess.Popen(["run_plantuml.sh", str(args[1])], shell=True)

```

外部のplantumlで画像を出力したいため、下記のスクリプトを実行するようにします。

```
[run_plantuml.sh]
#!/bin/sh
TARGET=$1
echo "plantuml create png image"
echo plantuml file:$TARGET
java -jar plantuml.jar $TARGET
```

# 動きをみてみよう

実装し終えたので、今度は動作を確認しましょう。

## 実行結果

plantuml,Graphvizは利用できるように環境変数を登録しておきます。
登録出来たら、差異があるファイルとないファイルで出力結果を確認してみましょう。

```
$ python main.py 作成UMLモデルファイル 解答UMLモデルファイル
```
### 出力結果

#### 確認結果がOKの場合

```
>python main.py usecase.pu usecase.pu
確認結果：OK
```

#### 確認結果がNGの場合

```
>python main.py usecase.pu usecase_a.pu
確認結果：NG
-差分結果を表示します-
--- usecase.pu
+++ usecase_a.pu
@@ -8,10 +8,11 @@

 actor UMLモデリング学習者

+usecase UMLモデルを作成する
+UMLモデリング学習者 --> (UMLモデルを作成する)
+
 rectangle UMLモデリング練習帳アプリ {
-    usecase UMLモデルを作成する
     usecase UMLモデルを確認する
-    UMLモデリング学習者 --> (UMLモデルを作成する)
     UMLモデリング学習者 --> (UMLモデルを確認する)
 }
```

以上で確認結果が出力できることを確認できました。

# 次回に向けて

さて、今回は一歩一歩ということでCUIベースで作成してみました。
「でもなぁ…サービスなんだから、UMLモデル作成も含めて、Webブラウザ上でやりたいよねー。」
そんな要望がやってきそうです。
ということで次回は、今回の内容をWebアプリにできるかに取り組んでいきます。
https://qiita.com/tomohiro_odan/items/4cd5795768c25242d562

以上。