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

Gradle Plugin実装の基本

$
0
0

Gradleは動きが早いのでTIPSを文書化する意味があまりないのですが、全体像をざっくりつかめるだけでも変化を追うには有用のはず。 そのうち体裁まとめてZennに置いたほうがいい気がしてますが、一旦走り書きということで。

Gradleの考え方

設定と実行の分離

キャッシュを効かせるためにも、Configuration Cacheとかの文脈で、設定フェーズと実行フェーズは分けて考えることを推奨する動きがあるっぽい。 実行フェーズに設定を変えるなとか、afterEvaluate { ... }に過度に依存した設定を書くなとかを気にすればいい。

設定の遅延

設定より規約

能力と慣習の分離

登場人物

プラグイン実装に必要な登場人物は、だいたい3つほど頭に入れれば良いと思われる。

  1. Plugin
  2. Extension
  3. Task

他には依存を扱うConfigurationとかProjectにメソッドやプロパティを追加するためのConventionなどもある。ConventionはExtensionで代替すべきという情報もCommunity Forumにはあったので置いといて良いかも。

Plugin

プラグインを適用した際、真っ先にインスタンスが作成されるクラス。このPluginによってまず必要な初期化処理を行う。Gradleのバージョン確認もここ。 基本的にはファイル作成やタスク作成といった重い処理は行うべきではない。適用しただけで重くなるようなプラグインになってしまうので。

また"能力と慣習の分離"の観点から、機能を提供する部分をbase pluginとして慣習・規約を扱う部分から独立して定義することが望ましい。 BasePlugin, ReportingBasePluginなど標準で用意されたbase pluginもあるので、適宜 project.pluginManager.apply(BasePlugin)などとして利用できる。

Extension

Property-like fieldsを持つPOJO。 ExtensionもPlugin同様、インスタンス生成コストは抑える方が良い。これはプラグインの提供する機能(タスク)を使わない場合でもExtensionは作成されることが多いため。

Extensionではプロジェクト内で実行されるTaskすべてに共通の設定を行うことになるはず。

Task

主にDefaultTaskを拡張Property-like fieldsを持つ。入力と出力を宣言することで、キャッシュ可能にできる。

実行のコストは重くして良い。不要なTaskは生成されない・実行されないようにビルドスクリプトを書くことがユーザには推奨されている。 同じプロジェクトに属するTaskは同時実行されない=後続Taskをブロックするので、重い処理はWorker APIに逃がすことも検討する。

lazy config をどう実現するか

PropertyFileCollectionに代表されるProperty-likeなクラスを活用する。Extensionのプロパティのconventionをデフォルト値に、TaskのプロパティのconventionをExtensionのプロパティにする。ちょっと古いプラグインだとconvention mappingというのを使っているがinternal APIなので無視で良い。

// ExtensionはPOJOにする。生成コストを低く保つ。// 抽象クラスにすることでProperty-likeフィールドの生成処理を省略できる(ドキュメント未確認)abstractclass MyExtension {
  abstract Property<String> getFoo()
}

// TaskもProperty-likeフィールドを持つ。@Inputや@Output,@Internalなどの修飾子を使ってキャッシュ可能にする// やはり抽象クラスにすることでProperty-likeフィールドの生成処理を省略できる
@CacheableTask
abstractclass MyTask extends DefaultTask {
  @Input
  abstract Property<String> getFoo()

  @TaskAction
  void run() {
    printthis.foo.map { "The value of foo property is ${it}" } .get()
  }
}

// base pluginはextensionの登録やGradleのバージョン確認など、機能実行の前準備のみ実行。規約(慣習)は扱わない。class MyBasePlugin implements Plugin<Project> {
  @Override
  publicvoid apply(Project project) {
    def extension = project.extensions.create("myExtension", MyExtension)
    project.tasks.withType(MyTask).configureEach {
      // 規約に関係ないデフォルト値はここで設定して良いはず
      it.foo.convention(extension.foo)
    }
  }
}

// こちらのpluginでは規約(慣習)を扱う。これはsourceSetごとにTaskを作る例class MyPlugin implements Plugin<Project> {
  @Override
  publicvoid apply(Project project) {
    project.pluginManager.apply(MyBasePlugin)

    project.plugins.withId('java-base') {
      def convention = project.convention.getPlugin(JavaPluginConvention)
      convention.sourceSets.all {
        def name = it.getTaskName("foo", null)
        project.tasks.register(name, MyTask) {
          // 必要な設定を行う
        }
      }
    }
  }
}

VerificationTaskのようなインタフェースもあるので適宜実装すると、他プラグインとの整合性を取りやすい。

ドキュメントに目を通しても迷ったら


外国人永久居留証を取得しました

$
0
0

外国人永久居留証の申請条件を満たしたので、2020年9月25日付で外国人永久居留証を申請し、半年後の2021年2月25日に受け取りました。

どういうカードなのか

俗に言う中国版グリーンカードですが、だいたい以下の恩恵があるようです。

  1. 就労許可・居留許可を継続的に取り直す必要性がなくなる。有効期限は10年。毎年3ヶ月は中国に滞在する必要あり。
  2. 投資に制限がなくなる、らしい。
  3. 行政手続で段階的に使えるようになる、中国人レーンや住宅公共積立金を使えるようになるなどの計画があるらしい
  4. コロナ禍環境下においても入境が可能とされている(2020年11月27日現在)。無ければ入境できないというわけではない。

正直なところ、現状あまりメリットはありません。オンラインサービスで身份证代わりに使えるわけでもないですし、銀行や行政での手続にも引き続きパスポートが必要だという話も聞きます。2020年から鉄道もパスポートで乗れるようになっているので、会社に就労許可・居留許可の更新を代行してもらえる駐在員としてはさほど利点はない感じです。

ただコロナ禍環境下でも入境がしやすいはずという期待と、ICチップが入っているのでいずれ第二代身份证のシステムの環に入れるのではないかという期待、また会社に頼らず家庭環境を維持できるという生活の安定性向上の観点から申請に臨みました。

これから申請する人へのアドバイス

上海での行政手続というと、情報が錯綜しているとか担当者によって言うことが違うというイメージでしたが、今は既に上海公安出入境管理のサイトで申請に必要な書類や手続が明確化されているため、大きな混乱はありませんでした。いくつか情報を補足すると:

  1. 上海総領事館で発行する婚姻証明書単体では証明として不適とのことで、婚姻証明書の発行に使った戸籍謄本のコピー2部とその翻訳文を合わせて提出する必要がありました。窓口で翻訳すると手数料100元。
  2. 上海総領事館経由で発行する無犯罪証明は自分では開封できないのですが、翻訳文もまた必要なため、申請当日に窓口で開封してもらいその場で業者に翻訳を依頼する必要がありました。手数料150元。
  3. 手続きはサイトに記載のとおり、学林路の窓口で行う必要がありました。以前は民生路だったようですが移転しています。
  4. 手数料1,800元は、申請時ではなく居留証受け取り当日に現金で支払う必要がありました。
  5. 写真は白背景の印刷したものを2枚のみ、データでの提出はありませんでした。当日窓口でも別に撮影があります。
  6. 「有效签证(或居留证件)」の原本とコピー提出をもとめられますが、居留許可カードのことではなく、パスポートに貼られたビザをコピーする必要があります。
  7. カードに中文姓名を併記するか英文姓名のみにするか選択できました。
  8. 申請時にバーコード付きの書類を渡されます。受取など後続の手続きにはこの書類の持参が必要です。

申請のクリティカル・パスは無犯罪証明です。申請から届くまできっちり2ヶ月かかりました。また婚姻証明のために日本から戸籍謄本を取り寄せる必要もあります。この2つを早めに開始するべきでしょう。

健康診断は2週間前から申込可能、1週間強で受取可能。公証は申請してから1週間で受取可能。銀行での預金凍結は即日でできます。户口本の名称変更(英文に訂正する必要あり)も、配偶者の戸籍がある場所の公安で即日でできました。配偶者の協力が必須なのは住居に関する公証と、户口本の名称変更、そして申請当日に身分証やパスポートを預かるのみです。配偶者の勤め先の名前も控えておくと良いと思います。

参考

静的解析ツールまとめ2021年春

$
0
0

静的解析ツールで飯を食えないか定期的に気になるタチなので有償サービスなど調べている。のをまとめる。主にJava/JavaScript周り。

NameDownloadStar開発企業など
SpotBugs482k/mo2.2kなし
PMD-3.3kなし
Stylelint10m/mo8.5kなし、Open Collectiveはある
SonarQube-5.6kSonarSource
Codacy--Codacy
CodeClimate--CodeClimate

有償サービス展開している企業は、どこも(国境を超えた)リモートでの就業はやってない。

選外

coveralls
カバレッジ出すSaaS。他のSaaS機能で代替できることが多そう。
snyk
依存に含まれる脆弱性を見つけるSaaS。DependabotやSonatypeと競合?

オンラインコミュニティに参加してるまとめ

$
0
0

