u16suzuの blog

日々学んだことのメモブログです。

Reactのメモ

準備

sudo npm install -g react-tools
# jsファイルをwatch して自動ビルドをさせる
jsx --watch src/ build/

html

<!DOCTYPE html>
<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <script src="https://fb.me/react-15.1.0.js"></script>
    <script src="https://fb.me/react-dom-15.1.0.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.23/browser.min.js"></script>
  </head>
  <body>
    関数定義
    <div id="hello"></div>
    <br>
    クラスとして関数を定義
    <div id="hello2"></div>
    <br>
    component の中から別のコンポーネントを呼ぶ
    <div id="hello3"></div>
    <br>
    配列の内容を出力
    <div id="print_array"></div>
    <br>
    全部まとめて呼び出し
    <div id="all_sample"></div>
    <script src="build/hello.js"></script>
  </body>
</html>

javascript

  • ファイル名を hello.js として /src ディレクトリに保存すると、build されて /build/hello.js が生成される。
// 関数として定義
const Hello = (props) => {
  // props.name で引数取得
  return (
    <div className="Hello">
      Hello {props.name}
    </div>
  );
};
// 呼び出し
ReactDOM.render(
  <Hello name="Mr. Sato" />, // name で引数を指定
  document.getElementById('hello')
);


// クラスとして関数を定義
class Hello2 extends React.Component {
  constructor(props) {
    super(props);
  }
  render() {
    return (
      <div>
        Hello2
      </div>
    );
  }
}
// 呼び出し
ReactDOM.render(
  <Hello2 />,
  document.getElementById('hello2')
);


// component の中から別のコンポーネントを呼ぶ
const Foo = (props) => {
  return (
    <div>
      <Hello name="Mr. Suzuki"/>
      <Hello name="Mr. Kaede"/>
      <Hello name="Mr. Minato"/>
    </div>
  );
}
// 呼び出し
ReactDOM.render(
  <Foo />,
  document.getElementById('hello3')
);


// jsの配列の内容を出力
ar = [1,2,3,4]
/* comment */
const PrintArray = (props) => {
  // JSXの中で{}で変数展開できる
  return (
    <ul>
      {props.items.map((item, index) => (
        <li key={index}>{item}</li>
      ))}
    </ul>
  );
}
// 呼び出し
ReactDOM.render(
  <PrintArray items={ar}/>,
  document.getElementById('print_array')
);

// 全部まとめて呼び出し. renderは1つの要素のみ扱えるので <div> で全体を囲む必要がある
ReactDOM.render(
  <div>
    <Hello name="Mr. Sato" />
    <Hello2 />
    <Foo />
    <PrintArray items={ar} />
  </div>
  ,
  document.getElementById('all_sample')
);

トラブルシューティング

  • JSXについて何かしらの変換に失敗している場合、エラーログで教えてくれる便利
  • よくあるのは <Foo /><Foo \> と書いてしまうミス
built Module("hello")
["bar","foo","hello","style"]
hello.js changed; rebuilding...
Error while reading module hello:
Error: Parse Error: Line 21: Invalid regular expression: missing /
    at throwError (/usr/local/lib/node_modules/react-tools/node_modules/jstransform/node_modules/esprima-fb/esprima.js:2813:21)
    at scanRegExpBody (/usr/local/lib/node_modules/react-tools/node_modules/jstransform/node_modules/esprima-fb/esprima.js:1490:17)
    at scanRegExp (/usr/local/lib/node_modules/react-tools/node_modules/jstransform/node_modules/esprima-fb/esprima.js:1569:16)
    at parsePrimaryExpression (/usr/local/lib/node_modules/react-tools/node_modules/jstransform/node_modules/esprima-fb/esprima.js:3562:43)

実行結果

f:id:u16s:20171205013334p:plain

outer join を使ってみる

テストデータ

# towns table
id  name
1  アテネ
2  ヴェネチア
3  ローマ
5  ピサ

# users table
id  name    town_id
1  taro    1
2  jiro    2
3  saburo  3
4  shiro   4

