やる気がストロングZERO

やる気のストロングスタイル

システム開発での作業優先度の付け方とか

仕事とかで優先度について考えること多いけど、優先度の決め方って人によって結構異なる気がした。
自分は優先度の決め方にそれなりに理屈を持ってやってるつもりで、それは個人開発やってた経験が大きく影響していて、そのあたりについて書いてみる。

(個人開発の経験が大きく影響しているので、企業開発の場合に求められる物と少しズレはあるかもしれない。これについて自己認識出来ている部分は記載しておく。)

完璧主義をやめて優先度を考える

優先度決めるとき「これも大事、これも大事」ってなって「全部優先度(高)」みたいなのってありがち。
人って基本完璧主義で、理想が高すぎるんだと思う。

個人開発でもよく「これも盛り込みたい、あれも入れたい」ってやってて結局完成できずお蔵入り、、ってのも多い。

企業開発でも個人開発でもやりたい事に対して基本的に工数は不足する。
なので「やりたい事はできない」を基本マインドにする。

その「できない」の中から「できそう」な事をチョイスしていくイメージ。

優先度決めの作業で無数の要望の中から優先度(超高)を数えるくらい選んだら、残りが優先度(高)なのか(中)なのか(低)なのかは考えるだけ工数の無駄なので考えない。(超高)の実装が済んで初めて考える。予め検討しても状況も変わってるのでどうせ考え直すことになる。

個人開発なら上記した事でOKだが、企業開発だとこれに追加の事情が加わる。

別部門からの要望で「とにかく絶対にこの機能は必要!優先度超高でお願いします!」みたいなやつ。
結果、優先度超高で溢れることになる。

これはステークホルダーそれぞれの譲れない事情があって(よくよく議論してみるとそうでない場合も多いが)、それらが全部開発に降ってくるから発生するのだと思っている。
例えば営業にとっては今季の利益を上げることが何よりも優先なので、開発からみたら「一時的に利益あげても払う工数に対しての見返り少なくない?」っていう理論はあまり理解されない。
もちろん会社がなくなっちゃったら元も子もない。利益は大事。
ただ、この一時的な利益を優先するために失われるものも確かにあって、それは継続的は利益を得るための機能実装や、現在赤字になっている状況の解消の先送りであったり。

こういう状況でどれを優先させるかの判断は開発だけでも営業だけでもできないので、少し上のレイヤーの職位の人の判断になるパターンだと思ってる。

相手の言っている優先度の高い要求を受けるかどうか考える時、その要求が会社としての要求なのか、その人個人の要求でしかないのかを知る必要がある。
この時、相手が「要求を開発にいかにねじ込むかが腕の見せ所である」みたいに認識しているパターンだと優先度の議論が成立しないので、ちょっと難易度が高くなる。

マシなパターンに倒すことで、最悪のパターンを避ける

優先度とは少し異なるが「マシなパターンに倒すことで、最悪のパターンを避ける」というのを意識している。

個人開発をやるにあたって最悪のパターンとは「モチベーションを失って、結局アウトプットが何もない」である。

個人開発は無償で苦しさに立ち向かわなければならず、それを支えるのはモチベーションのみである。
なにか作ろうと思い立ったとき一番モチベーションが高いが、徐々にそれは失われていく。
他に興味が移っても失われる。基本いつ失われるかわからないと思っておく。

開発半ばでモチベーションが失われるとそれ以降開発はほったらかされ、そこまでどれだけ完成度が高くてもリリースされなければアウトプットはゼロである(経験は残るが)。

この「モチベーションを失って、結局アウトプットが何もない」を避けるために以下の戦略を取っていた。

  • 機能を極限まで絞ってリリースしてしまう。その後、モチベーションが続く限りほそぼそと追加機能開発を行う。
  • 開発で得られた知見をブログなどでアウトプットする。

完璧主義を捨て、機能を極限まで絞ったしょぼい状態でリリースまで持っていく。
結果これがモチベーション維持にも繋がる。やっぱ本番で動いているというのは気持ちが盛り上がる。
あとはいつモチベーションが失われてもリリースした事実とモノが残るという算段。

