2020年なのにコード上に履歴持つスタイルを何とかする

# きっかけ

![Ostrich.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42445/142eab61-16cd-f1ae-6e62-73f0f2458b02.png)

ツイッターで会社にある変な文化みたいな話があった。コードの変更履歴をコードに持つという話。
要はこんな感じ。

```text
// 2020/03/17 UPDATE START
// ....
int x = 2038;
// 2020/03/17 UPDATE END
```

この履歴の取り方は、私がITに入った2000年頃には存在していた。
もうすでに消滅した文化と思っていたのだが、なんと20年近く同じことを繰り返していたのだ。
今は2020年。コードの変更履歴をコメントで入れる必要など0.01mmも存在しない。
何なら当時から皆`これ無駄じゃね？`と感づいていた。
まぁ、無駄になったコストは顧客が被ることになるのだが、それはまた別の話。
この変な文化の特徴は、`自らコードの可読性を落として、開発リソースを食う`と言う~~アホな~~独特なスタイルだ。

自らコードの可読性を落として、開発リソースを食う。

どこかで聞いたことはないだろうか。

自ら失敗しやすい状況を作って、失敗する。。。
自分でハードル上げて、コケる。。。
押される状況を作って、押される。。。
そう、まさにダチョウ倶楽部。

私はこの開発手法をダチョウ倶楽部型開発、DCD(Dacho Club Development)と名付けた。
いまだにDCDの手法が生き残っているのならば、エンジニアとして対処しなければならない。

# 結果

![ostrich_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42445/f1783c05-df8a-931f-c8ef-336c0ecad8f4.png)


<font color="dark_pink">やったぜ(やってない)</font>

