不安とワクワクの両方を感じる週

今週のタイムライン

エネルギーを与えた出来事(幸せになった・安心した)

  • 仲間の送別会をした(火曜日)
  • MaxSATの勉強をした(火曜日)
  • 経路探索アルゴリズムに興味が出た(木曜日)
  • Search Inside Yourselfを読み始めた(木曜日)
  • スクラムイベントの順番を変えてみた(木曜日)

エネルギーを奪った出来事(悲しくなった・不幸になったなど)

  • 低気圧がすごかった(日曜日)
  • 感情によって自分の行動が変わってしまっていること(水曜日)

戸惑った出来事や疑問に思った出来事

  • Doneにならない前提でプランニング時にアイテムを取ることはどうなんだろうか?(木曜日)

話したいこと

  1. 感情によって自分の行動が変わってしまっていること(水曜日)
  2. 経路探索アルゴリズムに興味が出た(木曜日)

不安になると自分はどうなるか

今週は仕事に対する不安がありながら過ごした週だったなぁと思います。なぜ不安になっていたのか。

その一つは尊敬していた仲間が今月末で転職しいなくなってしまうからです。私はその仲間をとても尊敬していたので、同じようになりたいと思い、一緒に作業する機会を多く作り、知識を吸収してきました。また、半年くらいかけて少し大きなタスクを消化しましたが、その際もその仲間にたくさん相談して、いろいろな問題を解決してきました。そのように頼ってきた部分があったのでいざいなくなるとなるとその仲間が担っていた部分の自分への責任が増え、また相談していた相手であった人もいなくなってしまうため、不安が募ってしまっていました。

また、今週は緊急で対応すべきことが発生しました。その部分に関して一番知識があったのは(転職してしまう仲間をのぞいて)私だったので、どのように解決すべきか、間に合うのかなどさまざまな不安が押し寄せてきました。

そこで今週改めて気づいたのは、私は不安になると「殻に閉じこもってしまうタイプ」なのだなぁ感じました。多分私は責任感が強い方で、どうにかして自分がやらないとと考えてしまうところがあるようです。(逆にいうと人を頼れていないんですが…)なので自分の作業に没頭したいや時間をかけてでもいいからどうにか解決したいという気持ちが強く現れ、思いやりにかけた発言や生活リズムを崩しての作業をしがちです。なんかこの部分は昔から成長していないなぁと感じました。

ブログを書くことで、こうやって自分の感情を振り返るのも面白いなぁと感じたという話でした。 (なんか締めがわからなくなりました笑)

経路探索アルゴリズムに興味が出た

今週は扱っているサービスの処理速度に問題があり、なんとか改善せねばという事態になってバタバタしていました。 いろいろ調査した結果、ある2点間の経路の距離を算出する処理が遅いことに原因がありました。

経路探索は「グラフ上でスタートからゴールまでの道を見つける」というグラフ探索問題として考えることができ、大学時代に習った幅優先探索深さ優先探索などが使うことで解くことができます。また、幅優先探索なんらかの規則に従って次に進むべき道を選ぶようにしたアルゴリズムを最良優先探索といい、このアルゴリズムが経路探索によく使われるアルゴリズムらしいです。

なんらかの規則によってアルゴリズムが変わってきます。

  • ダイクストラ法:スタートからある場所までのコストが最小となるように探索していく。
  • A*アルゴリズム:スタートからある場所までのコスト+推定値が最小となるように探索していく。
  • 均一コスト探索:スタートから通ったところまでのコストの総和が最小となるように探索していく。

A*アルゴリズムはスタートからゴールまでの距離を求める精度は高いのですが、実際にビジネス応用する際には速度の点で課題がありました。そこで他の機械学習アルゴリズムを使って精度は少し下げても良いが、速度をあげようという試みをしようとしています。その中の一つでXGBoostを使おうとしています。XGBoostはKaggleのコンペに挑戦するときに使ったアルゴリズムなのでこんなときに生きてくるとは!今週中盤まで不安がたくさんありましたが、週末になってワクワクが止まらない状況になっています。

最後に

今週は不安がたくさんありましたが、任されることって自分にしかない価値が少しは出てきたのかなと思って良い気分っちゃ良い気分ですね。パームレストを転職してしまう先輩からもらったので、その意思を引き継いでゴリゴリ頑張っていくぞ!

f:id:makky_emmanuel:20210327223401j:plain
もらったパームレスト

SATソルバーで数独を解く

今週のタイムライン

エネルギーを奪った出来事(悲しくなった・不幸になったなど)

  • わからないことをその場で質問できなかった(時間がなかったのもあったが)(水曜日)
  • レトロスペクティブ(チームでのふりかえり)が時間を書けている割に効果が出ていない感(木曜日)