また、ブログで知見をアウトプットすることで、リリースまでいかなくても「アウトプットゼロ」を回避する。

上記は個人開発での話だが、企業開発でもやたら仕様が大きくなってまとまらなくなり、このままだと期限にリリースできない(最悪パターン)が見えたときに「一旦、最小仕様(マシなパターン)で作ってみて、その後追加仕様で改めて検討しませんか?」みたいに提案したりする感じ。

曳光弾

開発中は「急だけど来週リリースな」って言われる可能性が常にあると思って開発する。
リリース日が動かなくても、差し込み業務で丸一ヶ月の工数が吹っ飛ぶ可能性を意識している。
個人開発で言うと、突如モチベーションが失われてしまって、来週中にリリースできなければお蔵入りになってしまう、みたいな状態。

だから開発は、まずリリースできる状態まで持っていき、それ以降常にリリース出来る状態をキープする。
※ここで言う「まずリリースできる状態まで持っていき」とは最小機能で、要求仕様は全く満たせていないがとりあえず動作する、程度の状況

達人プログラマーという本で曳光弾という名前で紹介されていた(うろ覚え。こういう事を言ってたような気がする。もしかしたら違うかも)

例えばECシステムで必要な機能って、

  • 商品一覧
  • カート機能
  • 決済機能
  • 商品登録・編集
  • 在庫管理
  • 会員管理
  • その他もろもろ

みたいに色々あるけど、とりあえず商品一覧が閲覧できる状態で本番で動くところまで持っていく。

極端だけど、ここまで作って「来週リリースな」ってなった場合、

  • 商品登録や編集はDBを直接触って登録
  • カートとか決済機能はないので、商品見て電話問い合わせで購入オペレーション。支払いは代引きとか使ってもらう
  • 会員管理もエクセルとかでやってもらう

みたいな、条件は色々あるけどリリースはしようと思えばできる、という状態にできる。
(もちろん企業開発だと「最低ラインの品質」というものはあるが)

これが例えば、全部の機能を並行して作っていると「来週リリースな」の時点で出来ている機能が何もない(カート機能はできてるけど、商品一覧がまだないとか。)、本番環境自体まだない、というような状態になる。

こうなると、この一週間で本番環境構築しながら最低限の機能開発を突貫でやらねばなくなり、あわあわすることになる。。

優先度の決め方イメージ

優先度の決め方は「その機能って無いとどうにもならないのかどうか」で考えている。

工数にもよるけど、例えば

カート機能:「電話でショップに問い合わせてもらうようにすれば購入できる」ので「どうにかなる」
商品一覧表示:「電話で問い合わせても一覧から選ぶという行為は難しい」ので「どうにもならない」

というわけで商品一覧が優先。

会員登録、決済機能もエクセルや代引きとかで「どうにかなる」ので優先度は低め
商品登録・編集機能は「毎回DB直接いじればどうにかなるが、運用をショップに任せるのであればどうにもならない」ので優先度高め
在庫管理は「在庫切れしていれば断りの連絡を入れたり、商品を取り下げておいたり出来る」ので「どうにかなる」ので優先度低め

みたいな感じ。

「どうにもならない」のやつが一通り実装できたら「どうにかなるって言うけど、実質これがないと運用が回らない」といったものに着手していく。
さっきの、カート機能:「電話で問い合わせて貰えれば購入できる」あたりは(規模によっては)実質運用難しいと思うのでこのあたりが候補になりそう。

売上管理とか、トレンド予想とか、おすすめ商品機能とか高優先度で希望されたりするけど、軒並み優先度低め。
こういうのは基本機能が揃ってから手を出すべき。

あと、以外に盲点としてシステム開発・運用側で優先度高い機能があったりする。
アラート通知まわりとか、CICD整備とか、バッチ処理の失敗時の復旧オペレーションの建付けとか機能化とか。 こういうのは初期にやっておくと、以降の工数が福利っぽく浮いてくるので優先度高でやっておきたい。