DCD支援(?)ツールはgithubに上げた。

 + [miyatama/ostrichdev](https://github.com/miyatama/ostrichdev)

現状のままでは実務プロジェクトには適用できるレベルではない。
なので使われる事はまずないとは思うが、マジで使われることが無い事を祈ってる。

# アプローチ

2020年現在であの変なコメント(以下、「Ostrich Comment」)を必要としているのは下記の様な人のハズ

 + Ostrich Comment付きでコードレビューがしたい
 + Ostrich Commentがある事で安心感を得たい

であれば、Ostricher向けのブランチ(以下、「ostrichブランチ」)を作り、Ostricherをそこに閉じ込める事でOstrich Commentの影響を最小限に抑えられるハズ。
開発チームはmaster/developで健全な開発を行えるという寸法だ。
やる事は

 + master/developへのpushを検知
 + コミット内容を解析
 + Ostrich Comment(*1)を差し込む
 + ostrichなブランチへpushする。
 
Ostrich Commentのルールは以下の通り

追加された行に関するOstrich

```text
// 2020/04/01 ADD START MIYATAMA
追加された行
// 2020/04/01 ADD END MIYATAMA
```

変更された行に関するOstrich

```text
// 2020/04/01 UPDATE START MIYATAMA
// 変更前の行
変更後の行
// 2020/04/01 UPDATA END MIYATAMA
```

削除された行に関するOstrich

```text
// 2020/04/01 DELETE START MIYATAMA
// 削除された行
// 2020/04/01 DELETE END MIYATAMA
```

うん。何回見ても開発をうまく進めないための正しいやり方。

さらに、尚、歴戦のDCD経験者ならばとInnerOstrichの違いを指摘したいところだろう(今回は対象外の機能)。

OuterOstrichは修正履歴が増えた時に常に外側が最新となる。

```go:OuterOstrich
func main() {
  // 2020/03/27 DEL START MIYATAMA
  // // 2020/03/26 MOD START MIYATAMA
  // // // 2020/03/25 ADD START MIYATAMA
  // // fmt.Println("hellow world")
  // // // 2020/03/25 ADD START MIYATAMA
  // fmt.Println("hello world")
  // // 2020/03/26 MOD END MIYATAMA
  // 2020/03/27 DEL END MIYATAMA
}
```

InnerOstrichは常に内側が最新となる

```go:InnerOstrich
func main() {
  // 2020/03/25 ADD START MIYATAMA
  // 2020/03/26 MOD START MIYATAMA
  // fmt.Println("hellow world")
  // 2020/03/27 DEL START MIYATAMA
  // fmt.Println("hello world")
  // 2020/03/27 DEL END MIYATAMA
  // 2020/03/26 MOD END MIYATAMA
  // 2020/03/25 ADD END MIYATAMA  
}
```

デジタルネイティブの方は、さぞ`正気か？`と感じたことだろう。
おっさんから上の人間は真面目な顔してこれやってたのだ。

尚、実務利用に当たっては下記機能が必要となるが今回は対象外。やりたいなら自分で作ったら良いと思う。

 + ホワイトリスト(Ostrich対象外ファイルの指定)
 + inner ostrich/outer ostrichの指定
 + ostrich commentのフォーマット指定
 + 2回目以降の修正(複数コミットの対応)

*1: ダチョウ倶楽部型開発で使うコメントルール

# 使い方

githubは~~やらかすと怖い~~リスクが高いので今回はgogsを元に組んでゆく。

 + Gitサービスを立ててリポジトリ作る
 + OstrichDevを仕掛ける
 + Git hookを仕掛ける <- ここで呼ばれる
 + pushしてダチョウ倶楽部感を得る

ざっくりとした流れは下記の通り。ostrichdevはWebIFでやる。

![ostrich_flow.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42445/4c78df1c-8fda-7654-8a6a-7092a2a6e7f5.png)


## Gitサービスを立ててリポジトリを作る

gogsでサービス立てる。とある理由でラズパイ使う。

```bash
sudo apt-get update && sudo apt-get -y upgrade
curl -OL https://github.com/gogs/gogs/releases/download/v0.11.91/raspi_armv7.tar.gz
tar fx raspi_armv7.tar.gz
cd ./gogs
```
デフォルトで3000を使うので、ポート番号指定させないためにnginxを導入する。自前でビルドするもよし、apt経由で取るもよし。nginxの導入に関しては下記リンク参照にて割愛。

 + [Raspberry piに最新版のNginxを導入する](https://qiita.com/ochomaki/items/b9e1353a50ea43c50a35)
 + [PCRE library needed](https://www.raspberrypi.org/forums/viewtopic.php?t=89196)
 + [FAQs](https://gogs.io/docs/intro/faqs)

で、nginxとgogs起動

```bash
sudo nginx
./gogs web &
```

後はブラウザから開いて適当にリポジトリ作ったら、developのブランチ作成。

```bash
git clone 
cd script-checker
touch README.md
cat << EOF >> main.go
package main

import "fmt"

func main() {
  fmt.Println("hello world")
}
EOF
git add ./*
git commit -m "this is first commit"
git push origin master
git checkout -b developgit add ./*
git push origin develop
```

こんな感じになってればOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42445/8dbd45b6-06c5-8fc0-b37f-a604778e8538.png)

## OstrichDevを仕掛ける

ローカルホストの3030で待ち受ける。ラズパイへのGo言語設定は[Raspberry PiにGo言語をインストールする](https://qiita.com/Brutus/items/cdf077a4d161bd32a34b)と言う素晴らしい記事を参照の事。


```bash
git clone github.com/miyatama/ostrichdev
cd ostrichdev
make
mkdir -p ~/ostrichdev/log
cp ./ostrichdev ~/ostrichdev/
cd ~/ostrichdev
./ostrichdev -behavior web -port 3030 >./log/ostrichdev.log 2>&1 &
```

## Git hookを仕掛ける

gogsはGUI上でサーバサイドhookの編集ができる。尚、実際に利用する際はostrichdev側で多重起動(と呼び出し順適用など)の対策を行う必要がある。

```bash:update
#!/bin/bash

user_home="/home/pi"
script_home="${user_home}/ostrichdev"
log_dir="${script_home}/log"
log_file="${log_dir}/ostrichdev.log"

mkdir -p "${log_dir}"
echo "branch: ${1}" >> ${log_file}
echo "before commt: ${2}" >> ${log_file}
echo "after commit: ${3}" >> ${log_file}

branch=`echo "${1}" | tr '/' ' ' | awk '{ print $NF }'`
commit_id="${3}"
echo "branch: ${branch}" >>  ${log_file}
echo "commit id: ${commit_id}" >>  ${log_file}

if [ "${branch}" = "develop" ]; then
  data=`cat << EOF
{
  "repository": "pi@miyapi:miyatama/ostrichers-project.git",
  "fromBranch":  "${branch}",
  "ostrichBranch": "ostrich",
  "commitId": "${commit_id}"
}
EOF
`
  curl \
    -L \
    -XPOST \
    -H 'Content-Type: application/json' \
    -d "${data}" \
    http://localhost:3030/ostrich &

fi
  
exit 0
```


## pushしてダチョウ倶楽部感を感じる

さぁ、あとは編集したり追加したりしてpushするだけ。
developで編集してpush。コマンド割愛。

```go:main.go
package main

func main() {
  fmt.Println("hello the world")
}
```

Ostrichブランチへのpushが終わるのをまって

![ostrich_apply.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42445/0f2c7a2b-197e-f7ef-6c9e-9b6f8ca9950e.png)


ostrichブランチを確認

![ostrich_result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/42445/3ddb6527-e12b-0ec1-75b7-95217a347122.png)


<font color="dark_pink">無駄に脳を使うスタイルとか正気じゃないよね。。。</font>

# 振り返り

git hook連動は何気に初めてだったのでいろんな知見がたまった

 + update内ではgitコマンドがうまく動かない
 + update内から別のWebサービスを呼び出せるが、Webサービス内でコミット情報がうまく取れない。
 + goはテストが書きやすくて超ありがたい。
 + etc

尚、この記事を書こうと決めてから早2カ月が経過している。

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">そうか、まだコメントで変更履歴残すなんて物が生き残ってるのか。よし分かった。<br>developにpushしたら差分をコメントにしてmasterにpushするアプリを作ろう。そしたらdevelopが最新だ(混乱)</p>&mdash; miyatama@長所は早退で来世はサバ (@miyata080825) <a href="https://twitter.com/miyata080825/status/1239796022638854146?ref_src=twsrc%5Etfw">March 17, 2020</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

<font color="dark_pink">2カ月間の間にマスク(アルミ製)を作ったりしてました。</font>