自分のキャリアを考えたときに、FOSSエンジニアであることの比重が高いわりにプレゼンスないんだよね……ということに課題を感じたので改善策を考えてみた。LTやセッションを増やしたりcontributeするプロジェクトを増やしたりするのも必要だけど、他にも継続的にオンラインの知り合いを増やせる・議論の機会を得る手段がほしいと思い、オンラインコミュニティにいくつか参加し始めているところ。

参加コミュニティ

Codacy Community

OSSの静的解析ツールを複数組み合わせて統一されたUIで解析結果を伝えるSaaS、のコミュニティ。Twitterで見かけてDiscourseに参加。

SonarQubeやLGTMのような自社解析エンジンは持っていないが、CEOが静的解析で修士とった人だったし社員ぽい人もSpotBugsにPR送ってくる。のでマニアが集まるのではと期待してDiscourseに静的解析を学ぶ良い方法について話題を投げたけど反応薄いのが今。

SonarSource Community

前から参加してたDiscourseをより頻繁に見に行くようにした。私はコミュニティ担当の方とどうも反りが合わないようで、PRで話が噛み合わないとか返信を何週間も待たされたりとか、どうも見る気になれないのだけど。

どこにも買収されてない&自社で技術を持っている数少ない企業だと思うので、今後も注目していきたい。

Gradle Community

Slackがあるのに最近気づいて参加。Discourseでもいいけど、Configuration CacheとかWorker APIとかわりと新しめの話題について質問するにはSlackのほうが反応早いかもしれない。

GradleはGitHub Issuesでコミュニティ発のプラグインの機能について俯瞰状況をまとめてたり活発なユーザを称えるFellowship Programを初めていたりと周りを巻き込もうという意気を感じる。のはいいんだけどYoutubeチャンネルのノリがよくわからない。アイスブレイクのつもりなんだろうけどバラエティ番組みたいになっていたりする。

Write the Docs

コミュニティの蓄積がすごい。ツールの話はもちろんテクニカル面についてもまとまってそう。L10nについては特にまとまっていないので、Slackチャネルでおすすめのツールを聞いてみている。ドキュメンテーションツールもそうだが翻訳メモリなどについても話していきたい。

API the Docsというオンラインカンファレンスが近いようなので覗いてみるつもり。

SIGPX

DX: Developer Experience (開発体験)は重要だ - Islands in the byte streamで知り、PXは静的解析ツールとの親和性高いのではと思って第8回勉強会に以下のスライドで参加。静的コード解析そのものについて扱っている方はいらっしゃらなかったが、IDE周りというかMagpieBridgeLSPについて掘り下げて話すと良いかもと感じた。

speakerdeck.com

Java-jp Discord

ゆるゆる参加している。

twitter.com

コミュニティの更新を追う方法

モバイルアプリで追えるようにして、通勤中などのスキマ時間にぱぱっと済ませられるようにしている。

Discourse

公式モバイルアプリがあり、複数サイトを横断的に管理できる。今まではメール通知に頼っていたけどこちらのほうが早い。

Slack

Slackアプリが複数ワークスペース管理をサポートしている。各ワークスペースに同一のメールアドレスでサインインするようにすれば特別な配慮は不要。

Discord

こちらもSlackと同じ。

まとめ

はじめたばかりなのでまとまらない。情報発信は得意な方なはずなので継続していきたい。

JavaのRecordでは配列を使わないほうが良いという話

$
0
0

配列使うとmutableになるから使うべきではない、というのに加えて。生成される hashCode()equals(Object), toString()が配列を考慮しない実装になっているため、JavaのRecordでは配列を使わないほうが良いようです。

検証コード

生成される hashCode()equals(Object)の挙動を検証するコードです。

gist.github.com

なぜこうなるのか

ObjectMethodsクラスによって生成されるコードを見ると、 Arrays.hashCode(int[])ではなくint[].hashCode()が、Arrays.equals(int[], int[])ではなく int[].equals(Object)が使われているようです。これは考慮漏れというわけではなく、ObjectMethodsクラスのjavadocに明記されている仕様です。core-libs-devメーリスに質問を投げて確認しました

実際の実装はObjectMethodsクラスのコードを読むか、以下の記事を参照ください。

alidg.me

望ましい対策

Recordでは配列の代わりに不変コレクションを利用するのが望ましいと思われます。Java 9からimmutable listを作るfactory methodが導入されています。また不変であることを型として示したいならば、GuavaのImmutableListを使う手もあります。

Recordクラスがmutableになるリスクを受容した上で配列を使う場合は、hashCode()equals(Object), toString()を自動生成に頼るのではなくハードコードすることで、この問題を回避可能です。大抵のIDEにはこれらのコードを自動的に生成する機能が備わっているので、利用すると良いでしょう。

InclusiveなOSS開発体制を作る意味で、GFWの影響をざっくり知ってもらえるとありがたい

$
0
0

TL;DR

2021年5月時点では raw.githubusercontent.comgcr.ioはGFW内からアクセスできません。 開発しているOSSを広いユーザに利用してもらいたい場合は、こうしたドメインへの強い依存は避けることを検討しても良いかもしれません。

中国インターネットから見たOSS開発体制

中国本土でOSS開発をしていると、以下のようにバッジが壊れているGitHubリポジトリによく遭遇します:

f:id:eller:20210520191050p:plain
バッジが表示されないGitHubリポジトリの図

これはバッジが使っているドメインraw.githubusercontent.comにアクセスできないことから生じます。バッジなら大して影響ないのですが、開発体制構築がこれに依存していると厄介です。 例えばYarn v2のインストール手順は、JSONファイルを raw.githubusercontent.comからダウンロードするためにうまく実行できません。このためGitHub Issuesでユーザ側による回避策の適用が推奨されています:

github.com

GitHubが中国本土からアクセス可能なのは有名な話だと思いますが、それでもこうした一部ドメインへの制限があったり、Web画面にもたまにアクセスできなかったりもします。

同様に gcr.ioもアクセスできません。Jibがかつて標準で利用していたベースイメージであるDistrolessのダウンロードが行えません。ただJibが利用するベースイメージはv3からDocker Hubに置いてあるAdoptopenjdkに変わったので、だいぶ使いやすくなりました。

試してませんがStackoverflowの投稿によるとfirestoreも一癖あるっぽいですね。

どのような回避・緩和策があるのか

GFW内からもアクセス可能なドメインを使う

バッジやJSONファイルを配布する場合、2021年5月時点では shields.ioGitHub Pages、Netlifyなどで代用が可能です。 おそらく最も運用が軽い対策になると思います。

2021年5月26日追記:GitHub Releasesに添付されたファイルもダウンロード可能でした。

ミラーサイトを用意する

Mavenやnpmなどのパッケージダウンロードが遅い場合は、中国国内に大手が提供するミラーサイトが利用できます。通信自体は可能なので必須ではありませんが、開発体験を向上できる場合があります。

maven.aliyun.comgithub.com

このように、ミラーを用意してそちらを使ってもらう手は一応あります。ただ個人的にはXcodeGhostの1件があったので、ミラーの利用をコミュニティとして推奨するのは避けたいなぁとは思っています。少なくとも公式サイトからチェックサムを確認できるようにする必要があるかと。なおGradleはv6から依存のチェックサムを自動的に検証できるようになりました。

hostsを書き換えてもらう

以下のように、中国語ブログでよく紹介されているのがこれです。詳細は割愛。

www.cnblogs.com

まとめ:そんなに気を使わなくても良いかも

こういうことを気にできると確かにInclusiveOSS開発体制の構築には貢献すると思いますが、今見たらant-designも普通に raw.githubusercontent.comを使っていたので、気にしなくても問題ないレベルかもしれません。

JJUG CCC 2021 Springでバイトコードの話をしました

$
0
0

ということでJava8〜16におけるバイトコード生成の変化について、先日開催されたJJUG CCCで喋ってきました。 動画をYoutubeにて配信していただいているので、よろしければご覧ください:

youtu.be

資料はSpeakerdeckにあります。ハイパーリンクを埋めているところは、PDFを落としてもらえれば追えるはずです:

speakerdeck.com

マイクロベンチマークGitHubに置いてあります。みんなも手元でレッツJMHだ:

github.com

なお最後の方に触れたJEP396については、掘り下げたセッションがあったようです:

youtu.be

運営の皆様、いつも素敵なイベントを開催いただきありがとうございます!

WIP: 内製化をすすめる知人へのアドバイス

$
0
0

ソフトウェアエンジニアとしての働き方を探求してきた経験と、駐在員として文化の狭間でうろちょろしてきた経験、OSSエンジニアとして多数の多様な人材と交流してきた経験をもとに、果敢にも内製化に挑戦する知人へのアドバイスを気持ちまとめます。

前提

  • 主な利用技術にはJavaSpring Framework)やTypeScriptを想定
    • FaaSを始めとしたManaged Serviceは(いまのところ)積極採用しない構え
  • Digital Transformationを推し進める一環としての内製化に、エンジニアリングの観点から挑む方を読み手として想定
    • 内製化のターゲットは決まっているか心当たりがある状態
    • 既存の開発チームはほぼ無い想定