、、みたいな感じ。

フォークト・小柳・原田病になった

突然フォークト・小柳・原田病という病気になった。

自己免疫機能が自分のメラノサイトを攻撃してしまうという病気で、アジア人の場合は毛根や目に影響があらわれるということらしい。
自分は症状としては、視力が急激に低下し文字が読めなくなった。人の顔も判別できなくなった。(入院した後、ある程度症状は回復しています)
激しめの頭痛や、徐々に耳鳴りなども発生した。

症状について

症状としてあらわれたのは、頭痛・視力低下・耳鳴りだった。
頭痛はわりと激しめで、ロキソニンなしだと活動できないくらいだった。
視力低下も激しく、徐々に見えなくなっていったが、一番ひどい状態のときは人の顔を判別できない程度に低下していた。スマホも文字がまったく読めないのでなにも操作できない。
真っ暗闇、という感じではなく全体的に黄色がかっていて、光は薄暗く感じ、視界の至る所に黒い斑点模様があらわれ、その斑点の範囲は物の輪郭しか判別できないような状態だった。 また、像も歪みまくっていて、本来真っすぐなラインがぐにゃぐにゃに歪んでみえた。
物の詳細はまったく見えないが、全体感はわかるので、昼間よく知っている道なら目的地へ向かうというようなことはできた。

発症と経過時系列

夜、少し頭痛あるなと思いながら寝て、翌朝起きると周辺視野に黒い斑点があった。
起きて数時間立っても消えなかったため眼科にて見てもらった。
眼底写真で検査したところ、眼底に水が溜まっており、そのせいで眼底に凹凸ができている事によって視界に異常が現れているとのことだった。詳しい担当が翌々日に病院にいるので、あらためて検査しましょうという話になった。
翌日も症状が悪化していたので、取り急ぎ別の眼科にみてもらったところ「おそらく原田病」と診断され、入院施設のある病院への紹介状を書いてもらい、そちらで見てもらうことになった。

翌日、そちらの入院施設のある病院で検査してもらい、土日を挟んで月曜から入院し治療することになった。

入院までの土日でさらに症状は悪化し、黒い斑点が視界の中心まで広がって文字も読めないような状態に突入した。

月曜になって入院し、ステロイドの点滴を合計6日間(中休み1日)行って、徐々に症状は回復し合計9日間の入院で退院となった。
ここから半年くらいは経口薬を処方されながら通院による治療となる。

現在は仕事もできるくらいに視力は回復した。黒い斑点も平常時は認識できないくらいに薄くなった。
だが、正常時にくらべてまだ全体的に視界が暗いし、全体的にコントラストが弱い感じがする。歪みも少し残っている。
これも徐々に回復していくということらしいので気長に回復を待とうと思う。

心境変化など

今回の病気はたまたま医療が治療法を確立していたお陰で症状回復させられたが、僕がサバンナの野生動物だった場合は視力は今回で失われており別の肉食獣の餌食になっていたハズである。
そうなると、本来の僕の寿命はここまでだったんだなぁと思った。
今後は運のお陰で生きていられる延長線であるような感覚が得られた。
人生で何を大切にするかを改めて考えたいとおもった。

入院すると人との繋がりが非常に大切なものに思えた。
心配してくれる人がいるということが大きな心の支えとなっているのを感じた。

入院前は育児や仕事で自分の時間が持てない事にフラストレーションを感じた生活をしていた。
入院中視力がある程度回復してから得られた死ぬほどの自由時間で、好き放題SNSを見たり、Netflixを見たりしてみたが、なぜか全く面白いと思えなくなっていた。

こんな事をしたいと思ってフラストレーションを溜めていたのかと馬鹿らしくなって、こんな物よりも家族との生活自体がどれだけ価値のあることであるかと認識できるようになった気がした。

退院してからも、以前のようにフラストレーションを感じることなく、以前よりも自然に育児・生活に参加できるようになった気がする。

Railsで実装した処理はどうやって実行されるのか

