Quantcast
Channel: Kengo's blog
Viewing all 157 articles
Browse latest View live

FindBugsのバグパターンをMavenでビルド&テストする

$
0
0

以前の記事FindBugsバグパターンの実装方法を試行錯誤している最中に作成したものでしたが、今回はその結果どのような開発手法に行き着いたかをまとめます。Mavenベースです。

前提

  • findbugs.xmlsrc/main/resourcesに置いてしまうと単体テスト実行時にエラーが発生してしまう(前回記事参照)
  • テストが面倒
  • Mavenプラグイン、Antタスク、SonarQubeなど様々な利用方法があり得る

拡張すべきクラスについては前回記事を参照してください。

ビルドのTips

メタファイルをどうpackageするか

findbugs.xmlsrc/main/resourcesに置いてしまうことによるエラーを回避するために、メタファイルをsrc/main/metaファイルに保存してprepare-packageフェーズにリソースに追加するという手法を取ります。プロファイルを利用することもなくシンプルな解決になります。

Mavenを実行するたびにcleanを実行しなければならないという制約は付きますが、Detector用プロジェクトは基本的に小さいものになるはずですので問題にはならないでしょう。プラグイン設定は以下のようになります。

<plugin><!--          Copy meta files to default outputDirectory at "prepare-package" phase.          Because of findbugs specification, an edu.umd.cs.findbugs.PluginDoesntContainMetadataException          instance would be thrown at "test" phase if we put these meta files on '/src/main/resources'.          We have to copy these meta files after testing.          See "How to build FindBugs plugin with Maven" thread in FindBugs mailing list          (findbugs-discuss@cs.umd.edu) to get detail and other solution.          Note: You should execute "clean" phase before you execute "test" phase.        --><artifactId>maven-resources-plugin</artifactId><executions><execution><phase>prepare-package</phase><goals><goal>copy-resources</goal></goals><configuration><outputDirectory>${project.build.outputDirectory}</outputDirectory><resources><resource><directory>src/main/meta</directory></resource></resources></configuration></execution></executions></plugin>

依存ライブラリをパッケージする

findbugs-maven-pluginだけでなくSonarQubeなどでの利用も検討している場合、依存ライブラリも同梱してしまうと便利です。私はmaven-shade-pluginでこれを実現しています。

<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-shade-plugin</artifactId><version>2.0</version><executions><execution><phase>package</phase><goals><goal>shade</goal></goals><configuration><createDependencyReducedPom>false</createDependencyReducedPom></configuration></execution></executions></plugin>

テストのTips

テストには大きく分けて2通りの方法を採用しています。FindBugs本体が提供する機構はドキュメントが無いため現時点では使わず、外部ライブラリに頼った手法のみを利用しています。

test-driven-detectors4findbugs による単体テスト

youdevise/test-driven-detectors4findbugs @ GitHubはDetectorをtest-drivenな開発手法で作成できる優れたライブラリです。FindBugs 2.0.3にはまだ対応できていませんが、多くの場合問題にはならないでしょう。

使い方は非常にシンプルで、テスト用のBugReporterをDetectorに渡してからassertXxxメソッドでバグが発見されるかどうかを調べるだけです。

// quoted from https://github.com/WorksApplications/findbugs-plugin/blob/1c1930cacd0fe2aed9b41633b9b72d6a9b50e07e/src/test/java/jp/co/worksap/oss/findbugs/jsr305/BrokenImmutableClassDetectorTest.javapublicclass BrokenImmutableClassDetectorTest {

    private BrokenImmutableClassDetector detector;
    private BugReporter bugReporter;

    @Beforepublicvoid setup() {
        bugReporter = bugReporterForTesting();
        detector = new BrokenImmutableClassDetector(bugReporter);
    }

    @Testpublicvoid testEnumIsImmutable() throws Exception {
        assertNoBugsReported(When.class, detector, bugReporter);
    }

    @Testpublicvoid testMutableClass() throws Exception {
        assertBugReported(MutableClass.class, detector, bugReporter, ofType("IMMUTABLE_CLASS_SHOULD_BE_FINAL"));
        assertBugReported(MutableClass.class, detector, bugReporter, ofType("BROKEN_IMMUTABILITY"));
    }
}

この方法は簡単かつ充分なテストが行えるため、まず最初に導入したいところです。ただしこのライブラリはfindbugs.xmlのようなメタファイルは参照しないため、メタファイルと実装の不整合を見つけることはできません。実際に実行を試せる環境を別途用意するか、次に述べる統合テストを併用する必要があります。

なお依存関係は以下のようになります。

<dependency><groupId>com.google.code.findbugs</groupId><artifactId>findbugs</artifactId><version>2.0.1</version><scope>provided</scope></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><dependency><groupId>org.hamcrest</groupId><artifactId>hamcrest-library</artifactId><version>1.3</version><scope>test</scope></dependency><dependency><groupId>com.youdevise</groupId><artifactId>test-driven-detectors4findbugs</artifactId><version>0.2.1</version><scope>test</scope></dependency>

実際にFindBugsを実行した結果を解析

eller86/findbugs-slf4jで利用している方法です。Mavenのマルチモジュールを利用したやや複雑な構成です。

まずはDetector実装を含むサブモジュールを作成します。次にDetectorによる解析を行うためのクラスファイルをsrc/main/javaに持つサブモジュールを作成し、pre-integration-testフェーズでfindbugs-maven-pluginを実行することで、その結果をintegration-testフェーズで解析・照合することが可能になります。 解析用サブモジュールをDetectorサブモジュールにtestスコープで依存させることで、mvn clean install実行時にfindbugs-maven-pluginが常に新しい実装を利用することを保証できます。

この手法は実際にfindbugs-maven-pluginを利用するため、FindBugsプラグインが期待通りに動作すること、すなわちメタファイルの整合性も含めた動作保証が可能になります。XMLパーサを用意するなど実施コストは高くなりますが、この動作保証を手動で行う手間を考えるとペイすると言えるでしょう。

プラグイン設定は以下のようになります。src/test/javaにあるテストケースをintegration-testフェーズで実行するためにmaven-surefire-pluginに2つのexecutionを設定しています。

<plugin><groupId>org.codehaus.mojo</groupId><artifactId>findbugs-maven-plugin</artifactId><version>2.5.2</version><executions><execution><phase>pre-integration-test</phase><goals><goal>findbugs</goal></goals></execution></executions><configuration><threshold>Low</threshold><plugins><plugin><groupId>my.groupId</groupId><artifactId>my.detector</artifactId><version>0.0.1-SNAPSHOT</version></plugin></plugins></configuration></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-surefire-plugin</artifactId><version>2.12</version><executions><execution><id>default-test</id><phase>test</phase><configuration><skip>true</skip><!-- all test case should run at integration-test phase --></configuration></execution><execution><id>default-integration-test</id><phase>integration-test</phase><goals><goal>test</goal></goals></execution></executions></plugin>

参考資料


複数の公用語がある国で店舗がどう工夫しているか

$
0
0

シンガポールは英語・中国語・マレー語・タミル語の4つの公用語があります。しかし、だからといって全ての表示が4ヶ国語で行われているわけではありません。シンガポール人が話せる中国語と、シンガポール人の一部と海外からの労働者が話せる英語の、2言語を中心とした表記が行われています。

ただ英語がうまくない人も(シンガポール人・海外労働者ともに)存在するため、そうした人を配慮した案内になっていることが多いです。

MRT駅など、公共の場について

MRT駅のホームでは駅名が4ヶ国語で書かれています。また路線図も4ヶ国表記です。道案内表示などは英語と中国語の2言語で表記されています。飲食禁止・ドリアン持ち込み禁止といった禁止事項は英語表記です。

ICカードチャージ用マシンは4ヶ国語に対応しており、手続き開始時に言語を選べるようになっています。これは銀行用ATMでも同じです。バス内部の広告も4ヶ国語で書かれていますが、バス会社内部の無線通信は中国語で行われています。顧客向けは4ヶ国語、社内は中国語と決めているのかもしれません。