inner join

  • town_id 4 のレコードは towns tableに存在しないので表示されない
select
  *
from
  users AS u
    join
  towns AS t
    on u.town_id = t.id
;

id  name    town_id id  name
1  taro    1  1  アテネ
2  jiro    2  2  ヴェネチア
3  saburo  3  3  ローマ

left outer join

  • こちらの outer join では town_id 4 のレコードは towns tableに存在しないので NULL になってる
select
  *
from
  users AS u
    left outer join
  towns AS t  
    on u.town_id = t.id
;

id  name    town_id id  name
1  taro    1  1  アテネ
2  jiro    2  2  ヴェネチア
3  saburo  3  3  ローマ
4  shiro   4  NULL    NULL

right outer join

select
  *
from
  users AS u
    right outer join
  towns AS t
    on u.town_id = t.id
;

id  name    town_id id  name
1  taro    1  1  アテネ
2  jiro    2  2  ヴェネチア
3  saburo  3  3  ローマ
NULL    NULL    NULL    5  ピサ

まとめ

  • inner join : 片方だけに存在するレコードは表示しない
  • outer join : 片方だけに存在するレコードはNULLで表示する. こちらはleft, rightの向きがある.

TOC と CCPMに関する本を読んだ

夏休みの読書感想文。

最近 TOCCCPMに関する本を会社からいただいて読んだ。

また、会社での研修にも参加することができそこでも座学とワークショップで CCPM, TOC について学んだ。

これにより、スケジュール通りに品質を落とさずに、仕事を進めるための方法論をいくつか学んだ。

人間の心理的な性質

(1). パーキンソンの第1法則: 仕事の量は、完成のために与えられた時間をすべて満たすまで膨張する

  • ➡️ 結果として、スケジュールを長めに取ってもやることをふやしてしまい、プロジェクトの終盤になって工数がたりなくなってしまう

(2). 学生症候群 : 人は締め切り直前にならないと本気で仕事をしないという人間の行動特性

  • ➡️ 結果として、スケジュールを長めに取っても、初めから本気になって仕事をしないから効率性がよくない

(3). 心理的安全性 : チームの中で 気兼ねなく安心して 発言や行動できるか?を示す言葉 どんな発言をしても決して非難されることはないという安心感

  • ➡️ チーム内でこれが低いと, 例えば, スケジュール通りに終わらないと、怒られるという恐怖から、サバ読み工数の申請や、深夜残業や体調を崩しても終わらせようとしてしまう.
  • 例. 見積もりをしてタスクを終わらせた場合…心理的な安全性が低いと…
    • 見積もりよりも、早く終わった場合 : 「見積もりの精度が低い」と怒られる. 本来なら早く終わったら、良いことなので、ほめられるべき.
    • 見積もりよりも、遅く終わった場合 : 「見積もりより超えている」と怒られる. そもそも、プロジェクトは「不確定」なもの. やってみないとわからない部分はある.
    • 結果として、工数の鯖読みや、見積もりのばかしあいが発生し、そもそも見積もりの正確性が低下し、スケジュールの正確性も低下する

これらにより、

  • ➡️ スケジュールに余裕があると、人はタスクをスケジュール通りに終わらせることができるというのは 「幻想」 ということになる。

プロジェクトの性質

  • 「がんばる」だけでは、プロジェクトはうまくいかない
  • プロジェクトとはそもそも、「不確定」なもの
    • プロジェクトには新規性がある. (やってみないとわからない)
    • プロジェクトには有期性がある. (期間が決まっている)
  • +上記の人間の心理的な性質

プロジェクトマネジメントの3つの性質

  1. QCD(quality,cost,delivery) という制約の矛盾
  2. 的確な優先順位をつけられない : おおきなPJになるほど詳細を把握することが困難になる為
  3. かけた工数では、プロジェクトの進捗を計れない

じゃあどうするか?

以上が、「プロジェクト」、「プロジェクトマネジメント」とそれにかかわる「人間」の性質になる。