1. チームビルディング

1.1. スーツとギークの対立を避ける

我々が若かった頃は"スーツ"と"ギーク"の対立を煽る風潮にありました。Rockstar Engineerという、ひとりで27倍の生産性を持つエンジニアを称賛する動きもありました。Being Geekという本の表紙がまさに象徴的です。

Being Geek ―ギークであり続けるためのキャリア戦略

Being Geek ―ギークであり続けるためのキャリア戦略

  • 作者:Michael Lopp
  • 発売日: 2011/06/25
  • メディア:単行本(ソフトカバー)

それから時は流れ、ギークとスーツは消えました。チームマネジメントが再評価され、Rockstarよりも多様性が重視され、Stallmanが批判され、Linusが変わりました。我々は生産性27倍のSPOFをありがたがることをやめ、ソフトウェアエンジニアリングを組織に適用し業務効率を高め、サイロを克服しドメインを深く理解することによってビジネスを加速化することが求められるようになりました。組織にとって選択肢でしかなかったソフトウェアエンジニアリングは、Lean Software Developmentの確立や端末の市民への普及によって、すべてのビジネスに溶け込んでいます。

現代においてDDDやプロジェクトマネジメント、品質管理やサブスクリプションに関する本を手に取ると何が書いてあるでしょうか。科学的に仮設を検証し高速に市場を創出するための手法として、いかにビジネスとテクノロジーを融合するかという一点に関心が割かれています:

  • ドメインに注力することでビジネスの専門家とソフトウェアエンジニアリングの専門家が同じ用語で議論できるようになり、またソフトウェアをビジネスに追随させやすい状態を比較的保ちやすいことが知られるようになりました。
  • Project Managerはプロジェクトマネジメント手法としてAgileを学ぶことを求められています。
  • 品質とスピードがトレードオフではないことも広く知られ、スピードのために品質に関心を払うことがQAだけではなくProject Managerや経営層の関心事になりました。
  • 多くの企業がサブスクリプションに移行しているのは、収入の予測可能性が高まることに加え、顧客とのつながりを確保しテクノロジーを通じて多様な顧客を理解するための役割を期待しているところもあるようです。

しかし、Digital Transformationのための開発組織を構築する際は、かつての対立が再現されやすいような気がします。 特に"ギーク"が"エイリアン"として振る舞い"スーツ"がそれを"受容"する……という空気を作ってしまうと容易にハマります。

無用な対立を避ける意味で最も良いのは、「ビジネスとテクノロジーが融合する重要性」という内製化の背景を経営層が理解することです。そのきっかけ作りとして私はソフトウェア・ファーストを経営に読むことを勧めたりしていますが、打率はあまり高くない印象です。たぶん長すぎるんでしょう。

ソフトウェア・ファースト

ソフトウェア・ファースト

読者(ソフトウェアエンジニアリングの責任者)がビジネスの文脈を理解できている場合は、経営との対話を通じて少しずつ意識を変えていくことも効果的かもしれません。
このとき、相手は内製化の背景をまだ共有できていない、ビジネスのスピードを高める必要性を理解していないということを意識する必要があります。相手の語彙で対話し、相手にその必要性を再発見させなければなりません。でもこういう誘導する話し方って、焦っているときほど難しくなるんですよね。他社事例をストックしたり、スピードが出せていないことによる機会損失を試算したりと、普段から道具を収集しておくと助けになります。また話している文の主語を省略せず、常に明確にしましょう。これだけで誤解を避け、相互理解を進められる場合がけっこうあります。

1.2. 目指すアウトカムについて開発チーム内外で合意し文書化する

経営側の意識を変えにくい場合でも、内製化をする理由・テクノロジーに期待するアウトカムを議論し、文書として共有すると良いです。明確な目的は今後のコミュニケーションに役立つでしょう。

アウトカムを明確にすることは、組織がテクノロジーを融合する重要性を理解する助けとなるだけではなく、ソフトウェアエンジニアがビジネスを理解する助けにも、ソフトウェアエンジニアが目先のノイズに囚われないための助けにもなります。この時点では定量的でなくても良いので、チームを越えた錦の御旗として使うに値する明瞭な目標を持つようにします。

1.3. Agileでなくとも構わないが、学習できる組織を目指す

アウトカムを明確にしたくても、そもそも目標や目的の明文化に抵抗がある組織もあります。その場合、その文化を変えることがDigital Transformationよりも重要な課題だと認識する必要があります。なぜなら、目標と目的の明文化は経験主義に立脚する今日のソフトウェア開発において頻出するからです。たとえば:

ここでのキーワードは「学習」です。Scrumやself-organizing team、組織論について学ぶと必ず出てくる言葉です。組織に人によって教えられる”正解”はなく、試行錯誤が必要です。我々がDigital Transformationを目指すのも、この試行錯誤のサイクルを速めたいからだったはずです。よって個人や組織が学習できる環境を作ることが求められます。

ではどうすればいいのか。中原淳氏の研究(2010年)によれば、職場で人が育つためには「業務支援」「内省支援」「精神支援」が必要だそうです。ソフトウェアエンジニアにとっては「OJTや技術教育」「1-on-1を通じた振り返りの促進」「日々のコミュニケーションで励まし褒める」ことになります。

目的が明確であれば、OJTの内容も、1-on-1で振り返る方向性も、褒めるポイントも明確になります。また失敗をした際に意味のあるPostmortemをすることもやりやすくなるでしょう。目標や目的を明文化し、個人と組織が学習できる組織を作ることを心がけましょう。

1.4. 専門職を設けるべきか

今回の想定事例のような新しいプロジェクトで、ビルドやテスト、運用について専門職を設けるべきでしょうか。個人的には否定的です。 人材の流動性が高く既存資産も多くない状況であれば、全員が開発から運用まですべてのプロセスに関わる方が開発高速化の恩恵を受けられるはずです。

ビルドスクリプトやパイプライン定義、プロビジョニング手順はファイルで定義してGitで管理するようにします。 これにより属人性を下げるだけでなく、変更内容がレビュー可能になり信頼性も向上します。

2. 技術選定

とりあえず↓に目を通すのがおすすめです:

qiita.com

その上でいくつか具体的な話を。

2.1. 目指したい「品質」の合意を作っておく

ビジネスの専門家はもちろん、ソフトウェアエンジニアにとっても「品質」の定義はゆらぎがちです。人によって違う定義を使っていたり、品質保証に幻想を抱いていたりすることもあります:

一応ISO/IEC 25010:2011でモデル化されているのでMECEに考えること自体はやりやすいのですが、全部重要に見えてきて「これローンチなんて何年も先になるのでは?」みたいなことにもなりがちです。もちろんそんなことはできないので、優先度をつけなければいけません。

今回の想定するケースでは、少ない資産で早急にプロダクトを作り検証を通じて学習し成果を出さなければならない状況のはずです。であれば、私としてはMaintainabilityを重視します。コードをどんどん書き、どんどん捨てられることが何よりも重要です。そのためにコードが疎結合であること、テスト可能であること、目が届き把握できることを優先します。

なおMaintainabilityは、今回の想定事例以外でも重要視されている認識を持っています。ビジネスなどの変化が速く、すぐに「最適」が変化するためです:

一方でPerformance EfficiencyやCompatibility、Usabilityは脇に置いても良いと考えます。MVPによって正しい仮説を掴むまでは、これらの判断をしようがないためです。Webアプリケーション開発のようにインストール先が管理下にある場合は、Portabilityも不要かもしれません。さすがにSecurityが低優先とは言いませんが、ある程度のリスクは受容する判断があってもいいでしょう。

2.2. ビルドパイプライン

パイプラインファーストを志向するべきです。ソフトウェアプロジェクトを始める際は、まずパイプラインを構築します。

Gitを使ったPull Request(PR)ベースでの開発をする場合は、デフォルトブランチへの直接pushを禁止し、ビルドを壊す変更が導入されない状態をパイプラインによって保ちます。

CIがあればPRは不要だとする意見もありますが、今回の想定では新設チームであることも鑑み、いきなりデフォルトブランチへのpushを解禁することは危険だと判断します。あと、あんまり直接pushを是とする組織は現状多くないと思うんですよね。長いもの(industry standard)に巻かれておくことは、組織外の資源を有効活用するためのひとつの知恵です。

なおビルドパイプラインがどうあるべきかは、以前ブログに書いてますのでご参考まで。

2.3. まずはテストケースから書く

先述の通り、品質としてはMaintainabilityを最優先にします。そのためには、まずテストケースから書き始める文化を醸成します。新機能開発にTDDを適用したり、バグ修正時にバグを単体テストで再現したりといったところから着手します。

このプロセスを不要あるいは非効率と主張された場合は、品質とスピードがトレードオフではないことを根気よく伝えていく必要があります。プロダクトが高速に変化・成長するためには、既存機能が壊れていないことを機械的に検証する手段である自動テストは非常に重要です。またテストケースから書くことには、目的や目標の明確化をチームに促す効果もあります。