グローバル企業の対応:McDonaldのケース

メニュー・トレーの敷物・広告などはやはり英語のみになっています。ただしメニューには番号が振ってあり、英語が得意でなくても数字とYes/Noだけ話せれば事足りるようになっています:

  • メニュー番号
  • Meal(セット)かどうか
  • Up Size(飲み物とポテトを増やす)かどうか
  • 持ち帰るかどうか

なお飲み物に氷を入れないとかポテトに塩を入れないとか、そういったカスタマイズは自分から伝える必要があります。またメニューは手元に無く、指差しで注文することは想定されていないようです。手元にはサイドメニューのみが貼られているため、指差しによる販促が行われているのかもしれません。

グローバル企業の対応:Starbucksのケース

スターバックスは英語も中国語も使えない人にはややシビアかもしれません。メニューには番号もなく、指差しでのドリンク注文もできません。ケース内のマフィンやサンドイッチを指して注文することは可能ですが、後ろに人が並んでいる時には困難ですし、想定された動作では無さそうです。

店舗によってはサラダや瓶ジュースなどがレジ手前においてあり、それをレジに持って行くことで言語によるコミュニケーションを減らせます。ただ、基本的には英語が使える人を対象にしており、英語が使えない層への配慮をしているわけではなさそうです。

日本企業の対応:伊勢丹のケース

伊勢丹の食品売り場に行くと、普通に日本語の製品が売られています。英語の案内もありますが、中国語やその他の公用語の案内はほぼ望めません。ただ店員さんは中国語が使える方が多いため、シンガポール人にとっては買いやすい状態と言えそうです。

日本語の製品紹介ビデオに中国語字幕をつけたものがよく使われています。英語でない理由はよくわかりませんが、中国など他国で作成したビデオをそのまま使っているのか、駐在員以上にシンガポール人をターゲットにしたいと考えているのか、どちらかではないかと思います。

地元の対応:フードコートのケース

駐在員が来ないようなフードコートでは、中国語のみで回っているところもあります。英語で注文しようとするとNo Englishと言われるそうです。

駐在員による利用を見込んでいる場所では、英語が基本となっています。英語と中国語を併記している場合もあります。日本料理店では日本語併記もありますが、韓国料理店やインド料理店ではそういった併記はあまり見かけません。

ここでもやはり、指差しよりメニューに数字を振ることによる解決が多く使われています。注文を終えて待っている人の後ろから注文をすることもあるので、この判断は合理的と言えます。なおこの数字はレジ担当からキッチン担当に注文を伝える際にも利用されているようです。

まとめ

  • 4ヶ国語をきちんと使っているのは公共機関のみ
  • その他の企業は自社の顧客層にあわせた1〜2言語を使用
  • 番号を使うことによる解決が主流

シンガポールにいらっしゃる際は、1〜20くらいの数値を難なく言えると食いっぱぐれないですよ!

経験の少ない技術者にどのような気付きの機会を作るべきか

$
0
0

チームで仕事をする上で気づきの機会を提供することが大切であると考えているのですが、では新人の技術者には何を気づかせるべきなのでしょうか。基本的には以下だと考えています。

  • 目的を忘れないこと
  • コミュニケーションの大切さとその理由
  • 作ったものがどう使われるか想像する必要性
  • 日々の学習がなぜ必要なのか、危機感を持つこと

まずそれぞれについて「何に気づくべきか、なぜ気づくべきか」を述べ、次に「そのためにどのような機会を作るべきか」について述べます。

気づくべきこと

目的を忘れないこと

技術者とは技術のエキスパートであり、技術とは問題解決のための手段です。ゆえに技術者は問題解決のために自分の技術がどう活きるか、どんな技術をどう組み合わせるのかを考えなければなりません。 流行や新技術もいたずらに追うのではなく、なぜ今それが流行なのか・既存技術と比べての利点や欠点は何なのかを咀嚼し自分なりの解釈を作った上で日々の業務に適用していく必要があります。

もちろん技術は理屈抜きに面白いものですし、問題を解決するために技術を学び始めた人はむしろ少数派でしょう。
しかしプロとしてビジネスとしてお客様や課題と接する以上、なぜお客様は我々に対価を払っているのか?なぜチームは自分をここに置いているのか?を考えると、この「目的」が非情に重要であることは疑いありません。この意識こそがプロとアマの違いと言っても過言ではありません。

締切厳守、体調管理、報連相、例外系想定やBootlegging(スカンクワーク)も目的を考えることでその重要性を認識できます。

コミュニケーションの大切さとその理由

私の場合、チームの存在こそが仕事と趣味の大きな違いでした。サービス運用障害対応も自作ライブラリの保守や要望対応も趣味でやった経験がありますが、どれも個人で完結していたものでした。仕事にはコミュニケーションが必要不可欠であり、コミュニケーションこそが成否を決める要素であるという価値観はここから来ています。

また、ビジネスが多くの場合複数名で行われることも見逃せません。規模の違いはあれど、複数名が役割を分担するからこそ可能になること、1人では調達できない資源や時間を使ってこそ実現できることがビジネスです。
お客様は自分でもうまくできることには対価を払いません。自分ではできないこと、やれるかもしれないが最善手ではないことをプロフェッショナルに委ねるために対価を払うのです。それらは1人で解決可能な課題ではないことがほとんどでしょう*1

複数人数だからできること、それは作業の並列化・平行化そして専業化です。開発において、parallelとconcurrentが難しいことと役割の明確化が重要であることは、常識です。技術者がチームの存在意義を追求すると、必ずここに価値を見出すでしょう。そして自分がどの役割を担うべきか、他のメンバーにどう情報を渡すべきか、どう情報を取りに行くか、そして全員でビジョンと問題意識を共有するにはどうすればよいかを考えていくことになります。

作ったものがどう使われるか想像する必要性

「プロフェッショナルとアマチュアの最大の違いはねぇ、例外処理だよTODA君。」とは私の元上司の言葉です。私もこれに同意します。
学生のコードや新入社員のコードを見ていると、必ずといっていいほど、例外を握りつぶすcatchブロックに出くわします。なんでこんなことするの?と聞くと、ほとんど「IDEが補完したので」とか「えっ、どういう意味ですか?」とかそういう言葉が帰ってきます。事の深刻さがわかっていないのですね。本番環境でここに到達した場合に、どのようなトラブルになってしまうのか、という想像が働かないのです。

例外の扱いはそれだけでブログ記事が3-5本書けそうなくらい面白いのですが、ここではそれは割愛して良書にその役割を委ねることにします。例外のひき逃げ、すごい大切です。

コーディングの掟(最強作法) 現場でよく見る不可解なJavaコードを一掃せよ! (開発の現場セレクション)

コーディングの掟(最強作法) 現場でよく見る不可解なJavaコードを一掃せよ! (開発の現場セレクション)

例外だけでなく、ログも想像力の欠如によって悪い使われ方をされます。System.outが散らばっていたり、ループ内部でINFOレベルのログを出力していたり、肝心のメッセージが無意味で何の追跡もできなかったり。
ログのポリシーはチーム開発ではすごく重要ですが、その徹底と浸透は非常に難しいものです。最終的には各開発者の想像力に頼らざるを得ないことが多いでしょう。

日々の学習がなぜ必要なのか、危機感を持つこと

最近の新人を見ていて思うのは、勉強は得意なのに勉強を始めるのがものすごい苦手なんだな、ということです。課題を探すのが苦手っていうんでしょうか、授業や講義みたいな機会を与えられてはじめて勉強するって感じです。自発的に技術の道を歩み始めた自分からすると、奇妙そのものです。

日々の学習が必要な理由は、技術者であれば必ず知っています。技術は日々進歩し、陳腐化します。昔の常識が今の非常識になり、今の常識が未来のブレークスルーを邪魔します。また技術は手段であり、目的である「問題解決」のための業務知識も必要です。これもまた進歩し、陳腐化します。
学びに終わりはありません。海辺で砂山を作るがごとく、繰り返してはだめになり手法を確立してもなお他の方法を試すのです。