これを踏まえた上で、どう工夫してプロジェクトを進めるとよいのか?

を述べたものが、CCPMの方法論として、以下のものになる。

とくに、ここのタスクからバッファを排除し、プロジェクト単位でまとめてバッファを管理することで、個々のタスクの工数を限界ギリギリまで短くする。

これにより学生証症候群とパーキンソンの第1法則に陥ることを防いでいる。

CCPM5つの特徴

  1. マルチタスクを排除
  2. クリティカルチェーン(そこのタスクの流れが遅れたら全体が遅れてしまう部分のこと) によるマネジメント
  3. 個々のタスクからバッファを取り出す
  4. バッファの消費状況でプロジェクトを管理する
  5. フルキット(タスクに取りかかれる万全の状態)にして、タスクに取りかかる

CCPMの3つの心がけ

  • 毎日の朝会で問題を解決する
    • 後何日で終わりそうか?
    • こまっていることは?
    • 何か支援できることは?
  • 個々のタスクの遅れを責めない
  • 最も重要な課題 に対応する

感想

なんとなく自分が今までの仕事の経験でやってきた中でのうまくいったパターンが言語化されていて驚いた。自分のやり方は間違っていなかったという印象を得て救われた気分。

とはいえ、これを今すぐにチーム全体に適用しましょうというのはむずかしいので、できるところから徐々にやっていこうと思っている。

具体的には、自分のスケジュール部分だけはバッファの切り出して、まとめて管理をやってみるなどかなぁと。

講師の方とも話したのだが、やはりチームに展開するときに理論やってドラスティックに実践!というかんじではなく、ちょこちょこ細かいプラクティスをやっていって、うまくいったねー!よかったねー!でプロジェクトを終える感じらしい。

それで、より深掘りしたい方がいたら初めて理論や書籍を紹介する的なながれがうまくいっているという話を伺った。なるほどなぁ。そうだよなぁ。という感。

読んだ本

ARのjoinまわりのメソッドを勉強した

ARのjoinまわりのメソッドを勉強した。N+1を解消するのにとても便利。

joins

  • アソシエーションをキャッシュしない
  • アソシエーションを検索条件でだけつかいたいときに有効
  • 内部的には普通にjoinしてる

preload

  • アソシエーションをキャッシュする
  • 必要なテーブルをまとめて別のselect文で読み込みするのでクエリは2回に発行される
  • あまりjoinしたくないでかいテーブルに有効
  • joinしてないので、絞り込み条件に関連テーブルを使えない
  • index系のAPIでの N+1 の解消に有効

eager_load

  • アソシエーションをキャッシュする
  • joinする
  • joinしているので、絞り込み条件に関連テーブルを使える

includes

  • preload と eager_load を適切に使い分けてくれる
    • join先で絞り込んでいたら eager_load
    • してなかったら preload

merge

  • joinsをチェインすることができる
  • ちょっと初見だとどんなクエリになるか判断つかないかもしれない
Comment.joins(:entry).where(Entry.merge(:draft)) # scopeを使うとき
Comment.joins(:entry).merge(Entry.where(published_at: nil)) # scopeを使わないとき

これらのメソッドを使ってもどうしてもN+1が解決できない場合

最後に、これらのメソッドを使ってもどうしてもN+1が解決できない場合は、

一旦Rubyの配列に確保してしまってからループの中でRubyの方のselect メソッドを使うことで解決した。

# N+1 の発生を防ぐため, あらかじめまとめて読み込んでおく
user_favs = @user.favs.where( target_id: Articles.published.pluck(:id) ).to_a

users = list.map do |elem|
  user_fav = user_favs.select{ |f| f.id == elem.fav_id } # Array#select を使う
  # user_favを使って諸々の処理をする
end

参考

ActiveRecordのjoinsとpreloadとincludesとeager_loadの違い - Qiita

1 on 1 についてのまとめ

最近、自分の周りで 1 on 1 をやる機会が多くなってきた。

そんな折に、タイムリーにも WEB+DB PRESS