Railsで実装した処理は、どうやって実行されるのかが理解できたのでメモ。

わからなかったこと

ブラウザからリクエストが送出され、webサーバ(Nginx等)に到達し、webサーバからAppサーバ(Unicorn等)に流されるのは理解していた。
AppサーバがどうやってRailsで実装した処理を呼び出しているのかわからなかった。

Railsでは「こういうリクエストがあったとき、このメソッド(controller)が呼び出される」という取り決めがあるが、なぜそれが呼び出されるのか?
呼び出すのはおそらくAppサーバであるが、Appサーバ(Unicorn等)は別にRails専用というわけではないのになんでRailsのメソッドが呼び出されるようになっているのか?どこでそういう設定をしたのか?
Rackってよく説明で出てくるけど具体的になんなのか?

わかったこと

Railsの処理はAppサーバのプロセスとして実行される

Railsアプリケーションのプロセスが存在しているわけではなく、Appサーバのプロセスの中でRailsの処理は実行される。
Appサーバの処理の中で、Railsの処理が書かれたメソッドを直接呼び出している。

Rackはインターフェースで、これを実装しているオブジェクトをAppサーバは利用することができる

Rackはプログラミング言語のコンテキストで言われるインターフェースである。(もしかしたら「Rack仕様というものの一部にRackインターフェースがある」というような構造になってるかも)

Javaで書くと以下のイメージ

class SomeClass implements Rack {
...
}

Rubyにはインターフェースを表す構文が無く、Rackインターフェースを満たすようにメソッドを実装していればRackインターフェースを実装したことになる。(ダックタイピング)

Railsアプリケーションを表すオブジェクトRails.applicationはこのRackインターフェースを実装している。

そして、AppサーバはRackインターフェースを実装したオブジェクトを使うように実装されているので、Railsアプリケーションを使う(メソッドを叩く)ことができる。

どこでAppサーバにRailsの処理が呼び出されるように設定しているのか

Appサーバは起動時にconfig.ruというファイルを読み込む。(もしかしたらこれもRack仕様の一部かも)
Railsの場合、config.ruに以下のような記述がある。

require_relative 'config/environment'
run Rails.application

これによってAppサーバはRails.application(Rackインターフェースを実装している)の存在を認識し、リクエストが来たらRails.applicationのメソッドを呼び出し、Railsの処理を呼び出している。

GCについて調べてて理解したことの雑メモ

GCについて調べてて理解したことを雑にメモります。(間違いあったらご指摘ください)

GCでやること

不要オブジェクトの開放

これはそのままの意味。もう使われていないオブジェクトは破棄してメモリを開ける。

使用オブジェクトの再配置

メモリの確保、開放を繰り返すとメモリがフラグメント化する。 オブジェクトは連続したメモリ領域に配置される必要があるため、フラグメント化すると全体としては空き領域があるのにオブジェクトを確保できなくなったりする。 そのため、確保されているオブジェクトを再配置してフラグメント化を解消する。

アルゴリズム

細かくは色々あるけどざっくり以下

定期的にまとめてGC

定期的にメモリを走査して不要オブジェクトを開放する。 「定期的」とは一定時間だったり、メモリ不足のタイミングだったりする。 メモリ全体を処理するので時間がかかる。スレッド停止時間も長い。

JavaとかRubyとかはこれらしい。

参照が切れたら即GC

オブジェクトごとに参照カウンタをもっていて、これが0になったら即開放される。 都度都度実行されるので処理時間は短いが、参照カウンタの運用などにオーバーヘッドがあったりメモリが必要だったりする。 また、条件によっては大量のGCが必要になり停止時間が長くなったりする。

Pythonがこれらしい。

これらはどれか一つというわけではなく、複合的にアルゴリズムが組み合わされて使用される。

だれがGCを行っているのか?

JVMインタプリタ言語の場合

Javaの場合はJVM

Rubyの場合はRubyインタプリタPythonも同じくPythonインタプリタ

実行ファイルを実行する言語の場合はだれがGCを実行するのか?