これは一見すると儚く滑稽かもしれませんが、2つだけ陳腐化せず変化しないものがあり、技術者はそれらを知っているからこそ儚い短命な技術を学習しつづけることができています。

1つ目は変化そのものです。ものは陳腐化する、変化する、という事実を受け入れてしまうことです。この事実を受け入れるチームとそうでないチームには、製品の質に大きな違いが出てきます。変える勇気、捨てる潔さを持って初めて製品は真に永く使われ愛されることができるのです。
2つ目は学び方の個性と熟練度です。砂山とひとくちに言っても、作り手によって頑丈さ・高さ・幅・数そして作る速さは大きく違ってきます。ある人はすばやく新技術の表層を理解して物を作ることができます。ある人はひとつの概念を深く理解し、それに立脚する新技術をすぐに自分の中に取り込みます。ある人はアンテナが高く、誰よりも早くその存在と背景を知ることができます。もちろん彼らにも拙かった時期もあったでしょう。学習を続けることで知識を蓄積し手法に熟練し、新たな技術への対応力を高めていったのです。ここにも継続の重要性が現れています。

どのような機会を作るべきか

以上で、経験の少ない技術者に対して

  • 目的を忘れないこと
  • コミュニケーションの大切さとその理由
  • 作ったものがどう使われるか想像する必要性
  • 日々の学習がなぜ必要なのか、危機感を持つこと

を気づかせることの必要性を説いてきました。ではどのようにしてその機会を作るべきなのでしょうか。

コードをレビューする

どなたが仰った言葉だったか、「ソースコードは1行1行がbusiness decisionだ」という考え方があります。まさにその通りで、コードの1行1行には技術者の想定、理想、目的意識が明確に現れます。足りない部分が如実に浮き上がるため、1対1での会話のきっかけを作るのにかなりふさわしい場です。

コードレビューというとバグを見つけたり命名やインデントに口を出す場と思っている方がいらっしゃるかもしれませんが、そういうのはもっと事前に機械的に行うべきものでレビューでやるのは非効率です。レビューでは拡張性、保守性、性能、運用可能性といったコードの行間や背景、全体像から見える問題に対して建設的な議論と改善を行うべきで、そのためには技術だけでなく業務想定や運用想定、イレギュラーへの対応といった知識と意識をチームで共有されている必要があります。逆に言うと、知識と意識が不足している技術者を察知する場として使えるということです。

ただしレビューでは気付きの場を作りきれなかったり、その効率が悪かったりすることもあります。その場合は別途1on1や雑談、教育的ペアプログラミング*2を実施すると良いでしょう。技術者同士、技術屋コードについて語り合う機会というのは間違いなく面白いですし、ぜひとも作っていきたいものです。

理想や存在意義について語る場を作る

ビジネスやチームの全体像が見えるには時間が必要です。会社規模と日常業務によっては、3年経ってもまだ見えないということもザラにあるでしょう。3年間もの長い間、仕事の基礎である知識と意識が欠落してしまうのは非効率です。理想像や存在意義を理解しない状態でそれをうまく利用したり改善したりするのは不可能だからです。

営業は案件をどう探して持ってくるのか?営業は何をしたいのか?コンサルは何がやりたくて開発とコンタクトをとるのか?その現状は理想的なのか?問題の根本はどこにあるのか……。
これは営業やコンサルを紹介して交流機会を作り探らせるよりも、さくっと資料作って説明してしまうのが早いようです。紹介するとしても組織構造やその背景を理解させてからのほうが、その後の交流の効率も上がります。新人が配属された直後というよりは、日常業務に慣れた半年〜1年後に実施するのが吸収が早いです。
これをやると、単純に「報連相重要!」とか言うよりもずっと報連相してくれるようになります。やはり理由を知らないと、儀礼やテクニックとしてしか見ることができず、真の実践は難しいのでしょう。

もちろんビジネスや問題解決といった大枠だけでなく、チーム・製品・運用・技術者などの理想を語ることも大切です。理想が共有されていない状態では、各個人がそれぞれの姿とプライドを持ってしまい助け合いがうまくまわりません。優れた技術者はアクが強いことも多く、プライドのぶつかり合いは互いを傷つけることになりかねません。
私の場合「理想のチーム像」を語ったことがありましたが、それからは各個人が自分の役割だけでなく他者の役割を理解して能動的に活発に動くようになりました。また「今のやり方では彼が溢れてしまう、私の時間の一部を彼のヘルプに割いて良いか」というようにマネージャ(私)の失敗を助ける動きもありました。これもマネージャのやり方、考え方がわからない状態では原因特定まで動かなかったり「何考えてるんだかアイツは」と見放して終わったりするケースが多いのではないでしょうか。
全員が同じものを理想とすることは不可能でも、同じ理想をビジョンとして共有することは可能です。そしてビジョンを共有するからこそ、各自が自分の役割を理解しまた他者を助けることもできるのです。部下がマネージャとしての視野・視点を持ってくれないと思ったなら、まず自分の考えを伝えてみても良いかもしれません。

継続的な学習の場を作る

自発的に学習しない人に対して、学習が足りないから土日に勉強してこい、というのは無理です。就業時間中に機会を作る必要があります。
時間を作るなら、出社直後30分から1時間くらいが良いでしょう。昼食後は眠くなりますし、夕方は差し込み案件やミーティングが入るかもしれません。それ以外の時間はせっかくの集中を阻害する可能性があります。朝なら差し込みもなく、また頭も最もすっきりしていますので丁度良いです。強制はできませんが、就寝前にちょっと復習するとベストかと思います。

勉強の内容は資格勉強でも良いですし、輪講、読書、講義、LT、発表、お客様を迎えてのヒアリング、何でも良いです。様々な技術が使われるチームでは、隔月で最近の自分の業務で使った技術をプレゼンさせても良いでしょう。チームの技術知識を底上げし、技術者の流動可能性を高めることにも繋がります。
大切なのは、最適なやり方は各個人で異なるということです。まずは習慣を作るべく一斉に行える輪講や講義から初めて、徐々に各個性に合わせたやりかたに分化させると良いのではと思います。

自発的に学習する人であれば、その人のアンテナに引っかからない情報や技術、ニーズを適宜渡してあげればいいでしょう。これは日頃の雑談でカバーできます。
「今君が学んでいるこの技術はね、今海外ではこういう使われ方をしていて、既存技術の課題だったあれを解決することでビジネスの可能性を一気に高めたんだよ」というひとことだけでもテクニカルなことしか見ていない人には面白く響きます*3。逆にビジネス面しか見えていない効率の悪い実装をしてしまう人には「なるほど、確かにこのアルゴリズムでは君がやりたいことが実現可能だね。でもここでこんなにメモリ食っちゃうね……先行事例ではどう解決したか調べた?」と言うだけで良いのです。

学習というのは、極論すると、未知との接触です。相手の普段の発想を理解してそれとは違う方向にあるものを提示し、相手がそれを咀嚼する機会と手順を整えれば、それで立派な教育になります。

もちろん上記の施策は学習の必要性を認識した後でないと意味がありません。またやり方を間違えるとウザい人になります。必要性を認識させ、やり方と環境を整え、耳を傾けてもらえるような信頼を得てはじめて成功する可能性が出てきます。
教育というのはそれだけ難しく、またそのコストを払ってでも実践すべきほど大切なものなのです*4

まとめ

以上で、経験の少ない技術者には気付きの機会として

  • コードレビューと、それを起点にした1on1
  • 理想や存在意義について語る場
  • 継続的な学習の場

を作るべきだという持論を展開しました。実際この2年間で使ってきて、実用性はそれなりに立証されてきたものです。「入社してから初めて技術に触ります」という人には未実践ですが。

こうした機会を作っても有効活用できない人はいますし、銀の弾丸ではありません。また私とは異なる技術者像・チーム像を理想とする場合はまた異なる手法を追求すべきでしょう。

