技術をかじる猫

適当に気になった技術や言語、思ったこと考えた事など。

カンバンを思い出しながらやってみた

単位はデイリーで。

f:id:white-azalea:20190220210117p:plain

個人でやる分にはいつ導入してもいい。
ということでカジュアルにやってみた。

カンバンのエリア

横方向に4つ、縦方向に二つで区切ってみた。
内容は、横方向に

  1. Backlog
  2. Todo
  3. Doing
  4. Done

のシンプル構成。
むしろシンプルで無いと無駄に時間がかかる。

上下方向は、以下の区切り。

  • 事前に計画されたタスク
  • 突発的に入ったタスク

突発はメールでも電話でも、相談でも打ち合わせでもいい。
30 分を超えたら付箋を貼るようにした。

出社直後

だいたいこんなことをやった。
今日は初回だったので、トータル 1h 程度かかった。

  1. 優先度をみながら、その日にやっておくタスクをBacklog から Todo に引っ張る
  2. 最大2時間の単位のタスクに区切る(ここで一気に枚数が増える)
  3. 朝会で、他にどんなタスクがあるかを確認する
  4. その内容を踏まえて今日の範囲を決める

午前の作業開始

ひたすらタスクの消化に専念。

  1. Todo から Doing に引っ張っていき、処理する。
  2. 決めなきゃいけないところや、時間がかかりそうな部分が見つかれば、迷わず付箋にして Todo に突っ込む。
    今日やるかどうかすらもまずは考えない。そして先に進む。
  3. どうしても優先度の高い割り込みが入るようなら、Doing の作業で進んで無いものを思い切って取り消す。
    (中途半端に残ってると無駄に気になる)

飯を食いながら棚卸し。
ここで、午前中に増えた付箋を今日やるかどうか、午後一でどれを相談すべきか決める。

やってて思ったのは、この時点で消化枚数が少ないと、そのヴェロシティ(進捗速度)が無駄に気になる。
気にするだけ無駄になると割り切って、進捗の悪いタスクを放置して、軽いやつから片付ける方針に変更。

午後一

昼に決めた相談物を、早速相談して決めてしまう。
決まらなければバックログに突っ込んで決まるまで放置することを決める。
(他の人のタスクにかぶる場合の方針。時間をかければ決まるというなら、決めるタスクを Backlog に放り込む)

いくつか不要なタスクとわかったので、右下の隅に重ねて放り込んだ。

午後

午前の進捗が微妙だったので、軽いものからさっさと終わらせる。
途中 30 分ほど時間がかかる微妙な点(Problem)が見つかったので、左下の隅っこに付箋を放り込んだ。

あとは午前と同様に付箋のタスクを消化して、Done に放り込む。

定時

今回は集中しすぎて定時に開始してしまったが、定時ちょっと前くらいにスプリントの振り返りを行う。
とりあえず Todo/Doing が空になってるのが理想。
空になってなかったら、何に時間がかかってるかを思い返して try とする。