なお勘違いしてほしくないのですが、作成したテストケースは削除して構いません。実装や要件が変わり、既存テストが不要と判断された時点で削除しましょう。不要なテストが多く残ることでビルドやデプロイのパイプラインが遅くなっては元も子もありません。もちろんテストの並列実行のような技術的な解決方法はありますが、不要なテストを実行する理由にはなりません。
一応テスティングフレームワークには実行をスキップする機能もありますが、あれを多用すると好ましいスキップと悪しきスキップとを判別するコストが上がるので、VCSを信じてサクッと消すのが吉です。*1

また自動テストケースがあれば手動テストが不要、というのもよくある勘違いです。テスト自動化の8原則にも書いてありますが、手動テストはなくなりません。手動テストすべきところにコストをかける手段として自動テストがある、くらいの理解がちょうどいいかもしれません。

2.4. プロジェクト固有ルールを作らない

コミットコメント、コードレビューのやり方、ラベルの扱い、ビルド用コマンドやリリースノートの書き方など、ソフトウェア開発にはオレオレルール策定のチャンスが多く潜んでいます。これらを早めに潰すことで、新しくプロジェクトに参入する人の参入障壁を減らし、特定プロジェクトでのみ行うべき配慮をなくすことができます。既存資産がなく人材の流動性が高くレベル感もあわせにくい状況では、これは大きな助けになるでしょう。

例えば以下のような、一般化され公開されている知見を流用します:

逆に個人の裁量を認める部分としては、エディタやOSがあります。これらの選択を自由にするための技術として、というか開発環境の差を最小化する技術として、以下のようなものがあります:

なお新しい手法をまず小さく試すために一部プロジェクトに適用する、というのはありです。堅苦しく”管理”することは本意ではありません。必要なのは検証中という状態をずるずると伸ばさないことで、これも前述の学習する組織の構築や目的の明確化によって達成可能です。

2.5. KubernetesとかService MeshとかMicroserviceとか、他にもなんかエッジなやつ

チームが小さいうちは考慮しないでいいです。こまめにデプロイしリリースできることが重要です。 将来的にチームが増え、チーム間の協力体制をどう築くか?が組織の関心事になってからで良いでしょう。

その他

忘れてはいけないこと

実行こそが最重要です。ぐだぐだと基礎や知見、歴史を語ることは必要かもしれませんが、実行だけが世界を変えます。

つーか「明瞭な目標を設定しよう」とか、言うだけならタダなんですよ。それを現実のものとするのに、一体どれだけの傾聴と対話と勉強と失敗と思い切りが必要なのかって話ですよ。頑張ってください。

まとめ

  • ビジネスの専門家とともに目的と目標を設定し、継続的に学習するチームを作る
  • 求めるアウトカムと品質について、チームと議論し共有する
  • パイプラインとテストを最初期に導入する
  • コードを書け、検証しろ、振り返りをしろ、実行がすべてだ

あわせて読みたい

いただいたフィードバック

学習できる組織とはそもそもAgileでは?という疑問に対して、Agileという用語を避けることでビジネスの専門家に受け入れやすくなることを期待していると返答したことに対するフィードバック:

*1:この点ではLaunchableにはちょっと期待していまして、スキップすべきテストが自動的に選択される未来が一般化するのかもしれません。


SLF4JとLogbackは2021年現在では積極採用しない方が良い

$
0
0

SLF4JとLogbackの中の人はここ数年活発ではないのでLog4j2などを代わりに使いましょう。

SLF4Jの活動は最近活発ではない

SLF4JはVCSとしてGitHubを利用しています。最後の変更が2020年2月最後のリリースが2019年12月となっていることからも、あまり活発ではないことが伺えます。

またBTSとしてJIRAを使っていますが、こちらもメンテナンスされていません。昨夏SLF4J-209が既にクローズ可能な状態であることSLF4J-186が修正可能であることなどをコメントしましたが、1年近く経った今もすべて返信がない状態です。

2020年12月にイシューを閉じていたりするので全く動きがないわけではないのですが、年間で22つ作成されたのに対して2つしか閉じられていないので、充分にメンテされているとは言い難い状況です。

f:id:eller:20210531193941p:plain
2021年5月31日時点での過去360日のイシュー消化状況

メンテナーを増やすつもりはない?

2020年8月14日に ceki@qos.chにメールを送り、メンテナーを増やすつもりはあるか、あるなら自分はこういった貢献ができますという意思を伝えたのですが、こちらもまだ返信がありません。

少数のメンバーがリリース権限を握っており、かつプロジェクトリーダーが連絡を取れない状態……と考えると、かつてのFindBugsプロジェクトの最後に非常に親しい状況にある気がしています:

blog.kengo-toda.jp

Log4j 2が活発に活動しているのが幸い

ではSLF4JやLogbackに頼れないとして、どういった移行先があるのか。ロギングファサードないしロギングライブラリとしては、以下のような選択肢があります:

個人的にありがたいのはLog4j 2が活発なことです。Logbackを採用する理由として実行性能があったと記憶していますが、Log4j 2はLogbackと比べても高い性能を示しているとされています。lazy loggingflow tracingなども備えています。あと地味にLoggerインスタンス作るのが楽です:

// SLF4J// http://www.slf4j.org/faq.html#declaration_patternprivatestaticfinal Logger logger = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());

// Log4j 2// https://logging.apache.org/log4j/2.0/manual/api.html#Logger_Namesprivatestaticfinal Logger logger = LogManager.getLogger();

ログライブラリはプロジェクトによって要件も異なるでしょうし、必ずしもLog4j2が最適な選択肢とは限りませんが、一度試してみても良いのではないかと思います。

MRJAR (Multi-Release JAR)を使っているOSS一覧

$
0
0

GitHub Actionsのworkflow_runイベントでテストを回すときの要点

$
0
0

Dependabotの作ったPRがSecretsにアクセスできないためにことごとく失敗していたのを修正しました。

github.com

SecretsにアクセスできないのはKeeping your GitHub Actions and workflows secure: Preventing pwn requestsで説明されているようにセキュリティ向上のためです。workflow_runイベントでCheckを回すとワークフロー定義は常にデフォルトブランチのものが使われるため、PRでワークフローファイルが悪意を持って変更されてもマージしなければ悪影響を受けません。ので今後、基本的にはsecrets.GITHUB_TOKENをはじめとしたSecretsを必要とするワークフローはworkflow_runイベントで回すことになります。

上記securitylab.github.comの記事で色々説明されていますが、わりと限定的なユースケースについて述べているので、ここでは自分のケースで必要だった知見についてまとめます。

actions/checkout ではrefプロパティを指定する

ソースコードをチェックアウトする場合、どのrefをチェックアウトするのかを明示的に示す必要があります。何も指定しない状態ではデフォルトブランチをチェックアウトしてしまうため、PRで変更する内容をテストできません。

on:workflow_run:workflows:- build
    types:- completed
jobs:integration-test:runs-on: ubuntu-latest
    if: github.event.workflow_run.conclusion == 'success'steps:- uses: actions/checkout@v2
        with:ref: ${{ github.event.workflow_run.head_sha }}

Pull RequestのChecksを登録する際もshaを指定する

この「何もしなければデフォルトブランチの最新refが対象になる」のが曲者です。例えばChecksに結果を反映する際も、明示的にshaを指定する必要があります。

- uses: LouisBrunner/checks-action@v1.1.2
        if: always()
        with:token: ${{ secrets.GITHUB_TOKEN }}
          name: integration-test
          sha: ${{ github.event.workflow_run.head_sha }}
          conclusion: ${{ job.status }}
          details_url : https://github.com/${{github.repository}}/actions/runs/${{github.run_id}}

Secretsなしでもテストできるようにする

すべてのテストをworkflow_runの方に寄せても良いですが、Secretsなしでも実行できる単体テストや静的解析はpull_requestで実行してしまったほうが良いかもしれません。 その場合は、./gradlew buildnpm run allがSecretsなしでも正常ステータスコードで完了する必要があります。

JUnitならassumptionsでTokenがあるか確認して無ければテスト実行をスキップすればいいでしょう。Jestではうまい方法が見つからなかったので、Tokenの有無でtesttest.skipを呼び分けることにしました。

const token = process.env.GITHUB_TOKEN || ''
const integrationTest = token ? test : test.skip

integrationTest('fork() does nothing if the forked repo already exists', async () => {
  ...
})

GradleのbuildSrcとどう付き合うべきか

$
0
0

Gradleで複数サブプロジェクトをもつプロジェクトを作成する - kdnakt blogを見て、buildSrcディレクトリ周りで混乱した記憶が蘇ってきました。

ということで「Gradleの設定やコードをどこに書くべきか」のうち、答えが明確なbuild.gradleファイルとbuildSrcディレクトリの使い分けについて現時点での見解をまとめておきます。

宣言的か命令的か

Gradleのビルドスクリプトを分割統治する手法として、昔はscript pluginと呼ばれる手法が使われていましたが、Gradle 7.1.1時点ではbuildSrcプロジェクトを使ってimperative logicを抽象化することが推奨されています