*1:時間を切り売りするような職種は別かも

*2:本来の定義を離れて先輩が各種ツッコミを入れまくるペアプロ、ショートカットキーを知らなかったり「まず手を動かす」ことをしなかったりする人に最適

*3:なんで今まで無かったんですか?という質問に答える準備をしておきましょう

*4:とか書くとTODAさんは教育が好きなんだね、とか思われそうですが、逆です。やりたくないけど、やらないとチームの質が上がらず日々の仕事がつまらなくなるので、泣く泣くやらざるを得ないのです。 → http://blog.kengo-toda.jp/entry/2014/02/01/131321

How to migrate Java 7 with Guava to Java 8

$
0
0

replace Optional with java.util.Optional

  • replace import com.google.common.base.Optional; with import java.util.Optional;
  • replace Optional.fromNull() with Optional.ofNull()
  • replace Optional.absent() with Optional.empty()
  • replace Optional.transform() with Optional.map()
  • replace Optional.or() with Optional.orElse()

replace FluentIterable with Stream

upgrade Lombok project to the latest version

1.12.6 didn't work with Eclipse Luna in my case, and 1.14.2 was OK.

We've got married

$
0
0

We've got married at 1st/July/2014. Check my post at Facebook for detail:

I guess everyone has doubt about why we were bone. My answer for this question is creating and maintaining good family.

To achieve this goal, previously I only can focus on abstract milestones, like 'be better business person', 'be better team builder' or 'be better cooker'. But now I have clear and concrete milestone to achieve it: just make her happy. I believe that it's very good for our life.

Closure Library でカタいクラスを実装する

$
0
0

ここではカタいクラス=フェイルファストで、コンパイル時に問題を発見しやすく、かつ保守しやすいクラス と定義する。
基本的には goog.ui.Component あたりを読むと勉強になる。もちろんネームスペースでユーティリティメソッド群を実装する場合にも通じる。

goog.asserts.assert を使う

「ここではこういう理由からこういう状態であるべき」をコードで明記できる。例えばgoog.ui.Componentでは以下のようにして使っている。

/** * Similar to {@code getElementByClass} except that it expects the * element to be present in the dom thus returning a required value. Otherwise, * will assert. * @param {string} className The name of the class to look for. * @return {!Element} The first item with the class name provided. */
goog.ui.Component.prototype.getRequiredElementByClass = function(className) {var el = this.getElementByClass(className);
  goog.asserts.assert(el, 'Expected element in component with class: %s',
      className);
  return el;
};

@param, @type, @return で ! や ? をきちんと書く

Javaの人としてはundefinedやnullになりえる場合は明記したい。

JSDocで@param {?Object} object descriptionとすればnullになる可能性がある(nullを許容する)ことの明記になる。undefinedは{(Object|undefined)}とする。
逆に、nullになる可能性がない(nullを許容しない)場合は@param {!Object} object descriptionで良い。

@paramの場合は=を使って省略可能であることも明記できる。この場合、=の右側にデフォルト値を併記しておくとドキュメント生成に良い。

追記:はてぶコメントで指摘いただきました、stringはプリミティブなのでnullにはならないそうです。

@override の代わりに @inheritDoc を使えないか検討する

ドキュメントで説明すべき事柄がスーパークラスと同じ場合、@override の代わりに @inheritDoc を使うことでスーパークラスのドキュメントを使える。
Closure Library自身にもけっこうドキュメントが空っぽなメソッドがあるが、このタグを使えば解決できることが多い。

追記:はてぶコメントで指摘いただきました、deprecatedになっているそうです。

@typedef とRecord TypeでPlain Objectの中身について型情報を明記する

Record Typeを使うと、Plain Objectの中身(プロパティ)について名前と型情報を明記できる。Plain Objectを使いたい、値を表すクラスを作るまでもないケースで有用。

同じPlain Objectを使うメソッド複数ある場合、JSDocをコピペするのではなく、@typedefで型を定義すると良い。例えば goog/fs/fs.js には2メソッドを持つPlain ObjectがUrlObject_として定義されている。

/** * @typedef {{createObjectURL: (function(!Blob): string), *            revokeObjectURL: function(string): void}} */
goog.fs.UrlObject_;

XxxLike を理解して使う

JavaScriptでよくある「ArrayみたいだけどArrayじゃないモノで、だけどArrayとして使える」オブジェクトをXxxLikeと表すのがClosure Library流っぽい。Array等を扱うメソッドで代わりにこれらを使うようにすると、カタさを保ちつつ柔軟性を上げられる。

  • goog.array.ArrayLike
  • goog.date.DateLike
  • goog.events.EventLike
  • goog.net.XhrLike

ちなみに goog.dom.isNodeLike() というメソッドもあるが型として定義されているわけではない。

ツールをちゃんと使う

省略。別途資料等を参照。

memo: Non-blocking I/O on JVM

memo: JavaScript AST


最近読んだ本

$
0
0

今日は日曜日ですが中国では出勤日です。国慶節に向けて休日の移動が発生しているのですね。

さて最近読んだ本の紹介です。電子書籍中心の生活をしていますが、これらはまだ紙の本での入手でした。こういう本も電子化されると、私みたいに海外で暮らしている人には嬉しいのですが。

心の筋トレの話、モチベーションの話、ブランドとミッションの話が面白いです。チームと働く上でどうモチベーションを上げてもらうか・どういう発想を持ってもらうかというのが大切なのは常日頃実感していて、それが経営のレベルになってもそんなに変わらないのかなという印象を受けました。 あとはサービス業であっても経営者の仕事は環境づくり・気付きの機会づくりがほとんどなのだなぁと。店長や店員に動いてもらう・考えてもらうためにどう伝えるかに腐心する話とか。自分の場合だと、日本企業の持つイメージと自分の企業の実際のギャップをチームメイト(全員外国人)に認識してもらいつつ、自分の企業の特徴をうまく活かした自己成長を想像し目指してもらうことが第一の課題なわけですが、今悩んでいることが40年後にも活きるのだと思うとすごく良い成長の機会を与えられているのだなと実感します。

おいしい穀物の科学 (ブルーバックス)

おいしい穀物の科学 (ブルーバックス)

「コメは粒のまま食べるのに、コムギは粉にするのはなぜか?」なんて考えたこともなかったし、その裏に科学的合理的な理由があるとは!トウモロコシは実が包まれていて鳥害に強い上に運搬も楽だから山岳地帯にも向いているとか、普段目にしているものが長年選ばれてきた理由や人との関わりの中でどう姿を変えてきたかとか、雑学を超えた面白さがあります。

特に興味深かったのは、コメの利用には土器の誕生が強く関係しているという話。加熱にも食事にも必要ですものね。縄文時代から土器・青銅器・鉄器などの器・道具が発達してきていて、それが農耕の生産性に寄与してきたのは知っていましたが、そもそも植物の摂食利用に必要だったのですね。学校で歴史を学ぶときにこういうことを知っていると、なぜそんなに土器や貝塚について学ぶのかをもっと深く理解できたように思います。 他にも竹を使い捨て食器として使える(土器のような器を必要としない)地域があり特殊な文化が育ったとか、コメは集落を作りやすいとか、稲はなぜ田植えするのかとか、コムギを中心とするには石臼が必要で定住向けだとか、なるほどなぁと思わされるものが多かったです。

朝に効く薬膳 夜に効く薬膳

朝に効く薬膳 夜に効く薬膳

引き続き薬膳を学んでいますが、すごい単純に言うと旬のものをまるごと食べなさい(一物全体・身土不二)に集約されるようです。雨が多い時期には水分を出す食べ物が旬を迎えるし、乾燥する時期には喉や肺を潤す食べ物が市場に出回るので、適宜それを取りなさいねと。 喉が乾燥していた時にレストランでなんとなく梨のジュースを選んで、あとで梨の効能を調べてふーんと思う時もありましたので、食べ物の効能については知識以前に本能や経験のレベルで理解しているのかもしれません。