CやC++にはGCを言語レベルでは提供していない。(ライブラリはあるらしい) Goには言語レベルでGCが提供されているらしい。

GCが提供されているかどうかは言語のRuntimeによるところっぽい。

言語のRuntimeについて(想像)

各言語で書かれた処理がコンピュータで実行されるとき、実行の仕組みを提供している部分があると思っている。 これが処理系だとかRuntimeだとか実行系だとか呼んでいる部分だと思っている。 Javaの場合はJVMがこれを、RubyとかPyhonはインタプリタがこれを提供している感じ。

CやGoの場合は成果物(バイナリ)内にRuntimeが同梱されていて処理されていて、Goの場合はここにGCの機構も含まれているのでGCがある。 Cの場合はここにGCの機構が無いのでない。

という感じなんかな。

各言語のRuntime周りの情報が得られれば確認できると思うけど、どこを調べればいいのかよくわからない。コードを読む感じになるのだろうか

Javaパフォーマンスを読んでる 5章

Javaパフォーマンスを読んでる。

自分なりに理解した内容をメモる。

5章:ガーベージコレクションの基礎

ガーベージコレクション概要

定期的にヒープを走査して参照されていないオブジェクトを開放する。
断片化解消のため、メモリの配置し直しをする。
これを実行しているとき、Javaアプリケーションの処理は停止する。

Young領域とかOld領域とか

Young領域やOld領域をヒープ内にもっていて、定期的にGCを実行して使用中オブジェクトを整理している。
新規オブジェクトはYoung領域に確保され、そこが一杯になると軽量のGCが発生する。(young領域はヒープの一部分なのでGCにかかる時間が短い)
YoungGCはスレッド停止(アプリケーション停止)を伴い、未使用オブジェクトを開放し、使用中オブジェクトをOld領域やSurvivor領域に移動させる。
こうすることで、メモリ開放と断片化解消を行う。
YoungGCがたくさん実行され、次第にOld領域が一杯になるとFullGCが実行される。
FullGCはヒープ全体に対してのGCなのでYoungGCに比べて時間がかかる。そのためスレッド停止時間も長い。

パフォーマンス・チューニングの基本戦略としては「なるべくYoungGCのみでFullGCは起こさないようにする」になる。
もちろんアプリケーションがどのように使われるかによる部分であり、定期的に処理が遅くなる(FullGCによる長時間スレッド停止)が許容できるならFullGCを頻発させるほうが全体のパフォーマンスとしては良い、というのもありえる。

GCアルゴリズム

GCには複数のアルゴリズムがあり、上記の説明どおりのアルゴリズムから、なるべくFullGCを起こさないようにするアルゴリズムもある。
たとえばG1アルゴリズムはヒープを複数の領域に分けて管理することで一つ一つの領域のGCによる処理停止時間を短くしたり、GC処理の一部はメインスレッドと並列で走らせるなどしてアプリケーションの停止をなるべく引き起こさないようにしたりしている。
ただし、どのアルゴリズムでもOld領域がいっぱいになればやはりFullGCは発生する。

パフォーマンスチューニング

ガーベージコレクションのチューニングによるパフォーマンスチューニングとは、

  • どの程度のスレッド停止が許容されるのか?
  • まとめて長時間停止で回数を少なくしたほうがいいのか?
  • こまめに短時間停止で回数を多くしたほうがいいのか?

このあたりを見極めてヒープの領域配分やしきい値調整をすることであると理解した。

Javaパフォーマンスを読んでる 4章

Javaパフォーマンスを読んでる。

自分なりに理解した内容をメモる。

4章: JITコンパイラの仕組み