imperative logicというのはつまり”命令口調”なビルドスクリプトのことですね。ビルドスクリプト自身が極力宣言的(declarative)になるように、命令的なスクリプトをビルドスクリプトとは別のところに書いておこうということです。ビルドスクリプトを宣言的に保つことは、Gradleベストプラクティス堂々の一位に位置づけられており、その重要性が伺えます。

そしてimperative logicを隠しビルドスクリプトを宣言的に保つことは、プラグインの説明に書かれているように、プラグインの設計意図そのままです:

What plugins do (omit) Encapsulates imperative logic and allows build scripts to be as declarative as possible

自分が最近書いた例でいうと、チェックサムをGitHub Releasesに掲載するためのタスク定義はTHE・命令的でした。この定義、あるいは抽象化した定義をプラグインとして書いておいてビルドスクリプトに適用することで、ビルドスクリプトそのものを宣言的に保てるということです。

命令的なコードを置くためのbuildSrcディレクト

通常プラグインはGradle Plugin Portalにpublishして使いますが、プロジェクトごとにpublishしていたらキリがありません。そこでプロジェクト固有のローカルな"命令的"スクリプトを置くための場所として buildSrcプロジェクトが存在します。プロジェクトルートに buildSrcディレクトリを置くと、中のコードをコンパイルしたものをビルドスクリプトのCLASSPATHに置いてくれるのです。

以上のように、全体像がわかってしまえばbuild.gradleファイルとbuildSrcディレクトリどちらを使うべきかは見えてきます。 宣言的なコードはbuild.gradleファイルに、命令的なコードはbuildSrcディレクトリに置きましょう

buildSrcプロジェクトの書き方はmike-neckさんのブログに詳しいのでオススメです。プラグインテスト手法も確立しているので、ビルド性能だけでなくビルドスクリプト管理の生産性も上がるといいですね。

mike-neck.hatenadiary.com

Gradleのbaseプラグインに書くべきでないconventionとは何か

$
0
0

ひとつ前の記事では「Gradleの設定やコードをどこに書くべきか」のうち、答えが明確な「build.gradleファイルとbuildSrcディレクトリの使い分け」について書きました。この記事ではまだ自分の中でもよくわかっていない「Gradleでbaseプラグインに書くべきでないconventionとは何か」について書きます。

baseプラグインとは

ここで言うbaseプラグインは、plugins { id "base" }で使えるThe base pluginのことではありません。Gradleプラグインの設計手法のひとつとして推奨されている「設定より規約」の文脈で登場するものです。「設定より規約」を実現しつつ、(大部分のケースをカバーするであろう)規約が適用できないケースでもプラグインの機能を使えるようにするため、プラグインの規約(conventions)と基本的な機能(capabilities)とを別のプラグインに定義する設計手法です。

例えば javaプラグインjava-baseプラグインの場合、 javaプラグインが規約を提供し、 java-baseプラグインが基本的な機能を提供します。 javaプラグインjava-baseプラグインに依存することで、java-baseプラグインが提供するtaskやextensionを利用します。

なお公式にはbaseプラグイン「ではない」方のプラグインには固有名詞がないのですが、ここでは記載を簡略化するために「規約プラグイン」と呼ぶことにします。

GradleはConventionという用語を多義的に使っている

ではbaseプラグインに書くべきconventionとは何か。この話題に触れるにあたり、GradleがConventionという用語をいつどのように使っているか確認する必要があります。私の知る限り、大きく分けて以下の3つが存在します:

  1. ”設定より規約”の文脈でのconventionのこと。一般的な用法。
  2. プロパティを指定しなかった場合に暗黙的に採用される値。default valueのこと。
  3. プラグイン設定用のconvention
    • 例えばJavaPluginConventionなど。
    • 現時点では非推奨なため、Extensionを利用する必要がある。

こうなるとよくわからないのが「baseプラグインに書くべきでないconventionはどれ?」です。

1のconventionはプラグインが提供する規約そのものでありbaseプラグインに書くべきでないのは明らかですが、JavaBasePluginCargoBasePluginは2と3のconventionを含んでいます。

規約プラグインであるJavaPluginCargoPluginはconventionを持っていることを期待され、実際1や2のconventionを含んでいます。

非推奨となった3のconventionは脇に置くとしても、2の置き場所やそれを決定する判断基準は明瞭に持ちたいところです。

メソッド名に惑わされないのが吉か?

私も2021年7月現在では明瞭な判断基準は持っていないのですが、ポイントはProperty#convention(Provider)というメソッド名に惑わされないことだと思われます。言い換えれば、2のconventionはどこにでも出てくるものだと割り切り、1のconventionを規約プラグインに限定して書くことのみに注力します。そして機能を書く上で必要なプロパティがある場合、baseプラグインでも気にせずにデフォルト値をProperty#convention(Provider)メソッドで設定してしまいましょう。

公式フォーラムに問い合わせてみた

自分的にはわかった気になれましたが、なんかしっくりこないので公式フォーラムに問い合わせてみました。

discuss.gradle.org

返信もらえたらこちらのブログ記事も更新します。

The 2021 State of DevOps Reportが出た

$
0
0

ということでスキマ時間に読み進めていたので、感想と面白いと感じた点をまとめときます。網羅性が高く公平なまとめが必要な方は、3〜4ページに掲載のExective Summaryをおすすめします。

テーマは「中間層からの脱出」

6ページ目を見てもらえれば一目瞭然、今回のテーマは生産性が高くできず中間層で留まっているチームに対する処方箋の発見にあるようです。

近年のレポートは「今更それは無いでしょ」って感じのLow levelが5%強、「リアルチートじゃん」って感じのHighが10%強で、ほとんどのチームがMiddleに属していました。ごく少数の上澄みが高いパフォーマンスを出していて、その鍵となるKPIもベストプラクティスもわかっているのに、ほとんどの中間層は現状から脱出できず指を咥えて見ていた……と言ったら言いすぎでしょうか。この8割を占めるMiddle levelをさらに細分化し、中間層を脱するための働き方を見つけようということです。

f:id:eller:20210726175415p:plain
DevOps evolutionary levels (State of DevOps Report 2021 p.6 より引用)

DevOpsのやり方がだいぶ浸透してきて「何を計測し何をやるか」から「どうやるか」に関心がシフトしてきたとも言えます。同じ6ページにはDevOpsについて語ることよりも働き方について語るチームが多いことが述べられています:

In fact, many of the teams that are “doing DevOps” well don’t even talk about DevOps anymore—it’s simply how they work.

面白いと思ったところ

  • トップダウンによりボトムアップ型の改革を可能にする (p.11)
    • 経営の協力は当然必要というか「DevOpsによる生産性の向上=経営の関心事」という大前提がこのレポートには感じられる
    • 生産性が低い組織はリスクを避けるためにリスクを増大する手段を選択する傾向にある(p.31)が、これも部下を信じられない・Continuous Deliveryの適用をためらう経営なのではと思った
    • executive summaryによれば何でも話して疑問を解消し論点を明確にできる組織が高い生産性を持つわけで、マネジメントやリーダーの日々のコミュニケーションの賜物なのだろうと思った
  • DevOpsチームの存在は組織の進化を助けず、その曖昧な責務が組織に混乱をもたらす(p.13)
    • 開発とオペレーションの間に独立したDevOpsチームを配置するのはアンチパターンとして知られる(p.13)
  • 高度に進化した組織にとって文化は障害にはならず、これこそが高度に進化した理由である(p.14)
  • Team Topologiesという概念の導入(p.17)
    • Fast flow(p.16)実現にとっての障害を取り除くことに注力するものである(p.29)
    • 役割が多く、小規模のチームに当てはめるのは難しそうだと感じた
    • これを実現するための教育はどうやるのだろう?各チームの役割について専門家を探すのも難しそうな気がする
  • internal platformsについて
    • 2020でも触れられたが更に掘り下げて説明している(p.36)
    • 社内向けシステムを構築する際に利用できる認証・認可・デプロイ・保守・監視に使えるPlatformという理解をした
    • データレイクにおけるデータカタログとかも入ってくるんだろうなという理解をした
    • 高度に進化した組織はこうした基盤をinternal customerのビジネスを理解してエンジニアに構築提供している(p.30)
    • こうしたplatform teamがあっても生産性が向上するとは限らないが、DevOps transformationを加速できる(p.30)
    • 標準やルールではなくサービスを提供するということ、すなわち人をチームを信じることが肝要なのだと感じた
  • DevOpsの進化とinternal platformsの利用状況には関連がありそう(p.18)
    • 知識やベストプラクティスを他のチームと活発に共有することが生産性と関連しており、(p.19) これこそがMid levelを脱出するためのとっかかりになる(p.29)
    • だからこそ「でも保守(conservatism)も必要だよね」というCTOコメントが面白い(p.31)
    • 他チームがデプロイの課題を解決したことについて話す事例(p.28)があり、チームの壁を超えて課題解決や挑戦について共有する仕組みや文化が必要なのだと感じた、成果発表会のような季節性の仕組みでは動作しなさそう
    • Chat、金曜のメール、月次学習セッションといった共有手法の一例が共有されている(p.29)
  • 文化を嘆くのをやめて手を動かせ(p.28)
    • これ個人的にはとても気に入った、文化は個人の持ち物ではなくmutabilityを確信できないので
    • 表層の変えやすく失われやすい変化ではなく、5 Whyで組織文化の根っこを変えよう (p.32)
    • 日々正しい方向に組織の振る舞いをnudge(誘導?)していこう(p.32)

