$shibayu36->blog;

クラスター株式会社のソフトウェアエンジニアです。エンジニアリングや読書などについて書いています。

自分たち夫婦のことや育児のことをインタビューされました

東洋経済の、ほしいのは「つかれない家族」という連載で、夫婦での生活のことや育児のことについてインタビューされました。結構なボリュームになってしまったらしく、3記事に分割されて掲載されました。

toyokeizai.net
toyokeizai.net
toyokeizai.net
toyokeizai.net

インタビューの中では

  • 家庭で使っている便利家電
  • 子供が産まれた後すぐに育休を取ったら非常に良かった話
  • 夫婦間で感謝すること

など、言いたいこと結構話せたなと思ってます。個人的には結構いいこと言えたと思う。

興味がある人はぜひ記事をどうぞ〜。


【PR】ここで一緒にインタビューを受けた妻の書籍が絶賛発売中なのでこちらも是非!妊娠中に2冊本出しててすごかった。

技術的負債のパターンと悪影響・原因・返却方法について考える

先日飲み会で技術的負債についての雑談をしていた。結構いろいろな側面の話をしていたのだけど、技術的負債って一括りにしているのが今はあんまり良くなくて、負債の性質によって技術的奨学金、技術的FX、技術的年金などと言葉を変えると良いのではみたいな半分冗談で会話をしていた。


技術的負債について - hitode909の日記

それで技術的負債のパターンを見つけて、それによりどういう悪影響があるか、それがなぜ起こるのか、どう返却するかについて考えておくと良いのではと思ったので、今日思いついた3つのパターンをメモしておく。

思いついたパターンは3つ。

他にあったり、ここはミスってるとかあったり、こういうことについて書かれている本があったら教えてください。あとたぶんまだまだ分かっていない分野だと思うので、色んな人と一緒に考えていきたい。

変更困難パターン

次にその部分を触った時に負債の影響が一気に襲いかかり、その部分に新しい仕様を追加しようにも非常に時間がかかるという種類の負債。現実の資金の負債と違い、その部分に触らないと負債の影響が現れないというのが難しいところ。触らないと負債の影響が現れないので、特に後回しにされやすいパターン。

どういう悪影響があるか

  • ある部分の変更容易性が損なわれ、新機能や改善により時間がかかってしまう
  • 変更が容易ではないので、その部分に新機能を追加しないようにするためのネガティブな圧力が発生する。これにより事業的に必要でも、エンジニアからnoが起こることが多い
  • エンジニア以外から見えにくい負債なので、他職種との対立が生まれやすい

それがなぜ起こるのか

  • リファクタリングが行われず、同じ機能の実装が何度も変更された
  • 同じ機能の実装を、色んな人が触りすぎた。そしてリファクタリングが行われていない
  • 初めの設計がミスりまくっていた

どう返却するか

  • 一気に返すのは難しいので、新しい機能を実装を作る時はいつもリファクタリング期間込で見積もりを立て、機能を作る前に先にリファクタリングする
  • 一旦その部分のことは一人の人が責任を持つようにして、その実装部分のタスクを特定の人に集中させる。それでコードの整理がある程度ついたら他の人に知見を共有する
  • あまり変更の必要がないようなあまり重要ではない部分だったらいっその事放置する

期限付き返却パターン

OSや言語などのLong-term supportや、外部サービスのAPIのdeprecatedなどの外部要因を原因として起こり、期限がある程度決まっているというパターン。難しいのは、Long-term supportが切れたりしても、ただちにサービスが動かなくなるみたいな問題が起こらないということ。このため、他の新機能作成タスクを優先してしまいがち。

どういう悪影響があるか

  • ある日に突然動かなくなる可能性がある
  • 期限が過ぎると
    • 脆弱性が発見された時に直されないみたいなことがある
    • 速度向上や使い勝手の向上など、新機能が利用できなくなる

それがなぜ起こるのか

  • 時間経過などによる外部要因
  • コードの中身はあまり関係ない