健康状態の診断と改善に五行とか気血水とか考えられるようになるとまた違ってくるのでしょうが、そこまで大きく体調をくずすこともなく健康に暮らせているので、しばらくは活用の機会はなさそうです。

詳説日本史研究

詳説日本史研究

教科書ですね。オビに「大学受験に必携」って書いてあります。

海外で暮らして「外国人」の女性と結婚して、やっぱり日本人であることや日本の歴史を見なおす機会は増えています。最近興味深かったのは、日本では「終戦の日」「原爆の日」として認識・報道している日が中国では「ポツダム宣言の日」として報道されていたことで、当然ながら立場によって見方も認識も違うのだなぁということを再認識した次第です。

この本では日本の歴史について再度学んでいて、鎖国時の出島の役割について奥さんに話す際に参照したりしました。頭から読み進めるというよりは、適宜参照する使い方をしています。

日本の起源 (atプラス叢書05)

日本の起源 (atプラス叢書05)

まだ頭しか読んでませんが、天皇の起源や権力者同士の争いについて様々な説が紹介され楽しめています。「穀物の科学」で読んだコメの生産性が集約労働であがることやコストをかけるだけ収量を増やせることと合わせて読むと、当時の権力者の闘争にリアリティを感じることができます。

あと歴史の専門家が話しあうという形をとっていて、資料や説から一歩引いてそれらを俯瞰する立場で話が展開されているのが素敵です。歴史は勝者によって都合が良いように書き換えられるそうですが、そうしてできた資料をただ紹介するだけでなく「これこれこういう背景があったからこういう書き方をしているのかもね」という話をしてくれるので、知識のない素人でもいろんな見方が楽しめます。

最近読んだマンガ

$
0
0

まさかの2巻発売ということで、早速Kindleで入手しました。シャーリーがカフェに行く話が一番お気に入りです。大人が仕事をしている姿というのは素晴らしいものです。

長時間かけて書かれた本ということで、絵柄がかなりばらついているのですが、それでも同じ作家さんによる一連のマンガとして楽しめるのが不思議です。

俗に言う日常系四コマなのでしょうが、主人公が喋らないことによって人間模様が濃く描写されている印象です。肩の力を抜いて読めます。

Helck 1 (裏少年サンデーコミックス)

Helck 1 (裏少年サンデーコミックス)

なんか久々にすごいのが来た気がします。オンラインで最初の数話と最新話が読めるのでとにかくお試しを。

中国では技術力のある国・先進的な国として、よくドイツの名前を目にします。しかし私はドイツの実際はほとんど知りません。また国際結婚固有の問題に共感するところもあり、両方の意味から楽しみに読みました。

読後にもうちょっと内容があってもいいのではと思いましたが、このページ数だと仕方ないのかもしれません。

孔明のヨメ。 (1) (まんがタイムコミックス)

孔明のヨメ。 (1) (まんがタイムコミックス)

どこまで史実でどこまでフィクションかわかりませんが、ひとつのマンガとして楽しんでいます。3巻4巻がまだ未入手なので近々。

memo: RabbitMQ

$
0
0

TODO

  • 2回以上実行される可能性(結果報告前にConsumerが落ちる,タイムアウト etc.)と、そのために必要な設計(INSERT処理のみにする=更新・インクリメント処理は避ける etc.)
  • キューを作り分ける意味とその狙い。例えば動的スケールするべきキュー(即実行すべきJob)と処理が遅延してもよいキュー(永続性を優先すべきJob)に分ける?

Reference

goog.ui.Componentの継承で気をつけるべきこと一覧

$
0
0

基本

インスタンスの状態

  • クラスフィールド(static変数)にインスタンスの状態を入れない。
  • インスタンスフィールドはprivateにする。
  • 親クラスのフィールドには触れない。

DOM要素の操作

  • DOM要素を指定する際にはIDではなくclassやカスタムdata属性などを使う。
    • IDは、コンポーネントが画面に常に一つしか存在しないことを保証できる時のみ利用する(1つの画面に2つ以上同じIDを置けないので)。
    • Closure Libraryはclassによる要素検索メソッドを多数提供しているので、classを使うことが望ましい。
  • 自分自身のDOM要素に含まれるDOM要素のみ触ることが望ましい。

メソッドで気をつけること

コンストラクタ

  • 必ずgoog.base(this, opt_domHelper)する。DomHelperは省略して良いが、引数で受け取る癖をつけて統一感を持たせる。
  • この時点ではDocumentに入っていない状態かつ自分自身のDOM要素がない状態。DOMの更新は控える。
  • コンポーネントインスタンスは極力この時点で作成する。あるいはコンストラクタ引数として受け取る。
  • this.addChild(childComponent)は親子でライフサイクルを統一するためにも効果的。これによって自身がdisposeされたタイミングで自動的に子コンポーネントもdisposeされるようになる。何らかの理由によりthis.addChild()できない場合はthis.registerDisposable(anotherComponent)しておくと良い。
/** * @constructor * @extends {goog.ui.Component} * @param {goog.dom.DomHelper=} opt_domHelper */
my.ui.Component = function(opt_domHelper) {
  goog.base(this, opt_domHelper);
  this.addChild(new my.ui.ChildComponent(this.getDomHelper()));
};
goog.inherits(my.ui.Component, goog.ui.Component);

createDom()

  • 必ずthis.setElementInternal(element)する。
/** @override */
my.ui.Component.prototype.createDom = function() {var element = this.getDomHelper().createDom(goog.dom.TagName.DIV, {'data-foo': 'bar'});
  this.setElementInternal(element);
};

canDecorate()

  • decorateできるDOM要素に制限がある場合は、ここでそのチェックを行う。
  • falseを返した時のエラーメッセージ(goog.ui.Component.Error.DECORATE_INVALID)は汎用的なものなので、decorateに適さない理由をデバッグログに出しておくと良い。
/** @override */
my.ui.Component.prototype.createDom = function(element) {return element.tagName === goog.dom.TagName.DIV;
};

decorateInternal()

  • 必ずthis.setElementInternal(element)する。またはgoog.base(this, 'decotateInternal', element)でも良いが、特に親クラス実装を呼び出す必要性はない。
/** @override */
my.ui.Component.prototype.decorateInternal = function(element) {this.setElementInternal(element);
};

enterDocument()

  • まずgoog.base(this, 'enterDocument')してから、自クラス固有の処理を行う。
  • goog.base(this, 'enterDocument')は必ず呼び出すこと。
  • イベントのlistenはgoog.events.listen()ではなくthis.getHandler().listen()によって行う。これによってexitDocument時に手動でunlistenをする必要がなくなる。
/** @override */
my.ui.Component.prototype.enterDocument = function() {
  goog.base(this, 'enterDocument');
  this.getHandler().listen(this.getElement(), goog.events.EventType.CLICK, function(event) { ... });
};

exitDocument()

  • まず自クラス固有の処理を行ってから、goog.base(this, 'exitDocument')を呼び出す。
  • goog.base(this, 'exitDocument')は必ず呼び出すこと。
  • enterDocument時に自身や他のオブジェクトに加えられた変更があれば、これを巻き戻す。ただしthis.getHandler().listen()で作成されたイベントハンドラは親クラス実装で自動的にunlistenされるので気にする必要はない。
/** @override */
my.ui.Component.prototype.exitDocument = function() {// do some operation if we need

  goog.base(this, 'exitDocument');
};

disposeInternal()

  • まずgoog.base(this, 'disposeInternal')してから、自クラス固有の処理を行う。
    • 自クラス固有の処理を先に行うとdispose()実行時に、自クラス固有のdisposeInstance→自クラス固有のexitDocument→親クラスのexitDocument→親クラスのdisposeInstanceの順に時に処理が行われることになり、exitDocumentがdisposeInstanceに遅れて実行されてしまう。
  • goog.base(this, 'disposeInternal')は必ず呼び出すこと。
  • インスタンスフィールドにある他のオブジェクトへの参照をnull代入あるいはdelete演算子により断ち切ること。
  • this.isDisposed()が真かどうかは気にしなくて良い(偽であることを前提にして良い)。dispose()がthis.isDisposed()が偽の時のみdisposeInternal()を呼び出してくれる。