過去ログ

2019と2020の感想はTwitterを漁れば出てきます

GitPodでJavaプロジェクトを開発する

$
0
0

GitHub Codespacesがなかなか個人向けに来ないので、changelog.comで宣伝していたGitPodを試しています。 どうも公式のJava向けの説明が古いようで、既にDeprecatedになっているtheiaを前提としているため、調べたことをメモしておきます。

最新のJavaを使う

普通に gitpod/workspace-fullイメージ内でJavaを起動すると、Zuluの11が使われていることがわかります:

$ java --version
openjdk 11.0.12 2021-07-20 LTS
OpenJDK Runtime Environment Zulu11.50+19-CA (build 11.0.12+7-LTS)
OpenJDK 64-Bit Server VM Zulu11.50+19-CA (build 11.0.12+7-LTS, mixed mode)

SDKMANやhomebrewが入っているので好きなバージョンを入れてもいいですが、ワークスペースを立ち上げる度に実行するのは面倒なので、 azul/zulu-openjdkのようなイメージを使ってしまうのが楽でいいと思います。

# .gitpod.ymlimage: azul/zulu-openjdk:16

Mavenの依存をダウンロードしておく

Mavenの場合、dependency:go-offlineプラグインや依存をすべてダウンロードできます。 これをイメージ作成時に実行しておくのが良さそうです。

# .gitpod.ymlimage: azul/zulu-openjdk:16

tasks:- init: ./mvnw -B dependency:go-offline

Gradleの依存をダウンロードしておく

Gradleには標準的な手法がないので、単にビルドを回しておきます。

# .gitpod.ymlimage: azul/zulu-openjdk:16

tasks:- init: ./gradlew build

Extensionを導入する

Java向けExtensionを3つ入れて様子を見ています。

# .gitpod.ymlvscode:extensions:- redhat.java
    - vscjava.vscode-java-dependency
    - vscjava.vscode-java-debug

ポートを開けておく

Spring Framework標準の8080ポートを開けておく場合は portsの設定で足ります。 が、URLの取得にgpコマンドが必要なので azul/zulu-openjdkではなく gitpod/workspace-fullをベースとしたイメージを用意する必要があります。URLの決定ロジックがいまのところ非常に単純なのでなくてもなんとかなりそうではありますが、一応。

# .gitpod.ymlimage:file: .gitpod.Dockerfile
ports:- port:8080
# .gitpod.DockerfileFROM gitpod/workspace-full
RUN bash -c ". /home/gitpod/.sdkman/bin/sdkman-init.sh && sdk install java 16.0.2-zulu"

バッジを付ける

バッジはDiscourseに落ちています。 README.mdとかに貼っておくと、Contributorの敷居が下がって良いんじゃないでしょうか。

community.gitpod.io


勝手を知らないプロジェクトにPull Requestを送るときに気にしていること

$
0
0

初心者向けのPull Request(PR)作成方法はopensource.guideをはじめとして数多く見るのですが、もうちょっと突っ込んだというか中級的な内容の記事を読みたかったので自分で書きます。題材として主に直近で書いた大きめの機能追加用PRを使っています:

github.com

修正や新機能を入れる利点を明確に伝える

何かを提案する場合、その背景には必ず動機となる利点があるはずです。これはとても単純に伝えられることもあれば、テストやグラフを作成しないと伝わりにくいものもあります。

今回の変更では、GitHub Actions workflowの定義ファイル簡素化とパフォーマンス改善が利点でした。定義ファイルが簡素化されることはドキュメントで簡単に伝えられますが、パフォーマンスは測定しなければわかりません。よってパフォーマンス検証用のリポジトリを作成し測定を行うことで、ビルド時間が約28%高速化されることを示しました。

github.com

このリポジトリにあるActionsを実行すると、グラフを描くために必要なCSVが出力されます。それをGoogle Sheetsに突っ込んで以下のようなグラフを作成し、PRページに添付しています。結果として、本当に高速化に繋がるのか?といった疑問や質問は来ず、純粋に実装手法についての議論から入ることができました。

f:id:eller:20210826152424p:plain
パフォーマンスがどの程度具合を説明するためのグラフ

こうして根拠となる事実を自動的に出せるようにしておくと、レビューを受けて実装が変わったときに再確認を行えるという利点もあります。今回の例で言うとキャッシュの解決とJDKのインストールとを並行することでの高速化を意図していたのですが、セキュリティ上の兼ね合いから順次実行するようコードを変更せざるを得ませんでした。このような大きな変更があっても、既に自動化されたパフォーマンス比較手段があったため、パフォーマンス改善が維持できていることを示せました。

考慮すべきことも伝える

変更には利点だけではなく、互換性や運用など考慮しなければならないこともあります。これらをどこまで認識していて、どのような検証を行ったのかを事前に共有することで、多角的な議論の下地とすることができます。

今回の変更では upload-chunk-sizeが設定できなくなりユーザの自由度が失われること、IvyやGrapeといったより多くのパッケージマネージャをサポートすべきかもしれないことを俎上に載せ、その上でそれらが現時点で問題にならない理由を述べています。

新機能をメンテナンスし続けることのコストを最小化する

新機能追加のためにPRを送る場合、その機能のメンテナンスを行うのが自分ではなく相手だという点を意識する必要があります。言い換えれば、メンテナンスの工数が高いと判断された場合、PRをマージしてもらえない可能性があるということです。

基本的には単体テストと統合テストの双方を実装し提供することで対応します。単体テストがあることで実装自体のテスト可能性を担保し、統合テストがあることでリグレッションに気づける状態を作ります。またユーザに対する説明が必要な機能なら、READMEのような書類もあわせて準備します。

また自己流のやり方を持ち込むのではなく、既存のコードベースに溶け込むコードを書くことも重要です。今回は既にある定数クラスを再利用したり、統合テストのための仕組みに乗ったりという工夫をしました。特に統合テストのやり方はリポジトリによって様々なので、既存のビルド設定やコードに目を通す必要があります。

早めに返信するが、相手には求めない

質問や指摘があった場合、24時間以内には必ず何らかのリアクションを返すようにします。どうせタイムゾーンの問題があるので”即レス”は難しいのですが、できるだけ早めに返すことで議論の沈静化を防ぎます。

逆に、向こうから連絡がなくても気長に待ったほうが良いことも多いです。今回は企業の中の人が業務としてレビューしてくれましたが、それでも2週間ほど返信がなかった期間がありました。自分が相手の立場でもそういう事はあるだろうと気長に待つのが得策です。

変更の理由をオーバー気味に説明する

PRを提案する際、依存先の更新やリファクタリングのような、一見不要に見える変更を入れることがあります。例えばこちらのPRでは、ネットワークエラー発生時でもHTTPリクエストのリトライを行うために typed-rest-clientのバージョンを上げています。何も説明しないと、依存を上げるのは他のPRでやればいいのでは?という疑問が湧くかもしれません。

github.com

こうした変更を入れる際は、コミットコメントかPR内コメントでその意図を伝えるようにしています。やはりコードでWHYを伝えるのは難しいので、少しオーバーかなと思うくらいの勢いで伝えたほうが良さそうです。

その他、細かいこと

  • README.mdはもちろん、 CONTRIBUTING.mdCODE_OF_CONDUCT.mdといったドキュメントに目を通しましょう。
  • Pull Requestテンプレートがある場合は利用しましょう。
  • わからないことはわからないと言い、素直に尋ねる方が良いです。相手もこちらを助けやすくなります。
  • 新しいライブラリの導入など相手に判断を求めるケースでも、自分の考えを述べた上で素直に尋ねるようにしましょう。

以上です。どなたかの参考になれば幸いです。 Happy hacking!

SonarQube解析をGitHub Actionsのpull_request_targetイベントで回す

$
0
0

SQ解析が現時点ではあまりpull_request_targetイベントをサポートしておらず、ちょいちょい手間が必要だったのでまとめます。 完全なYAMLのサンプルは↓にあります。

github.com

checkout する場合はrefを指定する

pull_request_targetイベントでcheckoutを実行すると標準ではデフォルトブランチをチェックアウトしてしまいます。 よって fetch-depth: 0に加えて refの指定も必要です。以下のようにHEADをチェックアウトするか:

- uses: actions/checkout@v2
        with:fetch-depth:0ref: ${{ github.event.pull_request.head.ref || github.ref }}

以下のようにマージコミットをチェックアウトすることで解決できます*1