どう返却するか

  • 期限と、その期限が過ぎることによるデメリットが、どちらかといえば見えやすい。そのため先に調査だけすることで新機能作成との優先度を比較がしやすい。簡単な調査を行い、実際のプロダクトバックログに乗せてしまうのが良い
  • 可能ならの返却期限(Long-term supportなどの期限)と、絶対の返却期限(これを過ぎるとサービスが動かなくなる)の二つを可視化して、絶対の返却期限は守れるようにしておく

ヒヤリハットパターン

障害にまでは至ってないけど、何かの拍子に障害が起こる可能性があるパターン。エラーログにまずそうなログが出ているなど、なんらかの傾向が見られたりする。工場とかではヒヤリハットとか呼ばれてたりする?難しいのは、まだ具体的な問題が起こっていないことが多いこと。

どういう悪影響があるか

  • 何かの拍子にユーザー影響のある障害が起こったりする
    • データが消えるなど、クリティカルな影響が起こることもある

それがなぜ起こるのか

  • サービスが成長しデータ量が多くなるなどによって、元々の設計では対応できなくなる
  • 依存している外部要因の変化によって起こる
  • 確率的に発生するバグを生じるコードをもともと入れてしまっている

どう返却するか

まとめ

今回は技術的負債のパターンと悪影響・原因・返却方法についていろいろ考えてみたことを書いてみた。この三つのパターンをあげてみたけど、実際にはパターンが組み合わさったりしてより複雑になっていることも多い。
例えば

  • JSのフレームワークのバージョンが古くなっていて、Long-term supportの期限が切れそう
  • サポートが切れた時に、ブラウザのdeprecatedの機能を使っていた部分がfixされないこともありそうで、どこかで動かなくなりそうという期限付きの場合がある
  • またJSのフレームワークが古いため、開発速度のスピードが下がり(変更が容易でなくなり)、変更困難パターンも包含している

みたいなこととか?


これが正解だとも思えていないけど、技術的負債にパターンを見出し、それぞれの返却方法について深掘りしていくという考え方は良いような気がする。なので他の人はどういうパターンを見出しているのかとかを聞いてみたい。

2018/03/29 21:30追記

Twitterでさらに議論できて面白かったので、こっちも貼っておきます。この議論の中で僕が言いたかったのは、

  • 負債パターンによって、起こる悪影響はぜんぜん違うだろう
  • しかし今は悪影響自体も分離できていないように思える
  • 悪影響を分離し定量化し、その負債の返済コストを定量化すれば、他のタスクと比較可能になる
  • ただし、悪影響の中で観測しづらいものもある。例えば「次にそこを触る時にかかる時間」とか。その場合は別指標に変換もしくは分割できると良いのかもしれない

という感じです。

2018/03/29 22:00追記

さらにいい意見が出てきたので引用させてもらいます。

sbtが依存管理に使っているivyのローカルレポジトリやキャッシュについて調べた

自作のScalaライブラリをpublishLocalしながら手元でリリース前に最終確認する - $shibayu36->blog; で、手元で自作ライブラリの最終確認をするにはpublishLocalすれば良いことを書いた。この時にsbtが依存管理に使っているivyについてもついでに調べたので、調べたことについてメモしておく。コードをちゃんと追いかけているわけではないので、もし間違っていたら教えてください。

ivyとは

ivyとは依存管理のライブラリ。sbtも依存管理にはivyを使っているようだ。

ただし、sbtはivyにパッチを当てて使っていそうに見えたので、これは注意かもしれない。

なぜローカルのivyレポジトリを参照してくれるのか

これはデフォルトでsbtが参照先に~/.ivy2/localがresolverを追加しているからっぽい。Resolverについては https://www.scala-sbt.org/1.x/docs/Resolvers.html あたりを参照。sbtでshow fullResolversすると、何がresolverに追加されているか分かる。

sbt:joda-time-fake> show fullResolvers
[info] * Raw(ProjectResolver(inter-project, mapped: ))
[info] * FileRepository(local, Patterns(ivyPatterns=Vector(${ivy.home}/local/[organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)([branch]/)[revision]/[type]s/[artifact](-[classifier]).[ext]), artifactPatterns=Vector(${ivy.home}/local/[organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)([branch]/)[revision]/[type]s/[artifact](-[classifier]).[ext]), isMavenCompatible=false, descriptorOptional=false, skipConsistencyCheck=false), FileConfiguration(true, None))
[info] * public: https://repo1.maven.org/maven2/