今回は、他拠点との意思疎通の問題でロスがみられたので、明日以降特定タスクの前に関連箇所と近くの作業者のタスクを確認してからやろう…みたいな振り返りになった。
課題として意思疎通情報共有、空気感、温度感…複数拠点あるあるだよなーと思いつつ(汗

初日目感想

もともとスクラムはやってたので、スムーズに進んだ…というかトラッカーを(主に政治的問題で)思う様に利用できず、Excel ガンチャ管理の現場だったので、やってみる前とは雲泥の差だ。
昔は一人でやってた筈なのになんでやらなくなったのかと本気で思った。

いくつか再確認

  • デイリーでやるならタスク粒度は長くて 3 時間で切らないと、ダレる。 2 時間以上かかったら、詰まってる部分を付箋切って Todo に突っ込む事を考える。
  • タスクの消化量は精神的にクルので、(優先度が多少低くても)楽なタスクからやるのも十分あり
  • 人の脳みそは複数を同時に処理する様にはできてない。それもあるので、同時に Doing できるタスクは二つまでに絞る。 (割り込みがあっても最大 3 が限界。あとは待ってもらう)
  • 物理カンバンまホント偉大。
    • 画面切り替えなくていい
    • フォーム画面なんていちいち呼び出さなくても即付箋が書ける (もっと言うと、デイリーで回す粒度なら、既に細かいので詳細まで書く必要も無い)

メモ: 今週末に社内勉強会

今回ハンズオンなので、スムーズに行くように資料作る。

なお内容は、CI 環境構築。
Jenkins 前提にはするけど、もしかしたら CircleCI に鞍替えするかも?

更にメモ:明日LineBOT メイクのハンズオン。

x-hack.connpass.com

何ならCIに連携したいというノリ。

一人デイリースプリント初日目。 わかった事:カンバンは常に表示してる状態を保つか、物理的にあったほうがやはり迷わない。

KPT内容は、常に手元にあった方がいい。 タスク傾向の分析も兼ねて、30分以上作業したものは、付箋にしてみたが、コレチケットだと面倒かもしれない。 ipad 音声入力でカジュアルにできるカンバンあったら受けそう(主に私に

後は目の前に3個以上doingにしちゃダメだ。 迷うコストや頭を切り替えるコストは思ったよりデカい。

あと、面倒な物から片付けたいって心理は確かにあるのだけど、チケットが消化されないのを見ると心理的負荷になる。 そこに来ると、優先度が多少低くても数消費して、優先度の高い重いヤツは腰を落ち着けてやった方が効率が良かった。

KPTが出てこないケース

カイゼン・ジャーニー読んでたら、ふと思い出したので。

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

Keep Problem Try の頭文字で、スプリントの最後に、「こう言う事良かったね続けようか」「こういう所問題だったよね」「なら問題解決にこう言う事やってみようか」を行うのが agile では定例。
これをチームによって期間はまちまちだけど、こちらは 2 週間に1回やった。

で、問題があったプロジェクトは、これが全く回らなかった。
どういうことかというと、problem がその場限りの問題解決になってしまったのだ。

そもそもイテレーションの運用内部「このプラクティス無駄だよね、こうしてみない?」とかそもそもプロジェクト運用に関わる問題が出てきてくれる方が望ましい。
でないと取り組みが改しないのだ。

これが 2-4 イテレーション位なら疑問にお思わないのだけど、結局最終スプリントでもそんなだった。
問題がなかった?というのは考えにくい、大なり小なり問題はあったハズだ。

何が問題だったのだろう?そう考えた

心理安全が確保されてない?

これはあったかもしれない。
そのプロジェクトは遠隔地 2 拠点での開発だった。
当然情報の粒度や格差の問題は大なり小なり出る。

何より、相手の姿が直接的に見えない。
もっと言うと気づいていないだけで、各拠点が排他的な村になっていた可能性はある。

Agile のプラクティスには大体鉄則がある。
同じ場所でやることアジャイル・サムライにはあり、実にその通りと実感する。

そうでなくとも、そうした事を理解したキーマンを両拠点に常駐させておくべきだったのかもしれない。

そもそもプロセスに無頓着

元々 SIer のニアショア拠点。言われた事への作業に慣れ切ってる。
果たしてその状況で開発プロセス自体が改善できただろうか?

そりゃ温度感が違うのにプロセスを見直す発想を求めるのは酷というものだ

後からなら何とでも言えるケースだが、こうした拠点でアジャイルするなら、有識者を常駐させ、好きに言える土壌を作らなければいかなかったのかもしれない。

改善の糸口が分からない

problem を出すときのコツは、自分がやってて詰まらないと思った作業、ド嵌りした事象だ。
ド嵌り事象は情報共有で済む場合もあれば、プロセスを変える事でそのポイントをそもそも回避できる場合がある。

何にしても言ってみる事が重要だったりする。

作業中とは面白いもので、上記のような事があっても喉元過ぎると熱さを忘れるものだ。
良くアプリが思ったように動かなくてイライラしているユーザも、どうすれば良いか分かった瞬間から問題に思わなくなる事象と一緒だ。
(いやそれユーザビリティが悪いんだからね?(汗)

SI 現場でそういうシーンは結構ある。

  • テストを手動で回してテストデータでひーひー言う
    テストそのものを自動化する運用とするか、テストデータ生成を自動化する
  • リリース作業で、手続きにチェックを入れながら…
    いや CI で自動化できる
  • 仕様書を探してディレクトリを右往左往
    検索エンジン入れましょう、運用的にドキュメントの配置をルール化しよう…etc

みたいなことが往々にしてある。
これらを解決可能だと思ってないか、過小評価して(だから改善するまでもないと思って)いるケースが多い。

どうすればわかるのだろう?
個々人が、30分以上同じ作業をしたらとりあえず紙に書いてみるという、要するに時間の使い方の見える化だろうと思う。

最急降下法を使用して、近似線を引いてみる

やっていることは前回とほぼ同様。
ただしこちらでは偏微分を使って複数のパラメータを計算している。

white-azalea.hatenablog.jp

目標とすべき線が

def actual(x):
    """目指すべき線"""
    return 0.6 * x + 4

で、学習データセットを以下の様に設定してみる。

data_set = [(x, actual(x) + random.randint(-5, 5)) for x in range(-100, 100)]

緑が学習データで、青線が理想の線。
ばらけ方は悪いけど、この辺がテストデータ

f:id:white-azalea:20190218204818p:plain

そして求めるべきパラメータは、前後変化するので引数で受け取る様にして外だしに。

# weight のパラメータを使って actual 同様の計算をする
def func(x, weight):
    return weight[0] * x + weight[1]

あとのやることは対して変わらない。
微分関数を用意。

def numerical_gradient(f, weight):
    """偏微分式にアップデート"""
    h = 1e-4
    grad = []

    for i in range(0, len(weight)):
        cpy1 = weight[:]
        cpy2 = weight[:]
        cpy1[i] = cpy1[i] + h
        cpy2[i] = cpy2[i] - h
        fhx1 = f(cpy1)
        fhx2 = f(cpy2)
        grad.append((fhx1 - fhx2) / (2 * h))
    return grad

ただし、今回は重み付けパラメータの値を個別に微分し、微分値を応答に含む様にしている。
偏微分て要するに他のパラメータを全て定数とみなして微分することなので、やっている論理は一緒。

損失関数を用意して、その損失関数に不足するパラメータを設定する。

def loss(func, data, actual, weight):
    calc = func(data, weight)
    return (actual - calc)**2

今回は 0 に近づけるのではなくて、微妙にブレた各数字データに近づける。

lern = 0.00001
weight = [-2, 3]  # 最初の重みは適当
for n in range(1000):
    for data in data_set:
        x, y = data
        loss_func = lambda w: loss(func, x, y, w)
        grads = numerical_gradient(loss_func, weight)
        weight = [weight[0] - grads[0] * lern, weight[1] - grads[1] * lern]

初期の weight は明らかに伸びる向きが間違ってる。
これは補正がかかることを確認するためにわざと行なっている。

その上で赤線プロットするとこのようになる。
(黄色は学習前で、赤は学習後。きちんと学習しているようである)

f:id:white-azalea:20190218205933p:plain

ここでもう一声。
損失関数と呼んではいるが、これは目的関数とも言えるので、その原義(下記)に従って、損失計算を作り直してみる。

f:id:white-azalea:20190218220922p:plain

※ y(i) はデータはデータの y 軸の値。fθは今回で言う所の func(?, weight)の意味で、θ=weight 値。

lern = 0.000002
weight = [-2, 3]  # 最初の重みは適当
for n in range(5000):
    def error(weight):
        all_err = 0.0
        for data in data_set:
            x, actual_y = data
            all_err += (actual_y - func(x, weight))**2
        return all_err / 2.0
    grads = numerical_gradient(error, weight)
    weight = [weight[0] - grads[0] * lern, weight[1] - grads[1] * lern]

f:id:white-azalea:20190218221522p:plain

ループなどは一部弄ったが、ループは明らかに少ない回数でいい精度の数字が出てきた。

Trailheadが地味に楽しい件

SalesForce 社のオンライン学習ぷらっとフォーム。

trailhead.salesforce.com

ここの内容が多岐に渡ってて、だらだらと学習を続けるのには面白い点。
そして、積み本が溜まっていく(汗

今月はとある活動もあってあまり更新できてなかったけど、そろそろこっちの更新もしてこうかと思う。
とりあえず以下の本も興味本位で買ったので、積まずに読まねば

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

カイゼン・ジャーニー たった1人からはじめて、「越境」するチームをつくるまで

この辺は読み物系なので、実践系と違って電車で読める(汗
プログランムとかアルゴリズムの類は見たら書きたくなるので、PC の前以外でなかなか読まないのが難点(そしてそっちの方が好きだという問題)

読み終わったら感想とか書きたい。

微分を使ってパラメータを求める(最急降下法or勾配降下法)

お題は、ある不明関数 f にっついて、t という値にもっとも近くパラメータを見つける。
ということで、ちょこちょことやってみた。

計算したい関数はこれで、もっとも 0 に近くなる x を求めたい。
このくらいならふつーに計算すればできそうなものだが、あえてプログラム的に。

def func(x: float) -> float:
    """計算対象の関数

    Arguments:
        x {float} -- 引数

    Returns:
        float -- 計算結果
    """

    return 2 * (x ** 2) + 2 * x + 1

ある値 x に対する誤差の計算を以下の様にかける。

def loss(f: func, x: float, t: float) -> float:
    """損失関数

    Arguments:
        f {func} -- 値を求める関数
        x {float} -- 確認する x 値
        t {float} -- 正しい値

    Returns:
        float -- 誤差値
    """
    y = f(x)
    return (t - y)**2

この時、関数は前述の func で、求めたい t は 0.0 固定でいいので

loss_func = lambda x: loss(func, x, 0.0)

こんな感じにしておく。
ここで、この勾配を求めるのに、微分をしてみる。

微分は、グラフ上の接線、ないしは接点であるとも言え、その定義は極限で 0 に収束させる時の値だったはず。
なら処理的にはこんな風に書けるはず。

def numerical_gradient(f: func, x_value: float):
    h = 1e-4
    grad = 0.0

    x1 = x_value + h
    x2 = x_value - h

    fhx1 = f(x1)
    fhx2 = f(x2)

    grad = (fhx1 - fhx2) / (2*h)
    return grad

その上で、800 回ほど誤差計算とパラメータの移動をさせてみた

loop = 800
lern = 0.001
current_x = 3.5  # 開始値
log = []


for n in range(loop):
    # 微分して
    gradient = numerical_gradient(loss_func, current_x)
    # 誤差を元にあるべき x に近づける
    current_x += gradient * lern
    log.append(current_x)

学習係数をかなり小さくしてやらないと、プラスとマイナスでやたらと振れた挙句オーバーフローを起こすので注意

f:id:white-azalea:20190206172104p:plain

プラスからでもマイナスからでも、最終的に x=-0.5 に収束する。
ニューラルネットワークの学習計算から論理を切り出してみたのだが、なんとなく良さそう。