- name: Decide the ref to check out
        uses: haya14busa/action-cond@v1
        id: condval
        with:cond: ${{ github.event_name == 'pull_request_target' }}
          if_true: refs/pull/${{ github.event.pull_request.number }}/merge
          if_false: ${{ github.ref }}
      - uses: actions/checkout@v2
        with:fetch-depth:0ref: ${{ steps.condval.outputs.value }}

PR解析用のオプションを加える

おそらくScanner側の問題だと思うのですが、Developer Editionの機能のためかコードは見つけられていません。現時点では sonar.pullrequest.keysonar.pullrequest.branchの双方を手動で設定する必要があります*2

run: |
          mvn org.jacoco:jacoco-maven-plugin:prepare-agent verify sonar:sonar -B -e -V \
            ${PR_NUMBER:+ -Dsonar.pullrequest.key=$PR_NUMBER -Dsonar.pullrequest.branch=${{ github.event.pull_request.head.ref }} }
        env:PR_NUMBER: ${{ github.event.pull_request.number }}

2021年8月30日更新:

上記実装では脆弱性が残ることをazu さんにご指摘いただきました。ありがとうございました! ブランチ名はPR作成者が決定可能なので、一度環境変数で受けてから使用するべきとのことです。

run: |
          mvn org.jacoco:jacoco-maven-plugin:prepare-agent verify sonar:sonar -B -e -V \
            ${PR_NUMBER:+ -Dsonar.pullrequest.key=$PR_NUMBER -Dsonar.pullrequest.branch=${PR_BRANCH} }
        env:PR_NUMBER: ${{ github.event.pull_request.number }}
          PR_BRANCH: ${{ github.event.pull_request.head.ref }}

Sonar Scannerの実行にはJava 11が必要

pull_request_targetと直接関係はありませんが、最近更新が入ったようなので念のため。

Sonar Scannerは実行にJava 11以上が必要なので、Java 8のコードを書いている場合でもJDK 11以上でビルドする必要があります。MavenもGradle*3--releaseオプションをサポートしているので、それを使うと良いでしょう。Java 8に無いAPIを見つけてコンパイルエラーにしてくれるので、 --targetよりも安心です。

個人サービスやOSS開発の保守運用から何を学んだか

$
0
0

というようなことを私はよく主に採用の文脈で口走るのですが、ちゃんと内容をまとめておこうと思ったのでメモ。特に保守運用を経験しているというのが強いと思っているので、そこに注力して書いてみます。

障害対応の経験が積める

10年ほど前にTwistoire (ついすとわーる)というサービスを運営した際に、利用想定の甘さから半日程度のサービス停止を招いたことがありました。

blog.kengo-toda.jp

個人が無償で提供していたサービスとはいえ、使ってくれているユーザに対してそれなりの責任を感じた記憶があります。またひとりで使っていたころには発生しなかった障害なので、単純に課題の分析と解決が面白そうに映るのも事実です。こうした体験から一次対応の必要性や根本解決ないしポストモーテムのあり方について実体験を持って考えられるようになります。

これ、言葉で「実体験を持って考えられる」と書くと軽いんですが、本人としては結構深刻に落ち込んでいて当時のツイート↓を見てもかなり悔しかったのだと思われます。

業務でメンテしていたシステムでも近い経験はできたので、ホビープログラマ固有の特徴かというとそんなことはないと思います。 ただ最近読んだシステム障害対応の教科書でも指摘されていましたが、障害対応は暗黙知と習熟とが必要になりがちです。そのため、むしろすべて自分でコントロールできる=SECIモデルのプロセスを自分の中で完結できる趣味開発というのは、学習効率の面からも悪くないと思います。

「運用しやすさ」という見えない品質に気づける

「いいログを書くためには何を勉強すればいいですか?」という質問をシニアなプログラマに聞くと、だいたいは「運用経験を積む」という回答が返ってきます(n=10くらい)。逆に言うと、運用を経験していないと悪いログを書きがちということです。思いつく「悪いログ」の例はこんな感じです:

  • 単純に量が多い。ログローテーションや保存、実行時性能に悪影響を及ぼす。
  • ひとつの情報が複数行に渡って表示する、パースしにくい書式を使うなど、機械による利用を想定していない。grepやログ解析サービスで追いにくい。
  • 何が起こったかだけ表示し、何が問題で何をすべきかを教えてくれない。次のアクションに必要な情報が入っていない。
  • 情報が足りず、ソースコードと照らし合わせることで初めて意味が理解できる。
  • 出力してはいけない情報が出力されている。

こういう問題は世に出ているガイドラインなどを参照すれば回避可能ですし、アーキテクトやテックリードがちゃんと統制しろという話もあるんですが、やはりプログラマ個々人が運用を意識してコードを書けた方が良いです。経験は最悪を回避するだけでなく、よりよいログを見出すのにも役立ってくれます。思いつく「良いログ」の例はこんな感じです:

  • 発生しやすい問題や運用時の関心事を考慮したもの
    • TRACEログにバッチ処理の進捗度を出力するとか(処理が進んでいないのか遅いだけなのかの切り分け、完了時間の見積の役に立てる)
    • 処理失敗の原因になりやすい「外部から受け取ったパラメータ」を残してくれるとか
    • ガイドライン化しにくい気がしている
  • 読み手が取るべきアクションがわかるもの
    • 「予期せぬのエラーが発生しました」の真逆
    • エラーコード、参照すべきURL、検索を助けるキーワードなど
    • ガイドラインによってエラーレベル(FATAL, ERROR, WARNINGなど)の使い分け方針を定めておくだけでもだいぶ違うが、最終的には想定力がモノを言う印象

このへんは、コーナーケース想定やテストシナリオ設計に通じるところがありますね。サービス運用やアプリリリースの経験があれば、こうした想定の幅が広がり、様々な面からソフトウェア品質の改善に役立てることができます。

品質を落とさないためのリグレッションテストや統合テストを大切にできるようになる

「良いテストを書けるようになるには何を勉強をすればいいですか?」という質問をシニアなプログラマに聞くと、だいたいは「ソフトウェアプロジェクトを継続して運用する」という回答が返ってきます。「テストを書くクセをつけるには?」という質問も同様です。

ここでソフトウェアプロジェクトの運用というのは、コードを書いて成果物を届けるという動きを継続して行うことを指しています。

個人プロダクトを始めた理由は「やりたいことがあるから」のはずです。それはお手玉をしながら綱渡りで火の輪くぐりをするような「あっちこっちを意識しながら壊れないように祈りつつコードを書く」体験とは大きく異なります。しかしながら、テスト設計も自動テストも無いプロジェクトでは容易にこうした体験が醸成されてしまいます。機能ひとつ手を加えるごとに他の機能や非機能要件に対する影響を確認しなければならない状況が生まれ、インクリメンタルに成果を積み上げ「やりたいこと」に近づくことすら難しくなります。

ので品質を落とさないための、というか「新しいことをやっているときに他のことを心配しなくて済むための」リグレッションテストや統合テストを大切にできるようになります。私の場合、同じ理由でシステム監視や運用の自動化、開発環境構築の自動化も関心領域になりました。

大富豪プログラミングに気づける

クラウドが生まれAPIやボタンひとつでデプロイが行えるありがたい時代になりました。私が初めて運用したサービスは有償レンタルサーバー上で動いていましたが、前出のTwistoireはGAE/Jで動いていましたし、最近はHerokuやさくらインターネットのHacobuneのような無償あるいは安価に使えるものも多くなっています。

しかし完全に無料でサービスを続けられるかというとそんなことはなく、ある程度はコストをかけていくことになります。そしてある日、想定していたよりもコストが高くなるという事態が生じます。Twistoireの場合はGAE/Jの料金プラン変更がその契機でしたが、アクセス集中や不具合によって気づくこともあるでしょう:

blog.kengo-toda.jp

趣味開発プログラマはこうした機会をコードが計算機資源を効率よく扱えていないというシグナルとして受け止め、プロジェクトとスキルの改善に繋げることができます。「性能足りなかったらサーバースペック上げればいい」ときもあるかもしれませんが、小型の趣味開発システムだとリスクを取った変更がしやすいということもありコスト効率を追求しやすいはずです。リスクや資源を自分でコントロールできるので、勉強会資料や個人Webサービスシステム構成事典↓のような情報を試しやすいというのもあります:

techbookfest.org

以上、まとめるとホビープログラマは勝手に試行錯誤していろんなことの重要性を理解しているかもしれません。落ち込んでいるときも計画していない出費ができてしまったときもあるでしょうから、元気なさそうだったら話を聞いてあげたら良いんじゃないでしょうか。

「New Relic実践入門」感想、あるいはなぜ監視SaaS使うんだっけという話

$
0
0

New Relic アニキこと清水さんから共著書「New Relic実践入門」をいただきました。ありがとうございます。清水さんにはかつてRDBMSの性能調査をいかに効率的かつ実践的にするかご教示いただいた恩があるのですが、今もその道を追求し活躍されていると知れて嬉しく思います。

破壊的イノベーションを現場の「あたりまえ」にする本書