このFileRepositoryの部分がローカルのivyレポジトリを参照するための設定。ivyPatternsあたりを見ると${ivy.home}/local/[organisation]/[module]/(scala_[scalaVersion]/)(sbt_[sbtVersion]/)([branch]/)[revision]/[type]s/[artifact](-[classifier]).[ext]と書いてある。実際のjarファイルが置いてある場所の~/.ivy2/local/com.github.shibayu36/joda-time-fake_2.11/0.0.3-SNAPSHOT/jars/joda-time-fake_2.11.jarとくらべてみると

  • com.github.shibayu36が[organisation]にマッチ
  • joda-time-fake_2.11が[module]にマッチ
  • (scala_[scalaVersion])はマッチしないけど括弧で包まれているので問題ない
  • (sbt_[sbtVersion]/)も同様にマッチしない
  • ([branch]/)も同様にマッチしない
  • 0.0.3-SNAPSHOTが[revision]にマッチ
  • [type]sがjarsにマッチ
  • joda-time-fake_2.11.jarが[artifact](-[classifier]).[ext]にマッチ

ということで、ちゃんと使われるということなのかな?このPatternについてはhttps://ant.apache.org/ivy/history/latest-milestone/concept.html#patterns あたりも参考になった。

ivyのキャッシュについて

ivyは毎回アーティファクトをダウンロードに使わないためにキャッシュしているようなので、このあたりについても調べた。sbt利用上のIvyに関するハマりポイント - たけぞう瀕死ブログが参考になった。

まずキャッシュのディレクトリは~/.ivy2/cache/以下にある。先程のjoda-time-fakeのキャッシュを見てみると、以下のようになっている。

$ tree ~/.ivy2/cache/com.github.shibayu36/joda-time-fake_2.11/
/Users/shibayu36/.ivy2/cache/com.github.shibayu36/joda-time-fake_2.11/
├── ivy-0.0.1-SNAPSHOT.xml
├── ivy-0.0.1.xml
├── ivy-0.0.2.xml
├── ivy-0.0.2.xml.original
├── ivy-0.0.3-SNAPSHOT.xml
├── ivydata-0.0.1-SNAPSHOT.properties
├── ivydata-0.0.1.properties
├── ivydata-0.0.2.properties
├── ivydata-0.0.3-SNAPSHOT.properties
└── jars
    └── joda-time-fake_2.11-0.0.2.jar


まずリモートレポジトリからfetchしてきたものに関しては、jars以下にjarファイル自体をキャッシュしているようだ。なのでjars以下にjoda-time-fake_2.11-0.0.2.jarが存在している。またivydata-0.0.2.propertiesというファイルを眺めてみると

ivydata-0.0.2.properties

#ivy cached data file for com.github.shibayu36#joda-time-fake_2.11;0.0.2
#Sun Mar 25 08:46:10 JST 2018
artifact\:ivy\#ivy\#xml\#742964223.is-local=false
artifact\:joda-time-fake_2.11\#jar\#jar\#1850426835.is-local=false
artifact\:ivy\#ivy\#xml\#742964223.location=https\://repo1.maven.org/maven2/com/github/shibayu36/joda-time-fake_2.11/0.0.2/joda-time-fake_2.11-0.0.2.pom
artifact\:joda-time-fake_2.11\#jar\#jar\#1850426835.location=https\://repo1.maven.org/maven2/com/github/shibayu36/joda-time-fake_2.11/0.0.2/joda-time-fake_2.11-0.0.2.jar
artifact\:joda-time-fake_2.11\#pom.original\#pom\#-791977799.is-local=false
artifact\:joda-time-fake_2.11\#jar\#jar\#1850426835.exists=true
artifact\:joda-time-fake_2.11\#pom.original\#pom\#-791977799.location=https\://repo1.maven.org/maven2/com/github/shibayu36/joda-time-fake_2.11/0.0.2/joda-time-fake_2.11-0.0.2.pom
artifact\:ivy\#ivy\#xml\#742964223.exists=true
artifact\:joda-time-fake_2.11\#pom.original\#pom\#-791977799.exists=true