javaコードは一度Javaバイトコード(バイナリとコードの中間地点)に変換される。
JavaバイトコードJavaバイナリが読み取り各環境に対応したCPU命令に変換して実行していく。(1行ごとに読みこんでインタプリタ的に実行)
何度も繰り返し実行される部分はコンパイルされてコードキャッシュに保存される。(JITコンパイル

すぐにコンパイルされない理由

javaでは繰り返し実行するコードがコンパイルされていると全体のパフォーマンスはよくなる。
1回しか実行されないコードはコンパイルするとパフォーマンスが悪くなるのでコンパイルされず、インタプリタ実行されるのみ。(1回実行の場合、コンパイル + 生成バイナリ実行」よりも、インタプリタ使った実行の方が早いため。)

繰り返し実行されて初めてコンパイルのメリットが活きてくる。
また、実行の特徴からコンパイル時の最適化を調整するので、しばらく実行して十分情報が得られてからコンパイルするほうが実行効率のよい結果が得られる。

コンパイラの種類

クライアントコンパイラとサーバーコンパイラがある。
どの程度コンパイルを積極的に行うかに違いがある。
クライアントのほうが積極的に行い、はやくパフォーマンスをあげようとする。
サーバーの方がより時間をおいて情報を得てからコンパイルを行い、最終的なパフォーマンスをあげようとする。

階層的コンパイラというものもある。
初期はクライアントコンパイラの動きをし、後半ある時点からサーバーコンパイラの挙動でコンパイルし直す。
主にはこれを使うのが良さげ。

コードキャッシュ

JVMがコードをコンパイルすると、コードキャッシュという領域に格納される。
サイズがいっぱいになるとそれ以上コードをコンパイルできなくなる

コンパイルの敷居値

コードがコンパイルされるまでのしきい値は調整することができる。

コンパイルの状況を見る

PrintCompilationフラグ設定を行うことで、実行時にどのようにコードがコンパイルされたかをログに出力するようにできる

Javaパフォーマンスを読んでる 2章

Javaパフォーマンスを読んでる。

自分なりに理解した内容をメモる。

2章: パフォーマンステストのアプローチ

パフォーマンスのベンチマーク計測方法

実アプリケーションでテストするのが最も信頼できる数値を得られる。 ただし、実施が簡単ではなかったりする。

対して、timestampなどを計測するコードを挟み込んでコードの特定部分のみの実行速度を測ったりする「マイクロベンチマーク」という手法もある。 こちらは簡単に実行できるが、測定値の信頼度は低かったりする。(測定したいコードそのものがコンパイル時の最適化によってごっそりなくなってたりする) その中間くらいの計測方法としてメゾベンチマークというのもある。 どこで計測を実行するかは目的やメリデメのバランス問題になるが、メゾベンチマークあたりで計測するのが有用なケースは多いっぽい。 それでも実アプリケーションではないので参考にならない可能性があることをわかったうえでそこでテストするって感じ。

スループット、バッチ、レスポンスタイム

バッチ処理でのパフォーマンス測定について

Javaの場合にはウォームアップ(コンパイルが十分に行われてパフォーマンスが最高に達するまでの時間)を考慮する必要がある。 バッチ処理の場合においては、ウォームアップ後にて測定を行うのが良さげ

スループットの計測

ある一定の時間内にどの程度の量の処理を行えるかということを表す。 クライアントはリクエストとリクエストの間に時間(シンクタイム)をおいてはならない。 クライアント側のスペックが問題になりやすいので気をつける。

■ レスポンスタイムの計測

クライアントがリクエストを送信してからレスポンスを受け取るまでの経過時間を測定する。 クライアントは実際のユーザーの動作を模して、レスポンスと次のリクエストの間に一定のシンクタイムを設ける。 たぶん、高負荷時の結果を測定したいわけではないということだと思う。

■ パーセンタイル値

計測結果のまとめ方に、平均値を取るやり方と、パーセンタイル値を取るやり方がある。 javaの場合にはGCにより外れ値がでやすいため、パーセンタイル値の方が合っていそう。

不安定性を理解する

計測できる値はテストのたびに異なる。これが優位な値なのかランダム性によるあたいなのか判断しないといけない。 統計的な手法によって判断する方法がある。(t検定など)

パフォーマンステストをいつやるか?

早期から自動テストに組み込んで置くと良い。 開発サイクルとのバランスを考慮する。