さて本書は「Part 1. New Relicを知る」「Part 2. New Relicを始める」「Part 3. New Relicを活用する」の3部で構成されていますが、特に「Part 1. New Relicを知る」が割り切った構成になっています。「監視とは何か?」「既存手法にはどのような限界があったか?」「近年の技術革新による新たな課題は?」といった背景をすべてすっとばし、いきなり「オブザーバビリティとは何か?」の説明から入っているのです。まるでTypeScript入門書でJavaScriptの説明を省略するような思い切りの良さです。

結果的にはこの思い切りが、幅広い読者にオブザーバビリティという概念を先入観なく伝えるための仕組みとして作用したように感じました。オブザーバビリティが従来の概念に積み上げる持続的イノベーションではなくDevOpsのような破壊的イノベーションである*1ことを踏まえると、複雑な現状を取っ払ってあるべき姿をまず描くこのアプローチは合理的です。

またNew Relicの利用者は開発者からマネージャまで多様な役割を想定しているようなので、運用技術的土地勘があまり無い読者にも読みやすいというのは狙ったところなのかなと思います。若手からシニアまでまぜた読書会とかもやりやすそうです。これはマネジメントやテックリードとしては「チームに共通理解と合意をもたらす手段」として活用できるというということで、けっこう重要だと思います。

なおPart 2. 以降で既存手法の課題についても都度整理されますし、Part 3. でもケーススタディがこれでもかと出てきます。ので運用経験者も改善手法を学ぶ技術書として興味を持って読めると思いますし、若手とのコミュニケーション手段にもできるかもしれません。

実際にわかりやすく実践入門できるのかという話

入門書を名乗るからにはちゃんとNew Relicに入門できるのかというのは気になるところです。筆者の場合は本書を読んで1日ほどで、手元のspring-boot webfluxアプリにAPM, Infrastructure, Synthetics, Browserを導入してダッシュボードでパフォーマンスを確認するところまで持っていけました。スクリーンショットや表が多くわかりやすく構成されているのと製品のUIが統一されているのとで、さほど迷わなかったと感じます。

f:id:eller:20211019205034p:plain
最終的に得られた解析結果

残念ながらJava agentの最新リリースである7.3.0はJava 17に対応しておらず、ランタイムをJava 16にダウングレードする必要がありました。これは次の7.4.0リリースで対応されるようです。

github.com

なぜ私達ソフトウェアエンジニアはSaaSを監視に使うのか

O'Reillyの「入門 監視」§2.3では、監視ツールはまず「作るのではなく買う」のが大切だと述べています。そのほうが安く良いものを得て、プロダクトにフォーカスできるからです。

本書も§4.1.2において、「運用のための運用」問題を解決する手段としてNew Relicが有効であると主張しています。そもそも監視ツールはIaaSやPaaS、CDNなどのビルディングブロックが不調に陥っても正常に稼働することが求められるため、可用性や対障害性能といった要求が非常に高いのが特徴です。最悪、開発したいプロダクト以上に運用に力を入れるなんてことにもなりかねません。ので監視ツールを「作るのではなく買う」のは多くの場合、合理的な選択になるでしょう。

これに加えて本書§2.1.4では以下に引用するようにノウハウ、すなわち試行錯誤や積み重ねの結果をすべてのエンジニアに提供することを目指していると述べています(強調は筆者による)。オブザーバビリティの重要性を理解して多くの事例を見て支えてきたであろうSaaSベンダーのノウハウを使える、巨人の肩に乗れるというのも、監視にSaaSを使う大きな理由になるでしょう:

次に重要なステップが、収集したテレメトリーデータを意味のある情報として分析、可視化することです。つまり、ありとあらゆるデータを収集できていたとしても、その情報を活用できるかどうかがオブザーバビリティの真価を発揮できるかどうかの分かれ目となります。 従来、この作業は熟練したエンジニアのスキルと経験が必要とされるものでした。New Relic Oneではそのスキルと経験に代わるノウハウを、すべてのエンジニアに提供するということを目指しています

本書の魅力として最後に忘れてはいけないのは、New Relic日本法人に強力な技術メンバーが揃っていることの証明になっている点です。この本は日本法人による書き下ろしで、翻訳本ではないそうです。そして執筆陣10名のうち3名を個人的に存じ上げているのですが、いずれも魅力ある優れたエンジニアです。彼らのような専門家が日本の商習慣や組織を理解して顧客を支えてくれるサービスが日本にある、というのが本書が一番言いたいことなのかなと思いました。職場楽しそう。

オブザーバビリティの入門としておすすめの一冊

ということで単にオブザーバビリティを学ぶ入門書としても、New Relicというサービスを活用し実践する参考書としても、現場にある課題に立ち向かうヒントを得るための事例集としても活用できる興味深い一冊だと思います。運用の現場に関わっている方はもちろんそうでない方も「今技術をフル活用すると、どこまでサービスの実態から洞察を得られるのか?」を考えるきっかけを得ることができるはずです。New Relicを使うにしても使わないにしても、読んでみて損はないと思います。

*1:これは本書の主張ではなく筆者の意見

ソフトウェアプロジェクトではないGitHubリポジトリにどのようなライセンスを適用するか

$
0
0

ソフトウェアプロジェクトではないGitHubリポジトリにどのようなライセンスを適用するか?という問いを東京都オープン・ソース・ソフトウェア公開ガイドラインのIssueで見かけたので意見を述べてみます。結論を急がれる方は以下のサイトをどうぞ。

choosealicense.com

なお筆者は弁護士でも法律家でもないので、ここの記載内容はあくまでも参考に留めるようご注意ください。また本投稿では、Open Source Initiative (OSI)による承認を受けたオープンソースソフトウェアライセンスに限らず、その他のライセンスも含めて「ライセンス」と呼んでいます。

GitHubリポジトリにライセンスを適用しないとどうなるのか

GitHubの利用規約には以下の定めがあります:

  1. License Grant to Other Users Any User-Generated Content you post publicly, including issues, comments, and contributions to other Users' repositories, may be viewed by others. By setting your repositories to be viewed publicly, you agree to allow others to view and "fork" your repositories (this means that others may make their own copies of Content from your repositories in repositories they control). If you set your pages and repositories to be viewed publicly, you grant each User of GitHub a nonexclusive, worldwide license to use, display, and perform Your Content through the GitHub Service and to reproduce Your Content solely on GitHub as permitted through GitHub's functionality (for example, through forking).

またGitHubのヘルプには以下の記載があります:

You're under no obligation to choose a license. However, without a license, the default copyright laws apply, meaning that you retain all rights to your source code and no one may reproduce, distribute, or create derivative works from your work.

これを合わせると、publicなGitHubリポジトリにライセンスを適用しなかった場合、

  1. GitHub上での閲覧やforkは可能だが、
  2. そのコンテンツを複製・再頒布することはできず、また
  3. 派生物を作成することもできない

状態になると解釈できます。公開はしているが使っていいとは言っていない、というやつです。

なおこの場合でも「著作権法が適用される」という記述から著作権者を明確にするのは必須と考えられます。ライセンスを適用しない場合でも必ず README.mdなどをリポジトリにコミットして著作権者を明確にしてください。Organizationの方に説明が書いてあっても(利用規約によりforkが許可されている以上)不十分と考えられますので、必ずリポジトリ単体で説明責任を果たすようにしましょう。

ソフトウェアではないコンテンツの利用・再頒布・派生物を許可するにはどのライセンスを適用するべきか

以上の理由から、ソフトウェアではないコンテンツであっても第三者による利用・再頒布・派生物を期待するならば、ライセンスを適用する必要があると言えます。ではどんなライセンスを適用するべきでしょうか。

同じくGitHubが提供しているchoose a licenseというサイトには、オープンソースソフトウェアライセンスやメディア用のオープンライセンスを適用可能だと記載されています:

Any open source software license or open license for media (see above) also applies to software documentation. If you use different licenses for your software and its documentation, be sure to specify that source code examples in the documentation are also licensed under the software license.

確認のため、ここで前例を見てみましょう。いくつか有名どころのガイドラインについてライセンスを調べてみました:

Creative CommonsApache Licenseが利用されることが多そうです。Apache Licenseは以下に引用するとおりドキュメントが明確にライセンス対象として定義されていることから、オープンソースソフトウェアライセンスとしては使いやすいものと思われます:

"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.

"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.

またソースコードを含むリポジトリにおいては「ドキュメント内に掲載されるソースコード」に「ソースコードに適用するライセンス」と「ドキュメントに適用するライセンス」どちらを適用するか、明確にする必要もあります。AWSの例ではREADMEでこれを明確にしています

まとめ

GitHubでソフトウェアプロジェクトではないリポジトリを公開する場合においても、オープンソースソフトウェアライセンスやその他のライセンスを適用することが可能です。特に再利用や再頒布を期待するのであれば必須と言えます。現時点ではCreative Commons 4.0を適用することが多いようです。またライセンスを適用しない場合でも、著作権表示はすることが望ましいでしょう。

Viewing all 157 articles
Browse latest View live