エネルギーを与えた出来事(幸せになった・安心した)

  • キムチ作り(日曜日)
  • 先輩とペア作業をして学ぶことが多い(Unit test, Git, RxJava)
  • Think Clearlyを読み始めた(水曜日)
  • 大きなタスクを完了にできた(水曜日)
  • e2eによって問題の解決方法が誤っていることに気づけた(金曜日)
  • SATソルバーで数独を解けた(金曜日)

戸惑った出来事や疑問に思った出来事

特になし

話したいこと

  1. SATソルバーで数独を解けた(金曜日)

SATソルバーで数独を解く

最近SATについて理解する必要があり、勉強のために数独を解かせてみました。SATは充足可能性問題(Satisfiability problem)のことで、たくさんの論理式を与えて、それらの論理式がすべて真となるような変数を探すという問題です。

具体例を示す前に説明に必要な用語があるので説明します。

  • リテラル:真か偽を示す変数
  • 節(Clause):リテラルをORでつないだもの
  • 連言標準形(CNF):節をANDでつないだもの

具体的には以下のような問題があったとします。

以下の条件を満たすx, y, zを求めよ

  1. xまたはyが真である
  2. xが偽である又はzが真である
  3. yは偽である

この時x, y, zがリテラル、xまたはyが真であるが節、1,2,3の条件を全部で連言標準形のことを指しています。この問題をSATソルバーを使って解くとすると以下のようなコードで解くことができます。

from pysat.solver import Minisat22

x=1
y=2
z=3

solver = Minisat22()

clause1 = [x, y]    #  x or y   = xまたはyが真である
clause2 = [-x, z]   # !x or z   = xが偽である又はzが真である
clause3 = [-y]      # !y        = yは偽である

solver.add_clause(clause1)
solver.add_clause(clause2)
solver.add_clause(clause3)

solver.solve()
solver.get_model()
# -> [1, -2, 3]

最後に出てきた[1, -2, 3]はxが真、yが偽、zが真を表しています。 実際にこの答えで与えられた条件をすべて満たしています。

SATでは上記のように条件を節に置き換えることができれば問題を解くことができます。 この要領で数独も解くことができるらしかったので、実際にプログラムを書いて解いてみました。

9×9の数独の条件としては以下のようなものがあります。

  1. 各マスには1~9のいずれかが入る
  2. 各行に少なくとも1回以上1~9が入る
  3. 各列に少なくとも1回以上1~9が入る
  4. 各ブロック(3×3の区域)に少なくとも1回以上1~9が入る
  5. 各マスに異なる数字が同時に入らない
  6. 各行に同じ数字が入らない
  7. 各列に同じ数字が現れない
  8. 各ブロックに同じ数字が現れない
  9. すでに埋まっている値はそのままである

これらをすべて節として表現し、SATソルバーに与えてあげれば数独が解けるはず。 それでは以下のような問題を考えましょう。

-,-,-,-,-,-,-,7,-
1,-,5,-,3,6,4,-,9
-,7,4,9,-,-,5,-,-
-,-,-,-,-,5,8,-,-
-,1,-,3,-,-,-,-,5
7,-,-,-,-,8,1,-,-
6,4,-,-,-,-,-,-,7
-,3,-,6,2,-,-,8,4
-,-,-,5,9,-,-,-,3

まずは各マスに1~9が入るかどうかという変数が必要なので考えます。 9×9の数独で、各マスに1~9が入るので9×9×9個のリテラルが必要です。 e.g. 一番左上でのマスに1が入るかどうか、一番左上でのマスに2が入るかどうか...

具体的には各マスにユニークな数字を割り当ててあげました。

class LiteralGenerator:
    def __init__(self):
        self.idx = 0
    
    def next(self):
        self.idx += 1
        return self.idx

gen = LiteralGenerator()
net = []
for i in range(9):
    matrix = []
    for j in range(9):
        row = [gen.next() for k in range(9)]
        matrix.append(row)
    net.append(matrix)
# net[行][列][数値]

一番上の行の7はnet[0][7][6]で70ということになります。 (ここを理解するのに苦労しました。)

それではここから一つ一つの条件を考えていきます。

1. 各マスには1~9のいずれかが入る

例えば左上のマスに1~9のいずれかが入ることを表現したければ、

net[0][0][0] or net[0][0][1] or ... or net[0][0][8]

で表現できます。これを全マス分の節を作る必要があります。

cnf = CNF()

for row in range(9):
    for col in range(9):
        cnf.append([net[row][col][num] for num in range(9)])

2. 各行に少なくとも1回以上1~9が入る

例えば1行目に少なくとも1が1回以上入ることを表現したければ、

net[0][0][0] or net[0][1][0] or ... or net[0][8][0]

で表現できます。これを全行、全数字分の節を作る必要があります。

for num in range(9):
    for row in range(9):
        cnf.append([net[row][col][num] for col in range(9)])

3. 各列に少なくとも1回以上1~9が入る

例えば1列目に少なくとも1が1回以上入ることを表現したければ、

