チーム異動があって、「ふりかえり」が自分の中では一番大事だと気づいた話
2月の半ばに組織改編があり、新しいチームにリーダーとして異動しました。新しい環境で試行錯誤する中で、自分がチームビルディングにおいて大切に思っているものが見えてきたので、それを書き残しておきたいと思います。
数回に分けて書く予定ですが、そう宣言しておいて続いた試しがこのブログでは無い…
ふりかえりのためにタイムボックスをセットした
異動してチームメンバーに初めにさせてもらったことは、二週間のスプリント切りでした。
今日から2週間で一旦区切らせてください、というお願いです。
「アジャイルな開発」をするため? 多分違います。
計画を立てて実施しきるため? それも違います。
理由は一つ。「ふりかえりをするため」です。
私は、チームが自分たちのやり方やスキル、チーム力を高めていくために、短いサイクルでの定期的なふりかえりが、最も大切と考えています。
ですので、私の新しいチームのメンバーには、定期的な間隔でふりかえりがあること、そしてその場では、自分たちの問題を自分たちで発見し、自分たちで解決までのプロセスを考えてよいことを知って欲しかったのです。
そのためのスプリント切りでした。
一方で、最初のスプリントの”計画は”、ややゆるめに、「今までの流れで、もともと、むこう2週間でやろうと思っていたことを、この2週間でやってください」と伝えるに止めました。
今回の異動では、もともと存在していたチーム・案件に、私一人が新参として入った状況です。一番プロダクトのことも案件のことも分かっていない私があーだこーだ言うよりも、基本的にはもともとみなさんがやられていたやり方を継続してもらう方がいいと考えました。
たくさんKeepやProblemが出てきたふりかえり
ふりかえりミーティングでは、「全員に参加」してもらうために、Keepと Problemのパートでは順番に一人一人思っていることをあげてもらう手法を取りました。また、私が強めのファシリテーションをし、あげてもらったものに対して深掘りすることもしました。
「○○ができてよかった」→「それができた要因ってなんでしょう?」
「○○で困った」→「本質的には何に困ってたんだろ?」「そういうことが起こった要因はなんだろう?」
という具合です。
嬉しかったのが、みなさん、たくさんのKeepやTryを上げてくれたことでした。初回は一人当たり、2つ以上のKeepとProblemが上がったような気がします。
私が異動してから5回ほどふりかえりを行いましたが、今でもこの傾向は続いていて、嬉しい限りです。
また、ProblemからTryに落とし込む際も、真剣に考えてアイディアを出してくださっている印象があります。
このチームはこれからどんどん、自分たちを自分たちで良くしていって、強いチームになっていくと思います。
テストを整備するよりもアーキテクチャを変更するほうが効果が高そうと思った話
2月の半ばに、これまで3年弱携わらせてもらったプロダクト/チームを離れて、新しいプロダクトを担当することになりました。
プロダクト面での一番大きな違いは、これまでは主にデータ更新/参照系のAPI(HTTPでコールして、JSONとかXMLとか返す)ばかりを担当してきたのですが、今回担当させていただくことになったプロダクトはいわゆる普通のWebアプリケーションで、「画面」があります。
これまでは担当プロダクトがAPIだったので、EndToEndテストの整備もある程度いい感じにできてきていて、リグレッション系の不具合はほぼ0!という素晴らしいプロダクトとチームを作ってくることができました。
しかし今回、テストすることが難しい「画面」をサービスとして受け持つことになり、どうやって品質を保っていこうかなぁ… と思っていた矢先、早速、リグレッションにあたってしまいました。
ちょっと前の案件で、直さなくていいところまでJSPを直してしまっていたそうです。
ロジック周りがどれだけちゃんとしていても、最後の最後にViewでバグられたら回避方法無いじゃん… と悩みました。
エンドツーエンドテストで細かくテストできるか
ここで一旦、Seleniumなどのツールでで細か目のエンドツーエンドテスト(=イメージ的には画面レベルのユニットテスト)と思いました。
ちょうど一ヶ月ほど前にGebというものを覚えたこともあり、GebというかSpockのデータテーブル機能が、いろんな組み合わせのテストケースを並べるにはイケそうじゃん!と思ったのですが…
ダメだこれ、遅すぎる。
メンテナンス性がー とか HTMLが古くてタグにIDすら振られてねー
とか言う以前に、自分のやろうとしているテストをやろうとしたら、どれだけハイスペックなマシンを使っても埒が明かねーなこれ、という結論に至ってしまいました。
そんなのよりアーキテクチャ変更なんだろうな
結局Viewに近いところのバグを減らすためには、Viewにロジックを持たせないことなのだろう
という結論に至りました。
CROSS2015 に参加してきました #cross2015
CROSS2015というイベントに参加してきました!
パネルディスカッションに参加した!
今回の主目的は、パネルディスカッションへのパネラーとしての参加。
旅行ECサイト各社に聞く成長の秘訣とこれから と題された、異色のパネルディスカッションに参加してきました。
一休.comさん、Reluxさん、そして楽天トラベルと、オンライン旅行サイトのエンジニアが集まってパネルディスカッションをするというもので、
正直、始めにお話を頂いた時は、「それ、誰か聞きに来てくれるの…?」という感じだったのですが…
会場に対しては少し少なめではあったものの、多くのお客さんに来場していただけました!
旅行ECサイト各社に聞く成長の秘訣とこれから #cross2015a - NAVER まとめ
私自身は初めてのパネルで、
常に回答を考えながら、そして「これ言っていいんだっけ?」も考えながらで、
結構表情がひきつりながら話していたんじゃないかと思います…。
「子供料金あるある」など、諸々の話題で盛り上がれて楽しかったです。
お互い話し足りなかったようで、ぜひ近いうちに居酒屋で延長戦を!ということで本日は別れました。
もともとこの企画の目的の一つが、エンジニア間での横のつながりを作る という話だったので、その点は成功だったのかな、と思います。
ただ、お客さんになにか持ってかえってもらえたのかは微妙…。パネルディスカッション難しいですね。
アウトプットを意識する → とりあえず喋ってみた! → いいことあった
代わって、聴講したセッションのお話。
先達に聞くこれからのエンジニア像というタイトルのセッション。
Googleの及川さん、テコラス技術研究所の伊勢さん、そして楽天の吉岡さんのお三方のパネルディスカッションでした。
90分に渡るディスカッションでしたが、特に印象に残ったやりとりを抜粋させていただきます。
自分が成長した、ターニングポイントはどういう時だったか
→ 転職や異動など、環境が変わった時が多い (3名とも)
→ 自分は自ら環境を変えてしまう。怠け者なので自ら仕事を取りに行って必死に勉強する。IPv6の担当になった時もそうだった。(及川さん)
自らを成長させるための方法
→ 思ったことをやればいい。ただし、やりたいことをやるために、やりたくないことを倍くらいやる必要あり(伊勢さん)
これは俺、似たようなことをつい今朝FBに書いてたな…と思ったり。
そして面白かったのが、
→ (40歳以降の人は)若い人と話す。若い人にあってもらいたいと思われるような人間で無くてはならない(及川さん)
→ 若い人と一緒に飲んだ時に説教モードにはいってはいけない(吉岡さん)
→ 自分はむしろ説教される(伊勢さん)
このエピソード、途中から酔っぱらいの戯言みたいになっていたのですが、すごく皆さんの学びに対する意識が現れているように感じました。
皆さん年齢も、経験も重ねているのに、いろんな人から貪欲に新しいことを吸収したいのだという姿勢の現れかと!
そして、はっとさせられたのがこの一言。
→ アウトプットを意識する。呼吸は吸うのを意識するのではなく、吐くのを意識するのが大事。
勉強会に出るのがゴールになってしまってはもったいない。「質問したり」「LTしたり」「ブログを書いたり」
して、いろんな人からフィードバックをもらい、そこから良い所を取り入れる姿勢が重要。(及川さん)
今日のカンファレンスでは、夜の部で1時間半ほども、アンカンファレンスという、野良LTの枠が用意されていました。
気にはなっていたものの、今日はまとまったテーマもないし準備もしてないし… と敬遠していたのですが、
この及川さんの一言で一念発起。
5分程度の枠ならどうにでもなるわ! と、とりあえず枠を取らせていただきました。
結局話したのが、以下の話。
俺、7人位の開発チームのリーダー。
チームのタスクのプランニング/アサインについて悩んでます。
リスク分散や、スクラム的な理由では、「アサイン」をしたくない。全員がすべてのタスクを理解して、自主的にタスクを取って行って欲しい。
一方、「あなたのタスクはこれ!」の方が、よりそのタスク/プロダクトに対して責任感が生まれ、モチベーションは上がる。
悩ましいのだけれど、どっちがいいと思う?
と言うもの。
5分枠のうち、1分半ほどで上の話をさせてもらって、残りはひたすら会場に意見を求めるという、
俺も会場の人も酔ってるからどうにかなるだろ! 的な酷いセッションでしたw
幸い、お仲間のメンバーが盛り上げてくれたこともあり、
・2人組にすれば両者のいいところがとれるのでは
・3ヶ月位でのローテーション制
・そもそも会社に自分しかエンジニアがいないのでそんな状況ではない
などの素晴らしい回答を頂きました!
さらにさらに結果的にここで話したことがきっかけになって、この後及川さんともお話させていただくチャンスが。
おそらく、先ほどのパネルディスカッションの後に話しかけに行っても人だかりにまみれて対して話せなかったのではないかな、と思います。
やはり、アウトプットあるところにインプットありだと感じました。
なんでアジャイルなんだっけ
グループの後輩が二人、James O. Coplien氏の認定スクラムマスター研修を受けてきました。
昨年私が受けた時と同様に、たくさんの刺激を受けて、いろんなことを考え、やりたいこと、悶々としていることがたくさん湧き出ている状態のようです。
このへんのくだりは昨年、社外で発表させていただく機会を頂きました。
これはこれで若干の違和感を感じ始め、今年の夏ころからもう一度「個人」にフォーカスした仕事の進め方の検討を始めてきました。
この後きっかけがあり、現在は、さらに各チームメンバーが「自分のタスク」に責任を持ってフォーカスをしてもらう形をとっています。
決して戻ったわけではないと思っています。
U+FFFF以上の文字ってなんや → サロゲートペアってなんや → Spring Web Services が言うことを聞きません! とかで一日潰れた話
表題のような感じなのですが、これまで理解が曖昧だったUnicodeとか何とかが今までよりわかったのでメモ。
尚、こちらのサイトを非常に参考にさせていただきました。
コードポイントとは 文字コードとは
今日覚えた単語その一。Unicodeに限らず、文字をコンピュータ上で表現する際、1つの文字に1つの数値を対応させるわけですが、この文字に対応する数値をコードポイントというそう。
いままでASCIIコードとか呼んでました。
そして、文字と数値の割り当てのルールのことを「文字コード」と言うんだそうです。
Unicodeとは から UTF-XXは何が違うんじゃ という話へ
Unicode誕生
文字コードが乱立したため、あるコードポイントで表現される文字が、文字コードによって、てんでばらばらという状況に。
ややこしいから、ひとつの統一した文字コードをつくろう! ということで「Unicode」が作られることになりました。
Unicodeを使うときは、U+12ABのように16進数の先頭にU+をつけて表すことにして、
U+0000~U+FFFFの216パターンで世の中の文字を表そう!ってことでUnicode1.0が生まれたそうです。
サロゲートペアの誕生
ところが、特にアジア圏の文字を表そうとしたらこれでは全然足りなくて、U+10FFFFまでUnicodeを拡張することになりました。
しかしこれだと1文字表現するのに21bit必要で、2nじゃないのでとっても切りが悪いという事態に。
そこで、もともとUnicode1.0で使われていた16bitでなんとか表現するために、
たまたま未使用だったD800H~DFFFHを2つ組み合わせ、32bitを使ってU+10000以上を表現するという、むりくりな方法が発明されたそうです。これが「サロゲートペア」。
で、U+0000~U+FFFFの文字をBMP(Basic Multilingual Plane, 基本多言語面)、U+010000~U+10FFFFまでの文字をSMP(Supplementary Multilingual Plane, 追加多言語面)と呼ぶことにしたそうです。
UTF-XX
上記のような経緯を踏まえ、実際にデータ上でどう表すかという、エンコード方式がいくつか考えられたそうです。
UTF-16 → 上の通りのサロゲートペアをそのまま実装した、一文字に16bit使うエンコード方式。一番正直。
UTF-32 → サロゲートペアはややこしいので、すべての文字に対して32bitを割り当てた方式。一番わかり易いけど、一番無駄が多い。
UTF-8 → 文字に合わせて、8bit, 16bit, 24bit, 32bitのどれかを使うようにしている。Unicodeの中では無駄が一番少なく、最も普及している。
JavaでのSMP
少し話変わってJavaのお話。
突然ですが、Javaのプリミティブ変数のchar型は、上限が (char) 0xFFFF なので、なんとSMPに割り当てられた文字が表現できないそうです!
そこで、Java5.0以降、上記のサロゲートペアの考え方を流用して、SMPは、char2つで1文字を表すようにしています。
Javaでのサロゲートペアの扱いについてはこの記事がわかりやすかったです。
Spring Web Serviceが言うことを聞きません!
…と、ここまで説明してようやく私の身に起こったことを。
いろいろありまして、XML上にU+1F6ADのようなSMPを出力する必要がありました。
XMLの仕様的には単純で、数値文字参照を使って 🚭 とか 🚭 と表現できればOKです。
一方、私達のサービスではSpring Web ServiceというSOAPアプリのためのフレームワークを使っています。
こいつ、普段はなかなか便利な子でして、EndPointのレスポンスとしてBeanをReturnすると、そのBeanの階層構造をそのまま反映したXMLを作ってくれるのです。
また、XML上必要なエスケープも自動で行ってくれて、たとえば「&」が文字列の値として含まれていたら、XMLを出力する際にはきちんと「&」と出力してくれる、という具合です。
では、このSpring Web Serviceを使った時に、
レスポンスのBeanに含まれる hoge フィールドに、🚭(U+1F6AD)が入っていたらどうなるか!?
なんじゃこりゃぁ!?
55357 = D83DH, 57005 = DEADHで、サロゲートペアに分解された上で実体参照として表現されています。
おそらく、String hoge 内のcharの配列を頭から順に1文字ずつ処理してるんだろうなぁ… と推測されます。
更に良くないことに、D800H~DFFFHはUnicodeでは単独で存在できない文字なので、上記�や�はXML上使えない文字で、これらが含まれたXMLは正しくパースされません。
結局現状で、XMLを破壊しないためには、Character#isSupplementaryCodePoint methodを使って、SMPを除外する以外方法がなさそう。
うーむ…。
おまけ Oracle上では
じゃあこの禁煙マークがOracle(UTF-8エンコードで)に入ってた場合どうなるか
select ascii(hoge) from hoge_table;
-> 4036991661
おうふ。
これは、4036991661 = F09F9AADH でして、SMPをUTF-8で表現する場合、やたらややこしいルールで、やたらでかい数値に変換されるため…みたいです。
Javaでequalsを実装するとき -失敗するとcontainsが動かない-
hashCodeはもちろん実装しましょう。
で、
public class 俺のクラス {
private String ore;
public 俺のクラス (String ore) {
this.ore = ore;
}
public boolean equals(俺のクラス o) {
return ore.equals(o.getOre());
}
...
}
ってやったらダメ。一見まともに動くんですが…
俺のクラス o1 = new 俺のクラス("hoge");
俺のクラス o2 = new 俺のクラス("hoge");
俺のクラス o3 = new 俺のクラス("foo");
// true
o1.equals(o2);
// false
o1.equals(o3);
Correctionのcontainsがちゃんと動かない。
Set<俺のクラス> os = new HashSet<>();
os.add(o1);//もちろんtrue
os.contains(o1);
//trueになるかとおもいきやfalse
os.contains(o2);
正しいequalsの実装はこう。
public boolean equals(Object o) {
ほげほげ
}
こんなところでしばらくハマってしまった…
ちなみにはまってる間、色々調べていてわかったのですが、
HashSetって内部的には単一のObjectをValueにもってるHashMapなんですね。(java7だと)
Mapのキーの管理にSet使うならわかるんだけど実態は逆で不思議。
org.junit.Assert.assertEquals って
中で比較してんのは equals じゃなくて == なのね…
ただしStringだけはちゃんと比較してる模様。