となっており、

みたいなことが書いてある。なるほど。


続いてpublishLocalしたレポジトリから取ってきた、0.0.3-SNAPSHOTのほうを見てみると

ivydata-0.0.3-SNAPSHOT.properties

#ivy cached data file for com.github.shibayu36#joda-time-fake_2.11;0.0.3-SNAPSHOT
#Sun Mar 25 10:06:08 JST 2018
artifact\:joda-time-fake_2.11\#jar\#jar\#679424103.is-local=true
artifact\:ivy\#ivy.original\#xml\#1006386850.exists=true
artifact\:joda-time-fake_2.11\#jar\#jar\#679424103.location=/Users/shibayu36/.ivy2/local/com.github.shibayu36/joda-time-fake_2.11/0.0.3-SNAPSHOT/jars/joda-time-fake_2.11.jar
artifact\:joda-time-fake_2.11\#doc\#jar\#-517561348.exists=true
artifact\:joda-time-fake_2.11\#doc\#jar\#-517561348.is-local=true
artifact\:joda-time-fake_2.11\#doc\#jar\#-517561348.location=/Users/shibayu36/.ivy2/local/com.github.shibayu36/joda-time-fake_2.11/0.0.3-SNAPSHOT/docs/joda-time-fake_2.11-javadoc.jar
artifact\:ivy\#ivy.original\#xml\#1006386850.location=/Users/shibayu36/.ivy2/local/com.github.shibayu36/joda-time-fake_2.11/0.0.3-SNAPSHOT/ivys/ivy.xml
artifact\:ivy\#ivy\#xml\#-428038509.exists=true
artifact\:ivy\#ivy\#xml\#-428038509.location=/Users/shibayu36/.ivy2/local/com.github.shibayu36/joda-time-fake_2.11/0.0.3-SNAPSHOT/ivys/ivy.xml
artifact\:ivy\#ivy.original\#xml\#1006386850.is-local=true
artifact\:joda-time-fake_2.11\#src\#jar\#-1768464466.is-local=true
artifact\:joda-time-fake_2.11\#src\#jar\#-1768464466.location=/Users/shibayu36/.ivy2/local/com.github.shibayu36/joda-time-fake_2.11/0.0.3-SNAPSHOT/srcs/joda-time-fake_2.11-sources.jar
artifact\:ivy\#ivy\#xml\#-428038509.is-local=true
artifact\:joda-time-fake_2.11\#src\#jar\#-1768464466.exists=true
artifact\:joda-time-fake_2.11\#jar\#jar\#679424103.exists=true

となっており、

  • localである
  • ローカルのivyレポジトリのjarファイルへの参照も書いてある
    • artifact\:joda-time-fake_2.11\#jar\#jar\#679424103.location=/Users/shibayu36/.ivy2/local/com.github.shibayu36/joda-time-fake_2.11/0.0.3-SNAPSHOT/jars/joda-time-fake_2.11.jarあたり?

となっていた。なるほど〜。


これらの調査から、sbt利用上のIvyに関するハマりポイント - たけぞう瀕死ブログに書かれていた、

Ivyはローカルリポジトリに格納されているライブラリに対してはjarファイルを絶対パスで参照するメタファイルのみキャッシュします。上記ではライブラリは一度キャッシュされたら更新チェックは行われないと書きましたが、ローカルリポジトリのjarファイルについてはjarファイルそのものがキャッシュされているわけではなく、参照がキャッシュされているだけなのでpublish-localするだけで変更が反映されるということになります。

をなんとなくであるが理解することが出来たように思う。

キャッシュ周り、このあたり理解できてないとむっちゃハマりそうだな〜。

まとめ

今回はsbtが依存管理に使っているivyのローカルレポジトリやキャッシュについて調べて、その内容をメモした。自分で適当にライブラリを作ってみると、こういう感じで依存管理やビルドツールについても詳しくなれるので便利。