net[0][0][0] or net[1][0][0] or ... net[8][0][0]

で表現できます。これを全列、全数字分の節を作る必要があります。

for num in range(9):
    for col in range(9):
        cnf.append([net[row][j][num] for row in range(9)])        

4. 各ブロック(3×3の区域)に少なくとも1回以上1~9が入る

例えば左上のブロックに関して少なくとも1が1回以上入ることを表現したければ、

net[0][0][0] or ... or net[1][1][0] or net[2][2][0]

で表現できます。これを全ブロック、全数字分の節を作る必要があります。 (この条件は実装するのが結構迷った)

for num in range(9):
        for j in range(9):
            cnf.append([net[(j//3)*3+(k//3)][j%3*3+k%3][num] for k in range(9)])

# 行は0, 1, 2 × 3, 3, 4, 5 × 3, ...と変化する必要がある
# 列は0, 0, 0, 1, 1, 1, 2, 2, 2, ...と変化する必要がある

5. 各マスに異なる数字が同時に入らない

左上のマスに1と2が同時に入らないこと表現したければ、

-net[0][0][0] or -net[0][0][1]

で表現できます。ちょっと分かりづらいですが、net[0][0][0] and net[0][0][1]の否定を表したいのでド・モルガンの法則を用いてorになおすと上記のようになります。 これを全マス分の節を作る必要があります。

for row in range(9):
    for col in range(9):
        for num1 in range(9):
            for num2 in range(num1+1, 9):
                cnf.append([-net[row][col][num1], -net[row][col][num2])

6. 各行に同じ数字が入らない

1行目の一番左とその右のマスに1が複数回現れないことを表現したければ、

-net[0][0][0] or -net[0][1][0]

で表現できます。全行、全数字分の節を作る必要があります。

for num in range(9):
    for row in range(9):
        for col1 in range(9):
            for col2 in range(col1+1, 9):
                cnf.append([-net[row][col1][num], -net[row][col2][num])

7. 各列に同じ数字が現れない

1列目に一番上とその下のマスに1が複数回現れないことを表現したければ、

-net[0][0][0] or -net[1][0][0]

で表現できます。全列、全数字分の節を作る必要があります。

for num in range(9):
    for col in range(9):
        for row1 in range(9):
            for row2 in range(row1+1, 9):
                cnf.append([-net[row1][col][num], -net[row2][col][num])

8. 各ブロックに同じ数字が現れない

左上のブロックの左上とその右に1が複数回現れないことを表現したければ、

-net[0][0][0] or -net[0][1][0]

で表現できます。全ブロック、全数字分の節を作る必要があります。

for i in range(9):
    for j in range(9):
        for k in range(j+1, 9):
            row1 = (i//3)*3+j//3
            row2 = (i//3)*3+k//3
            col1 = i%3*3+j%3
            col2 = i%3*3+k%3
            cnf.append([-net[row1][col1][0], -net[row2][col2][0]])

9. すでに埋まっている値はそのままである

今回与えられた問題は以下のようなものなので、数字が入っている部分に関して節を作っていきます。

-,-,-,-,-,-,-,7,-
1,-,5,-,3,6,4,-,9
-,7,4,9,-,-,5,-,-
-,-,-,-,-,5,8,-,-
-,1,-,3,-,-,-,-,5
7,-,-,-,-,8,1,-,-
6,4,-,-,-,-,-,-,7
-,3,-,6,2,-,-,8,4
-,-,-,5,9,-,-,-,3

右上の7はnet[0][7][6]、1行2列目の1はnet[1][0][0]という感じで表現してきます。 ここの処理は詳しい処理は省略しちゃいます。

全部の節が揃った!

この数独を解くために作成した節はすべてで9426個でリテラルは最初に述べたとおり729個でした。実際に解いてみると、

solver = Minisat22()
solver.append_formula(cnf.clauses, no_return=False)
solver.solve()

ans = np.array(solver.get_model()).reshape(9, 9, 9)
ans = ans[ans > 0].reshape(9, 9)
ans = ans % 9
print(np.where(ans == 0, 9, ans))

->
array([[9, 6, 2, 4, 5, 1, 3, 7, 8],
       [1, 8, 5, 7, 3, 6, 4, 2, 9],
       [3, 7, 4, 9, 8, 2, 5, 6, 1],
       [4, 9, 6, 1, 7, 5, 8, 3, 2],
       [2, 1, 8, 3, 6, 9, 7, 4, 5],
       [7, 5, 3, 2, 4, 8, 1, 9, 6],
       [6, 4, 9, 8, 1, 3, 2, 5, 7],
       [5, 3, 1, 6, 2, 7, 9, 8, 4],
       [8, 2, 7, 5, 9, 4, 6, 1, 3]])

解けた!すごい!

最後に

学んだことをまとめようとするとついつい長くなっちゃいました。最近読んだ本とかの感想や先輩から学んだことも書きたかったけど、書くのが疲れちゃいました笑 週末じゃない時にも書いて投稿しようかなぁ。。。

全然関係ないけど、今週のキムチ作りの時に食べたユッケジャンクッパが美味しかった!

f:id:makky_emmanuel:20210320192709j:plain
ユッケジャンクッパ

自分をReadyな状態に

今週のタイムライン

エネルギーを奪った出来事(悲しくなった・不幸になったなど)

  • 頑張り続けることでお金はついてくる理論は本当に信じるべきか考えてしまった(日曜日)

エネルギーを与えた出来事(幸せになった・安心した)

  • 朝喫茶で勉強をすること(ほぼ毎日)
  • パン作り(日曜日)
  • 仕事での目標を立てた(月曜日)
  • Amazon Personalizeの勉強(火曜日)
  • 銀行を一つにまとめるための行動(火曜日)
  • 不動産屋巡り(火曜日)
  • アルゴリズムの勉強を進めた(水曜日)
  • 普通に褒められた(木曜日)
  • 今まで一緒に作業していなかった人とペア作業ができた(金曜日)
  • 大学の友人と会話(金曜日)

戸惑った出来事や疑問に思った出来事

  • その場でわからないことを解決するべきか、ちょっと自分で考えてから改めて質問をするべきか(水曜日)

話したいこと

  1. 仕事での目標を立てた
  2. Amazon Personalizeの勉強

自分をReadyな状態に

3月から新たなクォーターがはじまるということで、5月までの目標をたてました。

私は目標を立ている時に「SMARTの法則」にしたがって考えています。SMARTの法則は具体性(Specific)、測定できるか(Measurable)、行動的か(Action-oriented)、関連性(Relevant)、期限(Time-bound)の5つの要素からなる目標設定の方法です。

(ちょっと内容は変えていますが)私が立てた目標の一つはこちらです。 S:チームメンバーがスクラムのプロセスやルールを理解し、スクラムの考えに基づいて行動するようになること M:どれくらい各イベントがチームに浸透したかで達成度を判断 A:自分がファシリテーターをする時に各スクラムイベントの目的を確認する、...(たくさんあるため省略) R:チーム全体の目標を達成するためにこの目標を達成することが重要だと考えている T:5月末まで

個人的に一番大切にしているのは行動的か(Action-oriented)です。目標達成のためには、何らかの変化が必要だと思います。その変化は自分の行動によって起こす必要があります。そこで具体的な行動を考えることによって自らの力で変化を起こすきっかけを作ることができると思っています。そのため、目標を達成するための行動を具体的に考えることが重要だと思っています。

今週は、目標達成のために何を自分がすべきかを考えることができ、自分をReadyな状態*1にすることができたと思っています。

レコメンドエンジンをさくっと作る

知り合いのお手伝いの中で、ユーザにおすすめのコンテンツを推薦する部分を実装する機会がありまして、その際にAmazon Personalizeを使ってみたので、学んだ知識をまとめてみます。

事前知識

Amazon Personalizeを使う際にはいろいろな言葉が出てきますので先にまとめておきます。

用語 内容
データセットグループ データセット、ソリューション、キャンペーン、バッチジョブなどが含まれたもの。
インタラクション どのユーザがどのアイテムに対してアクション(見る、購入するなど)をしたかという情報のデータセット
ユーザ ユーザに関するメタデータのデータセット
アイテム ユーザがアクションを起こすアイテムのメタデータのデータセット
ソリューション 実際のレコメンデーションモデルを作るところ。
キャンペーン リアルタイムで推薦するために使用するもの。(ちょっと料金が高い)
バッチジョブ バッチで推薦するために使用するもの。

実際にやること

ここではAWSのコンソールの画面上での操作で説明します。

1. データセットグループの作成

コンソールにてAmazon Personalizeと検索して、Get startedのボタンを押すと、データセットグループを作成する画面に遷移する。遷移後は名前を指定するだけで作成完了。

2. 必要なデータをS3にアップロード

S3にバケットを作成して、必要なcsvデータをアップロードしておく。また、Amazon Personalizeからのアクセスを許可するため、アクセス許可タブのバケットポリシーに以下のように記述を追加。

{
    "Version": "2012-10-17",
    "Id": "PersonalizeS3BucketAccessPolicy",
    "Statement": [
        {
            "Sid": "PersonalizeS3BucketAccessPolicy",
            "Effect": "Allow",
            "Principal": {
                "Service": "personalize.amazonaws.com"
            },
            "Action": [
                "s3:GetObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::[指定したバケット名]",
                "arn:aws:s3:::[指定したバケット名]/*"
            ]
        }
    ]
}

3. データセット・データセットインポートジョブの作成

データセットにはインタラクション、ユーザ、アイテムの3種類があり、それぞれインポートできるボタンがある。インタラクションは必須だが、それ以外は任意のデータとなっています。

データセット作成の際にはスキーマ(どんなデータかの定義)を作成し、指定する必要があります。スキーマはその場で作成することもできますし、以前作成したスキーマを使用することもできます。Amazon PersonalizeではAvroスキーマという形式で書く必要があります。 以下がインタラクションのスキーマの例です。

{
    "type": "record",
    "name": "Interactions",
    "namespace": "com.amazonaws.personalize.schema",
    "fields": [
        {
            "name": "USER_ID",
            "type": "string"
        },
        {
            "name": "ITEM_ID",
            "type": "string"
        },
        {
            "name": "TIMESTAMP",
            "type": "long"
        }
    ],
    "version": "1.0"
}

スキーマの指定を行うと、データセットインポートジョブの作成画面に移ります。ここではどのデータを用いるかを指定します。 手順2で保存したデータのパスを指定してあげます。

s3://[バケット名]/hoge.csv

これでデータセットとデータセットインポートジョブの作成が完了します。 実際に作成するまでに少し時間がかかります。

ソリューションの作成と行きたいところだったが…

インタラクションの必要データ数が1000データ以上ということでデータセットの作成に失敗してしまいました。

ソリューションを作成するためにはデータセットには以下の条件が必要らしいです。

  • インタラクションは1000データ以上
  • ユーザは2回以上インタラクションに存在するユーザが25ユーザ以上

その他の細かい制約についてはこちらに記載されています。データ数をどうにかあつめて学習まで進めたい気持ちです。

他にもデータセットを作るまでの工程をPythonのboto3とdiscord.pyを使って自動化などもしたが、体力が尽きたので書くのは諦めました…

最後に

先週の日曜日は人生で初めてパン作りをしました。以下の写真は作ってもらった食パンですが、絶品でした。パン作りの機会に誘っていただいたことに感謝です!

f:id:makky_emmanuel:20210313202345j:plain
食パン

*1:スクラムにおいて使う言葉で、実施する上でわからないことや妨げになるようなものがないこと。詳しくはこちらの記事が良さげです。

仲間について考える

今週のタイムライン

エネルギーを奪った出来事(悲しくなった・不幸になったなど)

  • PCが重くなって作業のやる気が下がる(月曜日)
  • ミーティングが重なり作業時間をなかなか確保できない(木曜日)
  • 飲みすぎて二日酔い(土曜日)

エネルギーを与えた出来事(幸せになった・安心した)

  • 3月の目標を立てた(日曜日)
  • チームメンバーが夢を叶えるため次のステージへ(水曜日)
  • 朝のカフェ作業(木曜日)
  • 会社のキックオフでのみんなの様子がよさそうだった (金曜日)

戸惑った出来事や疑問に思った出来事

  • どのようにフィードバックしあえるとよい効果がうまれるだろうか
  • オンラインで緊張を和らげる方法って何があるだろうか

話したいこと

  1. チームメンバーが夢を叶えるため次のステージへ
  2. どのようにフィードバックしあえるとよい効果がうまれるだろうか

チームメンバーが夢を叶えるため次のステージへ

チームメンバーの1人が夢を叶えるために転職をするという話がありました。チームメンバーの中でも特に尊敬をしていた仲間だったので、夢を叶えるという嬉しさの反面、寂しさがこみ上げてきました。2人きりで話す機会を作れ、今までのことやこれからのこと、相手や私についての印象など様々なことが話せてとてもしあわせな気持ちになりました。

一方でチームとしては重要なメンバーの1人が抜けるということで緊急ミーティングが開かれました。昨年くらいからこのような時のためにトラックナンバー*1を増やすことを行ってきました。すぐに今月までにやらないといけないこと、誰が行動していくか、などが決定され、「なんかいいなぁ」と感じるミーティングでした。こんな風に、チームメンバーが新たなことに挑戦する時に笑顔で喜んで応援し会える状態を作り出すのって難しいけど大切だなぁ。

今週は十分に悲しんだり嘆いたりしたので、来週からは気持ちよく仲間を送り出せるように頑張るぞ!

フィードバックってどうすればいいの?

今週は12月に立てた目標に関して、チームや関わるメンバーとフィードバックし合う機会がありました。私の会社はフラットな組織や自律型組織を目指しているため、上司は部下にフィードバックを与えるというような形ではありません。私も経験年数が長い仲間に対してフィードバックもしますし、逆に自分より経験年数が短い仲間からもフィードバックをもらいます。

そんな中、何を伝えることやどう受け取ろうとすることが良いフィードバックとなるのかが悩ましいなぁと感じました。 適当に動画を調べてみてみました。

www.youtube.com

この動画ではフィードバックを受け取る側の意識が大切ということを行っていました。フィードバックは「間違っているところ」「改善できるところ」「気づかないところ」など自分を成長させるチャンスである。もらったフィードバックを論理的に理解し、次の計画に取り入れることが重要であると言っていました。更には受け取るのが上手になると人から好かれるようになるよとも言っていました。

受け取る側の気持ちはわかったが、フィードバックをする側についてどういうことをどういう風に伝えればよいかはわからんなぁ

最後に

サンマルクが7時から開いていることに気づいて朝カフェ作業をしてみました。高校生のときによく勉強で使っていたので懐かしみがあります。

f:id:makky_emmanuel:20210306105657j:plain
朝のサンマルク

*1:トラックナンバー:ある日突然トラックに轢かれてもプロジェクトが停止しないメンバーの数

私の読書術

今週のタイムライン

エネルギーを奪った出来事(悲しくなった・不幸になったなど)

  • 資料がうまくまとまらない

エネルギーを与えた出来事(幸せになった・安心した)

  • 湘南蔦屋書店に行って次に読む本を買った
  • Discord botの開発に関して社内LT会で発表した
  • ハングリータイガーに初めて行った

戸惑った出来事や疑問に思った出来事

  • 発言に反応してしまいそうになるときにその気持ちをどこに消化させるのか

話したいこと

  1. 湘南蔦屋書店に行って次に読む本を買った
  2. Discord botの開発に関して社内LT会で発表した

私の読書術

最近、「最高の体調」を読了しましたが、思ったより早く読めたし、良いと感じたのでそのやり方を共有しようかなぁと思います。

私はほぼ毎日21時から1時間で読書会を行っています。 具体的な進め方は、

  • 最初の30分はちょうどよい区切れで交代しながら、声に出しながら読む
  • 後半の30分は読んだところに関して感想を言い合う

だけです。メリットは、何も準備をしなくて良いことや他の人と感想を共有することで、自分が着目していなかった部分にも意識を向けることができることだと感じています。また、1回あたり30ページほど読めるというペースもわかってくるので、あとどれくらいで読み終わるのかとかも予測しやすいというもの良い点かもしれません。個人的に思うのが、声に出して読むのは高校生以来くらいでなんか新鮮でとても良いです(新人研修のときに声に出して読んだか笑)。

ぜひ皆さんもお試しを!

スクラムをDiscord botに手伝ってもらった

私のプロジェクトのチームはスクラムスクラムマスターはいない…)で開発を行っています。そんな中、プロダクトバックログとスプリントバックログの情報の一致やベロシティの計測などの面で煩わしさを感じていました。具体的にはプロダクトバックログGoogle Spreadsheet、実際の詳細が書いてあるアイテムやスプリントバックログはBacklog(nu-lab)と別々のサービスで管理されており、アイテムが完全に同期できていないという点です。そこで、discord.pyを使ってどうにかできないかなぁと思っていました。

実際にやったこととしては以下の3点です。

  1. ベロシティの計算
  2. ベロシティの可視化
  3. プロダクトバックログGoogle Spreadsheet)の情報(ストーリーポイント)をアイテム(Backlog)に反映させる

実装してみて良かった点やうーんと感じた点は以下のスライドにまとめてあります。

開発していて面白いなぁと思いつつ、こういうタスク指向型のボットにはどんな機能があると便利なんだろうと対話システム勉強会に参加したときのことを思い出していました。

最後に

今週はなんだかもやもやする週だったなぁ感じています。 まぁそういうときもあるか!先週のハングリータイガー美味しかったなぁ(さわやかのほうが好みだけど)

f:id:makky_emmanuel:20210226231838j:plain
初めてのハングリータイガー

様々な知識を得る機会

今週のタイムライン

エネルギーを奪った出来事(悲しくなった・不幸になったなど)

  • 特になし!

エネルギーを与えた出来事(幸せになった・安心した)

  • ドリームマネジメントのキャリアのセッションを実施(月曜日)
  • Retrospective ANTIPATTERNS読書会(月曜日)
  • 久々にジムに行った(月曜日)
  • 最高の体調を完読(火曜日)
  • 対話システム勉強会に参加(木曜日)
  • 兄の誕生日(金曜日)

戸惑った出来事や疑問に思った出来事

  • リモートワークにおいて全員が集まる機会を作るということ
  • 議論の時間と発散のバランス

話したいこと

  1. 対話システム勉強会に参加
  2. ドリームマネジメントのキャリアのセッションを実施
  3. 最高の体調を完読

今後は人間らしさのフィルターが重要となるのか

2月18日にオンラインで対話システム勉強会 雑談AIもここまで来た! -最新の対話システムと未来-に参加してきました。 内容としては対話システムライブコンペティションというイベントについてとそのイベントで最優秀賞を受賞したチームの実装内容と「これからの対話システム」というタイトルでのパネルディスカッションでした。

そもそも対話システムにはタスク指向型と非タスク指向型があります。タスク指向型はよくある飲食店のレコメンドや機械翻訳などのようになんらかの目的がある対話システムのことを指します。一方で非タスク指向型はLINEなどで会話できるりんなのように雑談ができる対話システムのことを指します。今回の勉強会では後者の非タスク指向型の対話システムについて話していました。

ライブコンペティションオープントラックの最優秀賞のチームの実装内容は現在のstate-of-the-art(以下、SOTA)であるBlenderBotを日本語で学習させたものでした。 2017年に提案されたTransformerが機械学習界に大激震を与えましたが、対話システムの分野ではルールベールの手法もNNの手法と同等の性能を出していたそうです。ですが、2020年に提案されたGPT-3やT5によって対話システム界にもその波がきて、一気に雰囲気を変えたらしいです。BlenderBotはそのTransformerの考え方を用いたものらしく、それまでのSOTAであったMeenaを大きく上回る性能だったとか。 実際の対話内容を見ても本当に自然です。(こちらからコンペでの対話内容を確認できます。)

また、パネルディスカッションでは雑談AIの今後の開発について話していました。現在の対話システムの文章生成はある程度はできてあがっている気がするとのこと。これからの開発では生成された文の候補のうちどの分を選ぶのかという部分の開発がなされていくだろうと話していました。イメージとしては以下の図の赤枠の部分です。

f:id:makky_emmanuel:20210219224734p:plain
イメージ図

確かに実際の会話においてもいろんな会話パターンが思いついた中でどれを話すか選択する部分にその人らしさや倫理観などが含まれて来そうだなぁという感覚があるのでしっくり来ました。 どんな情報で学習するかだけでない部分に重要な部分がありそうな気がしますが、どうなんだろうか…

キャリアについて考える

私は会社においてドリームマネジメントプログラムファシリテーターをしており、月に1度夢を叶えることを支援するための活動をしています。 詳しいとこが知りたい方はザ・ドリーム・マネージャーを読んでみてください。

今回は「キャリア」についてということで自分がなりたい姿を思い描くようなワークを行いました。 私は資料などを準備する際に、実際に同じワークを行い、シミュレーションをしています。そこで、私もどんな働き方や生き方をしていきたいだろうかと改めて考える機会を得ることができました。 実際に行ったワークは以下のようなものです。

  1. キャリア面での夢を1~3個決める
  2. そのうち1つを選択し、達成したい期間を選ぶ(1年以内 or 1~5年 or 5年以降)
  3. 選択した夢を他の期間に置き換えた場合に、どのような夢になるかを考える
  4. パートナーを考えたり、SMARTの法則に基づき具体化する

手順2で私が設定したのは、5年以降に達成したい夢で物質・環境・時間に依存せずに働きたいとしました。

内容
具体的   場所や時間が異なっていても協力でき、物質(お金など)に困らない状態で「システムで人々をしあわせにする」が実現できている
測定可能  (うまく考えられなかった)
行動的 さまざまな文化に触れる、コミュニケーションを大切にする、勉強への向上心をおこならない
妥当性 (うまく考えられなかった)
期限 35歳くらいまで
パートナー 今の会社の仲間、近くで関わりを持てている他の会社の方々

また、手順3では以下のような夢を考えました。

1〜5年で達成したい夢資産所得が少しでもある状態にする。 これは経済的に自由となるための第一歩となるような気がしたのでおきました。

内容
具体的 今働いている会社の給与以外の収入ができること
測定可能 労働所得の5%くらいの資産所得がある状態
行動的 ブログを続ける、毎月株式投資をする
妥当性 ブログを続けることでいずれは事業所得となったりするかなぁ、株式投資によって配当などは入るなぁ
期限 1~5年で達成したい
パートナー 大学の友達(株式投資を積極的に行っている人がいる)、はてなブログなど

1年以内で達成したい夢はマインドフルネスな状態をいつでも起動できるようになる。 これは場所や環境に依存せず、いつでも集中できるようにするためにおきました。

内容
具体的 50分作業+10分休憩のサイクルで集中力が維持ができるようになる
測定可能 その日にやりたいことが達成できているかどうか
行動的 慣れるまではタイマーで測る、その日にやりたいことを3つを書き出す
妥当性 やりたいことが達成できているということはそのことに集中できているということ
期限 1年以内
パートナー タイマーアプリ、夢リスト(やりたいことがたくさん書いてある)

5年後にこの夢が達成できるように行動するのみ!

文明病を治す鍵は自然に触れること

最高の体調を完読しました。

ざっと要約すると、

人類は狩猟採集民の時代の方が長いのにもかかわらず、現在の生活は全く異なった暮らし方をしているために不安やストレスなどの文明病と呼ばれる病気にかかってしまっている状況である。
進化論に基づいた行動をすることで文明病から脱却することができる。

と言ったことが書かれていました。これらのことを語る際に実際に行った実験などが書かれていたり、実践方法などが書かれていてとても納得の本でした。

特に面白かったのが、自然と触れ合うことがストレスや体調を整える最強の方法であるということです。 具体的には研究結果によってマッサージよりも癒し効果が高いという結果が得られているらしいです。さらには実際の自然ではなく偽物の自然(画面に映った自然の写真や自然の音だけ)でもその効果が得られるということです。さらには、公園などにいくことで大気中に含まれる細菌が腸内環境をよくしてくれるというのだからすごいなぁと思いました。今後は積極的に散歩しようという気になりました。

その他にも時間感覚や遊びについてなど様々な観点から狩猟採集社会の時代と現在を比較し、良い効果が得られるような研究について紹介されており面白い本でした!(書くのが面倒になりました笑)

最後に

今週はいろんなことが盛り沢山でたくさん考え、たくさん学んだ楽しい週となりました。 写真は水曜日のランチに食べたパリヤのお弁当です。

f:id:makky_emmanuel:20210219223203j:plain
パリヤのお弁当

開発にワクワク

今週のタイムライン

エネルギーを奪った出来事(悲しくなった・不幸になったなど)

  • 人との会話が少なかった(月曜日)
  • 集中力がなかった(月曜日)
  • 楽天モバイルのSIMとXiaomi mi9の相性が悪かった(水曜日)

エネルギーを与えた出来事(幸せになった・安心した)

  • 久々にAPI実装の担当になった(月曜日)
  • チームメンバーと話せる機会が多かった(火曜日)
  • Discord botの作成を始めた(木曜日)
  • 焼肉食べた(日曜日)

戸惑った出来事や疑問に思った出来事

  • スクラムにおいてチームメンバーが増えそう(火曜日)

話したいこと

1.スクラムにおいてチームメンバーが増えそうなこと 2.久々にAPI実装の担当になった

開発を早くするためにスクラムでチームメンバーが増える

私はもう少しで3年目のエンジニアなのですが、スクラム(完全なものではない)で開発を進めていて、最低限のドキュメントしかない状況で、日々チームで認識を合わせながら開発しています。

開発力を強化するという目的で、1〜2人メンバーが増えることになりそうです。現在のチームは4人+4人の8人体制です。現在の開発力を維持しつつ、数カ月先に開発力を上げるためにどうしたら良いだろう。体制としては様々なパターンがあります。

  1. 5人+5人: それぞれのチームに一人ずつ追加するパターン
  2. 3人+3人+4人: それぞれのチームから一人ずつ出して、3チーム目を作るパターン
  3. 4人+4人+2人パターン: チームはそのまま維持し、3チーム目を作るパターン

事前の話し合いでパターン2が一番良いのではないかと思いながらチームでの議論に向かいました。

一番人気がなかったのがパターン4でした。理由は日々の認識合わせによって培ってきた品質の認識やコードの書き方などを新しいチームに伝えづらく、技術的負債が増えてしまい、逆に開発スピードが落ちる可能性があったためです。

次にパターン1とパターン2を比較し始めました。

パターン1

  • pros : 現在のチームを維持できる。計画する際の合計時間が増える。
  • cons : チーム内での意思決定が遅くなりそう。

パターン2

  • pros : チーム数が増える。小回りがききそう。
  • cons : チーム全体での意思決定が遅くなりそう。

結果としてはパターン2が選ばれました。理由は チーム内での意思決定が遅くなりそう です。私達のチームではプルリクエストを承認する方法としてチーム内全員のOKが必要です。5人チームになった場合、承認をもらう人数が増えれば遅くなりますし、承認する人数を減らした場合には最初に誰がレビューをするのかで責任が変わってきそうな気がします。一方で3人チームとなった場合は承認の人数が減ることで承認スピードが上がることが期待できつつ、全員がレビューをするためチームの責任であることが維持しやすいのかなぁと思います。まずは決まって良かったです。次は誰が新たなチームに行くかの議論がありそうですね。

API実装に悩む

画像のアップロード機能の送信側の設計をしており、既存のコードを修正するのではなく、新たにパッケージを切って書いていくことになりました。画像はS3に保存し、画像の情報はデータベースに保存するような形です。3層アーキテクチャーに習って以下のように切っています。

root
|- application
|   |- HogeService
|- domain
|   |- Hoge
|- infrastructure 
    |- controller 
    |   |- HogeController 
    |- repository
        |- HogeRepository

最近テストの大切さを知り、プロダクションコードを書く前にテストを書きたいのですが進め方がわからない… ちょっと相談したところ、まずはインタフェースだけ決めちゃえばかけるかもいうことで以下の事を実施

  • それぞれのクラスにインタフェースを切る
  • それぞれのクラスに必要そうなフィールドを追加

これでなんとなく書けそう。かもというところまで行けました!早くテストを書いて、実装を進めたいところです!

最後に

スキーへ向かうバスの中でこの記事を書いています。一年以上ぶりのスキーなので楽しみすぎるぞ!

f:id:makky_emmanuel:20210213220828j:plain
bus