/** @override */
my.ui.Component.prototype.disposeInternal = function() {
  goog.base(this, 'disposeInternal');

  // do some operation if we need};

getContentElement()

/** @override */
my.ui.Component.prototype.getContentElement = function() {returnthis.getRequiredElementByClass('container');
};

継承してはいけないメソッド

  • setElementInternal()
    • JSDocに Considered protected and finalと明記されている
  • dispose()
    • 代わりに disposeInternal() を継承する
  • decorate()
    • 代わりに decorateInternal() を継承する
  • render(), renderBefore()
    • 代わりに createDom() を継承する
  • その他、継承する必要がないもの(ドキュメントには明記されていないが、これら標準実装に手を加える必要性はないものと思われる)

参考資料

  1. goog.ui.Component のはぐれかた
  2. Component (Closure Library API Documentation - JavaScript)
  3. IntroToComponents - closure-library - Introduces goog.ui.Component - Closure Library - Google Project Hosting

Intel Edisonを購入した

$
0
0

Intel Edison Breakout Board Kitを淘宝网にて515人民元で購入。当然ながら技適マークは無いです。

まずは以下を試験実施。

wget, python, node が動くことを確認。

翌日起動したところ *** Ready to receive application ***から進まなくなった(U-Bootが起動しなくなった)のでここを参考に再インストール。

$ brew install dfu-util coreutils gnu-getopt
$ cd edison-image-rel1-maint-rel1-ww42-14
$ ./flashall.sh
Using U-Boot target: edison-blank
Now waiting for dfu device 8087:0a99
Please plug and reboot the board
Timed out while waiting for dfu device 8087:0a99
DEBUG: lsusb
./flashall.sh: line 77: lsusb: command not found
DEBUG: dfu-util -l
dfu-util 0.8

Copyright 2005-2009 Weston Schmidt, Harald Welte and OpenMoko Inc.
Copyright 2010-2014 Tormod Volden and Stefan Schmidt
This program is Free Software and has ABSOLUTELY NO WARRANTY
Please report bugs to dfu-util@lists.gnumonks.org

Did you plug and reboot your board?
If yes, please try a recovery by calling this script with the --recovery option

DFUデバイスとして認識されていない。--recoveryはOSXで使えないので対応を考える。

Windowsマシンに切り替えて再接続すると、特に苦労なく2つのLEDが点灯し起動完了。OSXとの相性問題?flashall.shのサポート状況を見ても、開発にはLinuxWindowsを選択したほうが無難だろう。

と、思っていたらWindowsが起動しなくなった。ドライバ入れたから?OS再インストールが必要そう。OSXでは相変わらず。

Windowsは(MacBook ProのBootcampで動いているので)パラメータRAMのリセットを行うことでOSXが起動するように。念の為OSXを最新にあげて再挑戦したところ、とりあえずWindowsは起動した。USB接続で2つのLEDが点灯することも確認済み。

Tips to accelerate your original game

$
0
0

To make your game more interesting, you should pay much attention to keep high performance. This is UX problem, but it is not designer who can solve. Only developer has solution for this problem, so we should learn about when we face problem and how many approaches we have.

Reducing I/O

Cache

This is popular tip for background-image, map-chip and character-chip.

Load picture and draw it onto cache on RAM, then you do not have to access to storage. For instance, your STG may load background-image when player decided the stage to play. By this cache, your STG does not have to read storage for background image during this stage.

Lazy-loading

In previous case, your STG needs to lock screen while it loads resources onto RAM*1. It's better to shorten this time, or player will feel that your game is boring.

To reduce locking, lazy-loading can be solution. At initialising phase, your STG does not have to load background-image of boss-stage. Postpone loading, then you can shorten the lock.

Pre-loading

Here is another and opposite solution. While player is choosing stage to play, your STG can load resources onto RAM. When player decides stage, necessary data is already loaded so you can start game immediately for player.

To use this tip, programmer should understand player's need and how they control your game. For instance, when player enters stage-select page, your STG may load SE (Sound Effect) of shooting action because you knows that player will choose stage so your STG should load such resources later. I think this is similar to implementing recommendation engine.

Are you implementing HTML5 game? If so, you may try pre-fetchAPI.

Reuse drawn picture

During user plays your STG, you should draw background-image and scroll it from right to left. So in each frame you should draw large picture, it costs resource of player's computer.

To reduce this cost, you can reuse background-image which is already drawn. You shift background-image some pixels, and draw only the right part. You can reuse almost all of drawn picture, and focus on drawing new parts.

Here is another example: even though you are implementing 3D game, you do not have to compute 3D models in each frame, because you can store computed images to RAM and use it instead.

Put multiple resource into one file

This is popular tip for map-chip and character-chip. And this is also very famous for web developer as CSS Sprites. Data URI also can be solution.

By this tip, you can reduce number of resource to load. So it's effective especially when resource is far from player. Learn latency for detail.

Compress data

You may like raw data format like BMP format, but when you publish your product it's better to use compressed format. Then you can reduce data size to load, so it will reduce time to load. Learn Throughput for detail.

To compress data, your may use ZIP or other format. It's OK but please remember that decompression costs machine resource.

Reducing computing cost

divide main-loop and loop-to-render

When you implement graphical game, you should have main-loop like below:

function main(){
  compute();
  render();
  setTimeout(main, 15); // about 60 FPS}
main();

It works, but it has one problem.

This code tries to render image 66.6 times per second, but in my environment 6 of them has no meaning because we render twice or more between 2 display refresh. You can try it at this page.

It means that we render needless picture 6 times per second... it should be stopped.

var previousTimeToRender = 0;
function tryToRender(){var now = Date.now();
  if (now - previousTimeToRender > 1000/60) {
    previousTimeToRender = now;
    draw();
  }
  requestAnimationFrame(tryToRender);
};

function main(){
  compute();
  setTimeout(main, 1000/60);
}

main();
requestAnimationFrame(tryToRender);

Looks too complex? Then capsule it:

function Renderer(fps) {this.fps_ = fps;
  this.previousTimeToRender_ = 0;
  this.callback_ = null;
};
Renderer.prototype.tick = function(){var now = Date.now();
  if (now - this.previousTimeToRender_ > 1000/this.fps_) {this.previousTimeToRender_ = now;
    this.callback_();
  }
  requestAnimationFrame(this.tick.bind(this));
};
Renderer.prototype.register = function(callback){this.callback_ = callback;
  this.tick();
};

// then you can code like below:function main(){
  compute();
  setTimeout(main, 1000/60);
}
main();
var renderer = new Renderer(60);
renderer.register(render);

And if we can reduce FPS to draw without UX problem, it's also good way to improve performance.

var renderer = new Renderer(30); // draw 30 times per seconds. we can keep computing 60 times per second.

Algorithm

Algorithm is very important to implement game. Routing, Z-sort, collision detection, AI... there are a lot of algorithm used in game. Brute-force is acceptable during development, but before you publish your game, it's better to consider to replace it with efficiently implementation.

This is too large topic for this article, so I just list up sample codes:

Now I'm interested in Simulated Annealing, I'll try to code a simple one.

*1:you may know that some PSP games display 'LOADING...' again and again

goog.Promise の使い方

$
0
0

日本語情報少ないので。

Promiseとは?

こちらをご覧ください。

Promiseオブジェクトを作る

newを使ってコンストラクタを呼ぶだけです。このとき、引数に関数をひとつ渡してやる必要があります。この関数はresolve関数とreject関数を受け取るので、関数内で

  • 処理成功時は resolve
  • 処理失敗時は reject

を呼んでやる必要があります。それぞれ引数に値をひとつ渡すことができ、他の処理に結果を受け渡すことができます。

var promise = new goog.Promise(function (resolve, reject) {if (...) {
    resolve(result);
  }else{
    reject(err);
  }});

コンストラクタ引数は無名関数ではなく、メソッドあるいはローカルな関数として定義しても良いですね。公式ドキュメントではresolverと命名されています。

function resolver(resolve, reject) {if (...) {
    resolve(result);
  }else{
    reject(err);
  }}var promise = new goog.Promise(resolver);

成功時の処理を書く

var promise = new goog.Promise(resolver);
promise.then(function(result) {// resolve() の引数に渡した値をここで使える
  console.log(result);
});

失敗時の処理を書く

var promise = new goog.Promise(resolver);
promise.thenCatch(function(err) {// reject() の引数に渡した値をここで使える
  console.log(err);
});

必ず実行したい処理を書く

var promise = new goog.Promise(resolver);
promise.thenAlways(function() {// リソース解放など});

合わせ技

thenなどのメソッドは自分自身を戻り値として返すので、メソッドチェーンが可能です。

var promise = new goog.Promise(resolver)
  .then(displayDialog)
  .thenCatch(displayAlert)
  .thenAlways(unlockSubmitButton);

Promiseの合成

静的メソッドとして、以下3種類が用意されています。

  • goog.Promise.all(promises)
  • goog.Promise.firstFulfilled(promises)
  • goog.Promise.rase(promises)

allはすべてresolveされた時のみresolveされるものです。thenにはすべてのPromiseの結果が配列に入れられて返ります。必要なリソースを並列で用意するときに利用できるでしょう。ES6のやつと同じです。

goog.Promise.all(assetLoader, dataLoader, calculator)
  .then(function(result) {var asserts = result[0];
    var data = result[1];
    var computed = result[2];
    doFoo(asserts, data, computed);
  });

firstFullfilledは、最初にresolveされた結果を返します。ひとつでもresolveされたら合成後のPromiseはresolvedになります。すべてrejectされたときのみrejectとなり、thenCatchが呼び出されます。同じ資源を複数の経路で準備できる際など、ひとつでも成功すれば良い・最も早く取得できた結果を使えれば良い時に利用できるでしょう。

goog.Promise.firstFullfilled(loadDataFromCDN, loadDataFromServer)
  .then(function(data) {
    doFoo(data);
  });

raseは最初にresolve/rejectされたPromiseの結果を返します。ES6のやつと同じです。

goog.resultとgoog.async.Deferred

これらは非推奨と明記されています。新規の利用は控えましょう。

  • NOTE: goog.result is soft deprecated - we expect to replace this and
  • {@link goog.async.Deferred} with {@link goog.Promise}.

When/How to use goog.ui.Component#makeId()

$
0
0

goog.ui.Component#makeId() is a helper function to generate ID for DOM elements. Let's start discussion based on sample component which contains following DOM:

<form><div><inputtype="text"></div><buttontype="submit"></form>

To implement createDom() method, we may need to decide ID for each element. And of course each of them should be unique in the document.

How you'll solve this problem? Use random value as ID? Or create counter to use sequential value? It looks troublesome.
So it's time to try makeId() method! It will use goog.ui.IdGenerator as counter to generate sequential value, and generated ID starts with ':' so it will not conflict other hand-made value so easily.

/** @override */
jp.skypencil.Component.prototype.createDom = function() {var domHelper = this.getDomHelper();

  var $input = domHelper.createDom(goog.dom.TagName.INPUT, {
    type : 'text',
    id: this.makeId('input') // will return a string like ':1.input'});
  var $div = domHelper.createDom(goog.dom.TagName.DIV, {
    id : this.makeId('div') // will return a string like ':1.div'}, $input);
  var $button = domHelper.createDom(goog.dom.TagName.BUTTON, {
    type : 'submit',
    id : this.makeId('button') // will return a string like ':1.button'});

  var $form = domHelper.createDom(goog.dom.TagName.FORM, {
    id : this.makeId('form')  // will return a string like ':1.form'}, $div, $button);
  this.setElementInternal($form);
}

getElementByFragment() helps you to get Element easily

Here is another merit to use makeId(); you can get Element instance simply like below:

var $button = this.getElementByFragment('button');

Stay away from setId() and getId()

goog.ui.Component also has setId() and getId(), but this is not for handling id attribute of DOM element. This is for handling Component-ID will be used to maintain component tree.

It is not necessary to keep Component-ID and DOM element ID same. I recommend you to stay away from these 2 methods, you do not have to care about component tree handling (it's responsibility of closure-library!).

Reference

The Art of Enbugging

$
0
0

I've read The Art of Enbugging (PDF) by Andy Hunt and Dave Thomas.

This is little long, but good article to share your topic with teammate. If you're trying to improve maintainability of your product, it will help your communication.

I feel that "The Paperboy and the Wallet" is good example, we can feel what is wrong and understand how to solve. I agree that Law of Demeter for Functions is good to keep software easy to maintain.

And, about "Shy". I know that a lot of developers are shy, this should become good metaphor to tell for beginners.

7年働いた時点での私の仕事の極意

$
0
0

最重要

  • 実行に重きを置く
    • やらないで後悔するよりも、やって反省する。
      • 反省は成長を産み生産的だが、後悔は精神の無駄な消費。
      • 時間は有限で貴重な資源だが、たぶん今の段階では行動する前に得るものや結果を予測するのは難しい。
    • 正しい反省の方法とは何か、考え続けること。
      • 「正しく反省するために、何を記録しておくべきか」実行前に明らかにしておくこと。
      • 反省の結果は組織的な何かに落としこむ。組織構造、戦略、静的解析、自動テスト、教育など。意識しないでも巨人の肩に乗れる状況を作ることが、組織の成長につながる。
    • Done is Better Than Perfect
      • ただし、思考停止の言い訳にしないこと。詰めの甘さを擁護する言葉ではない。詰めの甘さは立場や考え方が違うひと3人くらいに意見を求めればだいたい炙り出せる。
      • 長期的視野を持ちつつ、それに引っ張られない。進展を作ること、現状を少しずつ変えることを意識する。
    • 「やる内容」ではなく「たどり着くべき結果」が大切だということを忘れないために、問題の特定と問題解決の実行にフェーズの概念を持ち込む。やりたいから仕事をやるのではなく、解決するにはこの仕事をやるべきだからやる、ということをチーム全員で意識する。
    • いつでも行動を取れるよう、自己を印象づけておきつつ周囲との繋がりを育てておく。
      • ひとりで完結する仕事はない。

人との交わり方

  • 推測の扱い

    • 議論の仮説にできる「建設的な推測」と根拠の無い「不安や期待」を分けて扱う。
    • 議論の仮説はあくまでも「仮説」であり、「前提」ではない。状況に応じてアップデートされるべき。
    • 不安や期待は上司あるいは信頼できる人に1on1で話す。それ以外の人と場所には話さない。マネジメントに限らず後輩を持つ身なら意識したい/させたいポイント。
      • 不安はコミュニケーション不足を表すシグナルであることが多い。
  • ヒューマンスキル

    • という、横文字に惑わされないこと。「みんなが幸せ」になるにはどうするか考えて行動しようという話。それだけ。
    • 「幸せの定義」「何をもって満足するか」「情報の非対称性」「優先度の違い」「面子」「私生活」などなど様々な変数が絡むのでわかりにくくなる。
      • 目的意識がバラバラだと「みんなが幸せ」という絵を描けなくなる。ヒューマンスキルの前提にはプロジェクトマネジメント、チームビルディングがある。
      • 情報の非対称性は人間が複数集まった時点で当然生じるので、情報を取りに行ったり率先して提供したりセルフブランディングしたりする必要がある。
      • セルフブランディングの理想は「あの人なら問題を解決してくれる」。機能を切り口にする「XXならなんでも分かる人」は次点。
      • 個人に敬意と関心を持つこと。個人を知らないことがチームビルディングのミスを誘発する。
    • 私は年上・目上に対して(本人にその気はないのに)面子を潰しに行く傾向にあるので自重する。日本人に対するコミュニケーションが下手だ(要らん遠慮をする)という説もある。

エンジニアとしての心構え

  • 技術的・ビジネス的な流行り廃りとのつきあいかた

    • 跳びつくのではなく、それが生まれた歴史的背景を考える。
    • その背景を自分たちが共有しているか?を落ち着いて判断する。ウリ文句には多分にポジショントークが含まれることを覚えておく。
    • どうしても跳びついてしまう人は存在する。たぶん経験の差で、デザインパターンを何にでも適用しようとするのと同じ。モチベーションを削がずに再考を促す方法は、まだ見つかっていない。
  • 武器を増やすための研究は個人で、武器を磨くための追求は仕事で

    • 課題はそれの解決に必要な武器を教えてくれない(教えてくれたとして、それからキャッチアップしているのでは遅いことがしばしば)。仕事が始まる時点で武器を知っているために、予め広い視野を持って武器を増やしておく。
      • JVMは数少ない「教えてもらった」武器。新人にはOJTでも良いので、何かひとつは渡すようにする。責任を持たせることにも繋がる。
      • ASM, Findbugs, AMD (RequireJS), Maven, Grunt, SLF4J, npm, CI, OOP, FP は自ら研究しておいたことで業務においてリードする立場になれた。
      • LLVM, GAE, Vagrant, PMD, Chef はまだ役だってないが、考察のための視野を育む上で役立った。
      • enchant.js, Travis CI, Golang, Android, Intel Edison については今のところ全く役立っていない。百発百中である必要はない。
    • 深い理解や応用は要求によって育まれる。個人で作れるツールやライブラリとは比べ物にならない要求と資源(時間)を、業務では使うことができる。
    • 重要なのは、この原則を他人に求めないこと。すべて仕事で完結させるのも正しい選択で、だから教育や自動化(人手の排除)が必要。
  • 目指すべきは専門家でも何でも屋でもない

    • エキスパートになることで、組織の部品として問題解決の手段として使いやすくなる。問題を持ち込まれやすくなる=活躍の機会が増える。
    • 何でも屋になることで、問題の本質を見抜き迅速な解決が可能になる。問題を発見したり、切り分け前の問題を持ち込まれやすくなる。
    • 真になるべきは、周囲のやる気と関心を引き出しチームとしての問題解決に貢献できる人。エキスパートとしての自分や何でも屋としての自分は道具であり手段。時には他のエキスパートにdispatchしたり、他の何でも屋に意見を求める。
  • 「技術できます」と言ってしまう

    • 自分を超える超級エンジニアが山のようにいらっしゃることをわかった上で、あえて「技術できます」と言う。
    • ”技術できる”の定義なんて存在しないので気にしない。”技術に詳しいらしい”ということを知ってもらうだけで、組織に貢献できる機会は増える。沈黙や謙遜は個人の美徳であって、チームや組織にはリターンがない。
      • ヒューマンスキル上のリスクはある。またビジネスがわからないのではという不安を持たれるので、行動で示していく。

マネジメントとしての心構え

  • とにかく聞いて話す

    • 日本人とは飲み会、中国人とは昼ごはん、というのが今のところの経験則。業務の枠を超えないと業務を向上させることはできない。
    • 自分がどう成長したいかわかっていない人がほとんどなので、3-6ヶ月かかっても良いから1on1を通じて意識を作っておく。
  • 組織として目指しているのはどこか、チームとして目指すべきはどこかを明確にする。他のチームの目標と現場も可能な限り伝える。

    • 「自分には何ができるか?」常に考えてもらう。
      • 例)Stand-up Meetingは報告の場ではなく共有の場であり、共有された問題に対して動くべきは自分であると認識させる。
  • 戦略とビジネスモデルはシンプルであるべき

    • 判断基準となるこれらは、シンプルでなければ使いまわせない。
    • 今やっているタスクが技術的に特異なことであればあるほど、基本となる「目標」を意識すること。

被マネジメントとしての心構え

  • 要求を明確に上げる

    • 「〜だったらいいな」「〜なのは嫌だな」ではなく「XXという問題がありYYで解決したいのでZZをください」と言う。「AAな理由がわからないのですが、BBなのでしょうか」と理解を確認するのも可。
    • 私の場合「仕事がつまらない」と感じたら即座に「何をやるべきと考えているか」伝えるべき。すぐに自分が思っている以上のパフォーマンス低下が出る。
  • 自分で判断せず、判断基準を提供する

    • 高台にいる人のほうが視野が広いのは当然。高台にいては見えないこと、自分だからわかることを論理的に言語化して伝える。論理的でないと、マネジメントが他のマネジメントや上司に伝えられない。
    • 判断はマネジメントに下してもらい、その判断に意見はしても文句は言わない。文句があるなら自分でマネジメントする。
  • 目標を求める

    • 目標が与えられずタスクだけ降ってくる状況は、中長期的に見てまず良いことがない。
    • 結局何をやることが顧客のため組織のためになるのか、マネジメントに考えさせる。マネジメントをマネジメントする。
  • 「マネジメントがXX(技術、自分、状況 その他)を分かってない」と言うのは非生産的

    • マネジメントにわからせろ!
    • マネジメントがそれをわかっていないのは、マネジメント個人の問題ではなく組織構造や自分の情報の扱いに起因する問題であるとも考えられる。

まとめ

  1. 実行せよ
  2. 正しく実行するためには、実行の目標とプロセスに関心を払い、役割を正しく演じよ
  3. 個人と組織の成長を促すため、常に会話し、顧客や仲間を幸せにし続けよ

Gitbook v2.0.0で日本語書籍を書くときの落とし穴と回避策

$
0
0

Gitbookの多言語対応はまだ弱く、日本語で書籍を書く際はいくつか対応が必要です。 しかし文字化け等はないため、Markdownに慣れている人であれば充分に活用できる製品になっていると思います。

文中の意図せぬ空白

文中の改行が空白に変換されてしまうため、段落をすべて1行で書ききる必要があります。

下記プラグインで対応可能のようですが、利用時に警告が表示されます。折り返し表示可能なエディタを利用したほうが良いかもしれません。

github.com

GLOSSARY

用語集は半角空白で区切る言語のために設計されています。つまり半角空白で区切られた単位を「単語」として認識し、自動的にリンクを追加するような仕組みになっています。

このため、日本語のような単語間に空白が入らない言語の場合は、分かち書きをしないと使えません。 例えば「りんご」という言葉を用語集に追加する場合、本文には

りんごの木があり、りんごの実が3つなっていました。

ではなく、以下のように半角空白(あるいは改行)で単語を挟んで記述しなければなりません。単語が句読点の後に来る場合も、半角空白(または改行)が必要です。

#半角空白で「りんご」を挟む
りんご の木があり、 りんご の実が3つなっていました。
#改行でも良い
りんご の木があり、
りんご の実が3つなっていました。

How to upgrade Jenkins plugin to support latest LTS (1.596)

$
0
0

Today I've updated my Jenkins plugin, to support latest LTS version.

This article will explain what we should do to support latest LTS Jenkins.

Write dependencies on other plugins explicitly

Previously some core features were bundled in Jenkins core, but now they are independent plugins. If you need features of them, you should write dependencies in pom.xml.

<dependencies><dependency><groupId>org.jenkins-ci.plugins</groupId><artifactId>junit</artifactId><version>1.3</version></dependency><dependency><groupId>org.jenkins-ci.plugins</groupId><artifactId>mailer</artifactId><version>1.10</version></dependency>

See also: Dependencies among plugins - Jenkins - Jenkins Wiki

Replace deprecated API

API which is annotated with @Deprecated should be replaced with recommended API. Check Javadoc and implementation of deprecated method, then you can find how you should replace.

In my case, I had to replace following API:

About how to use JenkinsRule, please see Unit Test - Jenkins - Jenkins Wiki.

Add <repositories> and <pluginRepositories> to pom.xml

To pass build on buildhive, we need to add both of them to pom.xml.

Viewing all 157 articles
Browse latest View live