ひげぽんさんが 1 on 1 の記事を書いていらして、

とても良い記事だったので、後から見返しやすいようにまとめてみました。

1 on 1 を行う目的

  • 半年の1年の評価面談で、寝耳に水のマイナス評価を突然うけるのを避けたい
    • 半年前から判明していた問題点を評価面談の時に言われても遅い(汗
    • これをなくすために、1on1で小さなフィードバックのループを維持したい

1 on 1 の枠組み

  • 1~2週間に1度の頻度で
  • 1回30分程度
  • 2人で共有できる議事録を作成し, あらかじめ話したいことを箇条書きで書いておく

1 on 1 でマネージャと話すとよいこと

  • いま困っていること
    • ブロックされていることなどマネージャが直ちに行動を起こすべきこと
  • プロジェクトの進捗
  • 人に関わる相談があれば
  • キャリアマネジメント
    • この先、5年後、10年後どうなっていたいのか
  • 社内の最新事情
    • manager たちの中で問題になっていること
    • 組織変更の予感など
  • チーム貢献
    • チームで困っている人がいる場合、MTG, work flow で改善できそうなことはないか
    • チームやマネージャーの生産性向上に寄与できると素晴らしい

1on1 をスムーズに進める為の工夫

  • 2人で共有できる議事録を作成しよう
    • あらかじめ、話したいことを箇条書きで書いておくと話がスムーズに進む
  • マネージャーとの間に、仕事以外の共通の話題が1つあると導入部分によい

マネージャからみた場合

  • 広い質問をする
  • 8割聞き役になる
  • その人が期待されている役割やパフォーマンスを一緒にみていく
    • よくできている部分
      • 大げさなくらいにほめる
    • 改善できそうなポイント
      • 「できていない」という否定の説明ではなく、「こうするともっと良くなる」という肯定的な説明をしよう

WEB+DB PRESS Vol.99

WEB+DB PRESS Vol.99

  • 作者: ?橋健一,谷口禎英,井本大登,山崎勝平,大和田純,内村元樹,坂東昌哉,平田敏之,牧大輔,板敷康洋,大?浩崇,穴井宏幸,原口宗悟,久田真寛,ふしはらかん,のざきひろふみ,うらがみ,ひげぽん,池田拓司,はまちや2,竹原,片田雄樹,渋江一晃,WEB+DB PRESS編集部編
  • 出版社/メーカー: 技術評論社
  • 発売日: 2017/06/24
  • メディア: 大型本
  • この商品を含むブログを見る

リトライ処理のメモ

Rubyでリトライ処理をする際のテンプレ。再帰を使って綺麗に書ける。

class RetryException < StandardError; end

def foo
  p Time.now
  raise RetryException
end

def retry_foo( rc = 3)
  begin
    foo
  rescue RetryException => ex # RetryException以外はretryしない
    retry_foo( rc - 1 ) if rc > 1
  end
end

retry_foo

これだと、複数のメソッドに対応できない。 後で、blockで処理を受け取るようにしたい。

追記: retry 制御構文というものがあったので、それを使って書き直してみた。

def foo
  p Time.now
  raise
end

# 単純にfooメソッドをretryする
def retry_foo(count=3)
  c = count
  begin
    c = c - 1
    foo
  rescue
    retry if c > 0
  end
end

# 受け取ったブロックをretryする
def retryer(count=3)
  c = count
  begin
    c -= 1
    yield
  rescue
    retry if c > 0
  end
end

# retry_foo(5)
retryer(3) do
  foo
end

Object#methodについてメモ

この書き方ができるの知らなかった.

# レシーバがself. (Object#methodはレシーバとメソッドの実態を封入する.)
[1,2,3].each( &self.method(:puts) )
[1,2,3].each( &method(:puts) ) # selfを省略できる
[1,2,3].each{|i| puts(i) }

こちらはたまに使う.

# レシーバが配列の各要素.
p [1,2,3].map( &:to_s )
p [1,2,3].map{|i| i.to_s }

Refer