PRでコメントが多いそんなとき
みなさんはレビュー時にあまりにコメントが多くなりすぎて困ったことがないでしょうか?
今回はそういうことにおちいった僕が考えたことをそこはかとなく書き残しておきます。
チームの状況や練度等に大きく左右されるので他のチームの知見を鵜呑みにするのではなく、その考えが出てきた理由などに着目すべきでしょう。
前提
- 大量のコメントがつくような問題のあるPRを出した人は悪意を持ってそういったことをしているわけではありません
- チームは悪意を持ってそのコメントしているわけではなく少しでも良くしようとしています
何が悪いんだろう
PRで大量にコメントがついたとしても、必ずしも作業者だけに問題があるわけではないと思います。
僕が思うに、様々な前提が共有されていないためにそのような状況に陥ってしまったのではないかと考えます。
チームはその前提の共有のために惜しみない協力を行ったのでしょうか?
多くのチームではそういったことをせず、なぜわからないのなら聞かないのか?というような指摘をして終わらせているのではないでしょうか?
それが本当に問題なのだとして、その人が質問できる適切な場を提供しているのでしょうか?
こういったような作業者だけではない問題を直さないと、今回はたまたま問題のあるPRを出した人とは違う人が同じような状況に陥ることはあるのではないかと思います
こういったときにはチームとして何が問題だったかを考え、みんなでより遠くに行く方法を検討したいと考えたいと思っています。
解決策案
PRのコメントを効率よく減らそうと思うと、PRが出てコメントがつけられるようになった段階ではおそすぎます。なので、その前のどの段階で何をするのかが重要です。
僕が考えたのはプランニングの段階である程度コンセンサスを取っておけば大きな問題はないのではなか?というものです。(我々はスクラムで開発しています。)
とはいえ、プランニングがいたずらに長くなるのはいただけません。PRのコメントが減り、かつできるだけ短くプランニングを終えるたいのです。
そこで僕が考えたのは、「事前にインターフェースをある程度決めておけばそんなに大きく間違えないのではないか?」という手です。
例として、RESTAPIを作成するタスクであればドメインサービス周辺のインターフェースを作業者のみに委ねるのではなく、全員で一緒に考えてメソッドの引数、戻り値やその周りで使いそうなものをある程度定義しておけばいいのではないか?といった感じです。
さらに、先にインターフェースを定義することで、別の作業者がそれを呼び出すコントローラーや、それが呼び出すであろうリポジトリの実装を行えるようになるので一人で手に負えなくなっても手助けしやすいという嬉しい副作用もあります。
解決した?
しませんでした。
インターフェース決めればうまくいくよねって思ってたんですが、インターフェースという言葉がお互い認識が違っていて決めたインターフェースが作業に入ってから変わった変わらなかったの不毛な話し合いが後で置きましたとさ。
人間が解り合うのは難しいですね。
PlayframeworkのFormで要素が一つのcase classと仲良くする
要素が一つのcase classがあると困ること
例えば下のようなcase classをやり取りしたい時、JSONではちょっと困りますよね。
case class LongValue(value: Long) { require(value % 2 == 0) }
JSONの方は仕方なくこうして、
{ "longValue": { "value": 20 } }
そして Form
はこう
def hoge() = Form( "longValue" -> mapping( "value" -> longNumber.verifying(_ % 2 == 0) )(LongValue.apply)(LongValue.unapply) )
これだけならまだ良いけどこれが配列で…とかになるともう面倒ですよね。
それにせっかくcase classで require
を指定してるのに verifying
でチェックするのもなんか面倒ですよね。
専用の Formatter
を用意する
こんな感じのFormatterを用意してやるといい感じにできます。
def formatter[T](f:String => T) = new Formatter[T] { override val format = None override def bind(key: String, data: Map[String, String]): Either[Seq[FormError], T] = try { data.get(key) match { case Some(v) => Right(f(v)) case _ => Left(Seq(FormError(key, "error.required", Nil))) } } catch { case _: Exception => Left(Seq(FormError(key, s"error.${key}", Nil))) } override def unbind(key: String, value: T): Map[String, String] = Map(key -> value.toString) } val longValue = of[LongValue](formatter(s => LongValue(s.toLong)))
これを使うとJSONはこう
{ "longValue": 20 }
Form
はこう
Form(
"longValue" -> longValue
)
LongValue
配列だったとしてもこんなので済みます。
Form(
"longValue" -> list(longValue)
)
必要であれば標準の optional
や verifying
も使えます。
Form( "longValue" -> optional(longValue.verifying(_.value <= 10)) )
さらに、他のcase classをつかいたくなったときにはこうです。
case class IntValue(value: Int) val intValue:FieldMapping[IntValue] = of[IntValue](formatter(s => IntValue(s.toInt)))
普通にマッピング書くよりすこしコード量増えてしまいますが、要素が一つのcase classが頻繁に登場するようであれば Form
はむしろスッキリするのではないでしょうか
IntelliJ IDEAでsbtのテストをステップ実行する方法
ここで紹介されていた方法がうまく行かなかったのでsbt0.13.13で実行可能な最小構成を作成。
Defaults.testSettings
では test/main/scala
以下のテストが共有されないらしいので、代わりに Defaults.testTasks
を使えばいいらしい。
初めての WPF デスクトップ アプリケーション
初めてのWPF
MSから公開されいているこのチュートリアルをやってみましょう!
チュートリアル: 初めての WPF デスクトップ アプリケーション
何かがおかしい
最後までやってみましたか?
ListBoxには何も表示されないですよね?
実はこのチュートリアル間違ってます。
プログラミングコンテストで便利なIntelliJプラグイン CHelperを使う
テストしてないってそれ
プログラミングコンテストで解答が毎回正しいかチェックするためにいちいち実行、サンプル入力、目視確認とか死ぬほど面倒くさいですよね?
僕は面倒臭いです。
でもUnitTest書くのはそれの比にならないくらい面倒くさいですよね?
僕は面倒臭いです。
でもテストしないのはライオンのようなものに襲われる恐怖がありますよね?
みんなあんまりどうやってチェックしてるのか知らないのですごい人を参考にすることにしましょう。
なんか便利そうなの使ってますね。
これがCHelperです。
www.youtube.com
PaizaでJavaはどれだけのタイムがでるか?
Paiza Online Hackason Lite4
マンガ版「エンジニアでも恋がしたい!」〜転職初日にぶつかった女の子が同僚だった件〜|paizaオンラインハッカソン4 Lite
ここでちょっと気になったことがあるのでメモ程度に
検証
case 1で検証します。
問題が非常に単純でアルゴリズムによる差がほぼ出ないことが期待できるためです。
import java.io.BufferedReader; import java.io.InputStreamReader; public class Main { public static void main(String[] args) throws Exception { BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine()); int sum = 0; for(int i = 0; i < n; i++){ sum += Integer.parseInt(br.readLine()); } System.out.println(sum); } }
無難にやればこんな感じの回答になるかと思います。
これで提出するとこんな感じ。
マンガ版「エンジニアでも恋がしたい!」〜転職初日にぶつかった女の子が同僚だった件〜|paizaオンラインハッカソン4 Lite
全部0.07sで満点ですね。
これもうこれ以上短くするのは結構厳しいです。
でもそもそもこの0.07sってなんなの?気になりますよね
そこでイカのソースを使います。
import java.io.BufferedReader; import java.io.InputStreamReader; import java.util.Date; public class Main { public static void main(String[] args) throws Exception { Date start = new Date(); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); int n = Integer.parseInt(br.readLine()); int sum = 0; for(int i = 0; i < n; i++){ sum += Integer.parseInt(br.readLine()); } Date end = new Date(); if( (end.getTime() - start.getTime()) <= 1 ) System.out.println(sum); } }
これを実行すれば処理が1msより遅ければ答えが出力されないハードモードになります。
当店甘えは許しておりませんので。
これを実行した結果はこちら
マンガ版「エンジニアでも恋がしたい!」〜転職初日にぶつかった女の子が同僚だった件〜|paizaオンラインハッカソン4 Lite
なんと全部通っています!しかし0.07s変わらず!
これたぶんJVMの起動時間なんかも含まれているんじゃないかなって気がします。
ということでJavaで挑戦する人は0.07sに達していれば十分な速度を出せているといって問題ないかと思います。
ところで
そもそも0.07sでなんで遅いと思ったのかというのこれを見たからです。
※集計結果を詳しく見るを開いてください
天才火消しエンジニア霧島「もしPMおじさんが丸投げを覚えたら」|paizaオンラインハッカソンLite
0.01s早くね?この回答出した人やばくね?って思ったけどそもそもどうやってもこれでなくね?って話
ただしサーバーの混み具合等によって結果が変動することは明記されていますので、
空いてる時間にやればコレくらいの速度は出るものなのかもしれません。
つまりよりいい結果を出すには、空いている時間にいい結果がでるまでサーバーのご機嫌ガチャを回しまくるのが近道なのではないでしょうか。