PlantUML Web APIをSpark Framework + Kotlinなウェブアプリにしてみた

PlantUML を使うとき、 java -jar plantuml.jar だとほんの小さなダイアグラムの生成にも数秒かかってしまいます。ローカルではそれでいいかもしれませんが、ウェブアプリに組み込むのはちょっとイマイチですよね。

PlantUMLはJava製ツールなのでJavaのウェブアプリにしてしまえば高速になるはず、と思ってやってみました。

リポジトリ: https://github.com/gfx/plantuml-service

ウェブアプリといってもパスが /svg/:source しかないような最小限のものです。 :source はPlantUML Text Encodingでエンコードされたソース、または生のPlantUMLソースです。特にキャッシュなどはしませんが、手元のMBAだと小さなダイアグラムの生成で70msほどになったので実用に耐えそうです。

PlantUMLは plantuml-serverというウェブアプリも存在しますが、これはどちらかというとデモなので、純粋にもう少し小さなものが欲しかったのでした。

ウェブアプリケーションフレームワークとしては、SinatraライクなSparkを使ってみましたが、この程度の小さなものだとJettyを直接使っても大差ないかもしれません。Kotlinで書いたのは完全に趣味です。またビルドツールとしてはmavenではなくgradleを使っています。

これはデモも兼ねてHerokuにデプロイしています。Gradleで依存性の解決を行っているので特にKotlin由来の問題はありません。いつものHerokuアプリのように以下のファイルを用意するだけですね。

  • app.json
  • Procfile
  • system.properties (Java8を明示するため)

あとは Deploying Gradle Apps on Heroku | Heroku Dev Centerにしたがって、 build.gradlestage というタスクを用意して、そこでビルドを行うようにします。

以上。まだこれ自体はプロダクションに導入しているわけではありませんが、当初の目的であった高速化は達成できました。PlantUMLをJVMで動くウェブアプリにするというアイデアは効果がありそうです。

TypeScript 2.0+NodeJSツールを開発するときのプロジェクト構成

npm dependenciesを更新してGitHub Compare Viewのリンク付きでPRするツールを定期実行する - Islands in the byte stream

このci-npm-updateはTypeScript 2.0 (beta) で書いたので、TypeScript+NodeJSツールを開発するときのプロジェクト構成の一例としてざっと解説しておきます。

最近はRailsなどのウェブアプリのJSもnpmで管理するようになったため、そういう条件でNodeJSツールを開発することも増えてくることでしょう。

Table of Contents

エディタ

Visual Studio CodeはさすがにTypeScriptサポートはしっかりしていて、次のようにTypeScriptの型定義にしたがって補完をだせます。補完の際に引っかかりを感じることもないですし、構文エラーの指摘なども迅速です。

f:id:gfx:20160731215342p:plain

ただし今回はTypeScript 2.0 betaを使いたいので、 npm install --dev typescript@beta で入れたtypescript language service*1を使うような設定が必要です。

今回は .vscode/settings.json に、以下のようなJSONを設定しました。

{
    "typescript.tsdk": "./node_modules/typescript/lib/"
}

vscodeで本格的にプログラミングするのが初めてなら、ざっとドキュメントも目を通しておくといいでしょう。

とりあえずvscodeで最初におぼえるべきショートカット (for Mac) は command + shift + p (コマンドパレット)です。これはIntelliJ IDEAでいうところの command + shfit + a で、エディタコマンドを検索して実行するためのものです。最初はショートカットを無理におぼえるのではなく、コマンドパレット経由で呼び出すのが楽だと思います。

tsconfig.json

tsconfig.jsonはTypeScript compiler (tsc) に与える設定です。これを適切に設定しておくと、引数なしでtsc(1)を起動してもよしなにビルドしてくれます。

リファレンス:

tsconfig.json · TypeScript

ci-npm-updateでの設定:

ci-npm-update/tsconfig.json at master · gfx/ci-npm-update · GitHub

またtsconfigを作るときにプロジェクトの構成と配布形式を意識することになります。

つまり、今回はnpm distとして配布するので、TypeScriptソースファイルは配布物に含めず、ビルドしたJSと型定義ファイル *.d.ts をパッケージに含めます*2。また開発中は度々ビルドしてJSと型定義ファイルを生成するので、その成果物をどこに置くかを決めます。

成果物はデフォルトだとTSファイルと同じディレクトリにおかれます。このへんは好みだと思うのですが、私はこの挙動を変えたかったので、以下のような構成にしました。

  • src/ - TSファイル。npm distには含めない
  • lib/ - JSファイルと型定義ファイル。npm distに含める

そしてこれにしたがって outDir を設定します。

TSLint

コーディングスタイルを強制するツールです。

Visual Studio Codeのエクステンションを入れると編集中に報告してくれるのではかどります。

TSLint | Visual Studio Marketplace

なおtslintは "tslint:recommended" というプリセットがあるのですが、Visual Studio Codeのデフォルトのフォーマットルールだと警告をだす設定があり、一部変えています。なるべく奨励と銘打たれたスタイルで行きたいのですが、難しいものですね。

ci-npm-update/tslint.json at master · gfx/ci-npm-update · GitHub

Task Runner

今回はシンプルにしたかったし、TSファイルをビルドするだけなのでgulpやgruntは使ってません。そのかわり、npm scriptsを設定してコマンド一つでビルドできるようにしています。

ci-npm-update/package.json at master · gfx/ci-npm-update · GitHub

ビルドの際にtslintも通すようにしているので、たとえばmissing semicolonのよようなちょっとしたtslint違反でもビルドが通らないのですが、このへんは慣れれば減ってくるはずです。

Visual Studio Code Tasks

npm scriptsをvscodeから起動するために .vscode/tasks.json を設定しています。

リファレンス:

Tasks in visual Studio Code

プロジェクトの設定:

ci-npm-update/tasks.json at master · gfx/ci-npm-update · GitHub

(このJSONにはコメントを書けるようだ…)

開発中よく使うのは command+shift+b のビルドコマンドでした。

shrinkwrap

このプロジェクトでは npm-shrinkwrap.json をコミットしていますが、プロジェクトのドッグフーディングのために入れているだけです。。普通のCLIツールやライブラリではこれは不要なので真似しないでください。

所感

TypeScript 2.0とその開発環境は非常に良く出来ていると感じます。もはやES5とは別物といっていいくらい快適ですし、ES2015とくらべても生産性(かけた時間に対する品質のよさ)が高いと思います。

ウェブアプリでもどんどん使っていきたい。

See Also

*1:型定義に基づいた補完などを行うサービスで、TypeScript配布キットに付属しています。

*2:TSファイルも配布物に含めたいところですが、vvakame氏いわく、それをするとtscコンパイラがTSファイルと型定義ファイル両方みにいってしまうという問題があるとか。

npm dependenciesを更新してGitHub Compare Viewのリンク付きでPRするツールを定期実行する

タイトルに要素を詰め込みすぎましたが、要は CircleCIを使ってbundle updateを定期実行する - Qiitanpm update 版です。web appのJavaScriptライブラリ管理にnpmを使うとき、依存関係のアップデートを継続的に行うためのツールです。

https://github.com/bitjourney/ci-npm-update

これはいまのところGitHub専用です*1。CIサービスはドッグフーディングも兼ねてCircle CI用の起動スクリプトを同梱してますが、実際には ci-npm-update を定期実行するだけなので簡単に代替可能です。

これはCircle CI + Heroku Schedulerで動かしていて、以下のようなフローです。Circle CIはJenkins含め他のCIでも動かせますし、Heroku Schedulerはcronなどでも代替できます。

  1. Heroku Schedulerはci-npm-updateを実行するためのパラメータを渡してCircle CIのビルドを起動する
  2. ビルドのdeploymentフェーズで ci-npm-update --execute を実行する
  3. ci-npm-updateは npm-shrinkwrap.json を削除したあと npm install をしなおす((npm update --depth 9999 のほうが効率がいいはずなのですが、こちらはある程度の規模のプロジェクトだとOOMで落ちてしまうので npm install しなおすことにしました。))
  4. ci-npm-updateはさらに npm shrinkwrap で依存関係のバージョンを固定し、変更をcommitし、pushし、githubのpull-requestをつくる
  5. このときpull-requestはアップデートの前後のnpm-shrinkwrap.jsonをもとにgithub compare viewへのリンクをつくり、PRの本文に入れる

送られるpull-requestはこんな感じです。

https://github.com/gfx/ci-npm-update/pull/8

f:id:gfx:20160728000115p:plain


さて、それではこれを定期的に実行する必要がありますが、これは元エントリのとおりCircle CIのparameterized buildをHeroku Schedulerで起動します。

そのアプリのテンプレートも同リポジトリに入っているので、簡単に試したければ "Deploy to Heroku" ボタンで適当にHeroku appをつくり、Heroku Schedulerで定期実行します。たとえばci-npm-update自身の設定はこんな感じ。

f:id:gfx:20160728000608p:plain

あとは各種設定が必要ですね。

設定

Heroku

"Deploy to Heroku" ボタンでアプリを生成するときにCIRCLECI_TOKEN などの設定が必要なので、それらを指定してください。

TRIGGER_NAME は circle.yml でci-npm-updateを起動する条件分岐に使います。必要なければデフォルトでかまいません。

circle.yml

Heroku appの TRIGGER_NAME が渡ってきたらci-npm-updateを起動する、という設定を追加します。

ci-npm-update自身の設定はこんな感じです。

https://github.com/gfx/ci-npm-update/blob/master/circle.yml

抜粋:

deployment:
  update-dependencies:
    branch: master
    commands:
      - >
        if [ -n "${NPM_UPDATE}" ] ; then
          bin/ci-npm-update --execute
        fi

Circle CI

Circle Ciからは、(1) github repoにgit pushする権限 (2) github repoにpull-requestを送る権限 がそれぞれ必要です。

まずpushする権限をつくるために、repoに対してread/writeできるuser keyを作ります。

Circle CIの Project Settings -> Checkout SSH key -> Add user key

f:id:gfx:20160728002103p:plain

次に、GitHubのaccess tokenを生成してCircle CIに設定します。

GitHub Settings -> Personal access tokens で "repo" scopeをもつaccess tokenを生成し、 Circle CI projectの環境変数で GITHUB_ACCESS_TOKEN という名前で設定してください。

また、Circle CIでgit commitをするために git config user.namegit config user.email が必要なので、それぞれ環境変数GIT_USER_NAMEGIT_USER_EMAILを通じて設定します。

設定が済むとこんな感じです。

f:id:gfx:20160728091520p:plain

検証

もろもろうまくいっていれば、以下のコマンドでHeroku Schedulerを待たずにci-npm-updateを起動でき、pull-requstが送られるはずです。

heroku run -a $app './build-circleci'

成功すると、create pull-request apiの結果であるJSONが表示されます。

また、ローカルで実行する場合は、無引数で実行するとdry runモードで実行しPRの内容を確認できます。ただし、dry-runモードでも node_modules/ の内容はアップデートされるのでご注意ください。

まだ作ったばかりで導入実績も少ないですが、よければ使ってみてフィードバックをいただけると嬉しいです。

*1:github enterpriseでも動くはずですが試してません。他のgit hosting serviceも要望があれば対応するかも。

ExcelからtextareaにコピペするとHTMLのtableに変換するスニペット

ユースケース

  • Excelから社内ブログやWikiに表をコピペしたい

実装

とりあえず paste イベントをうけて処理するのでそのようにする。今回はCodeMirrorで制御されているtextareaなので、CodeMirrorを使ってないない場合は適宜読み替えてください。

ClipboardData

pasteで発行されるClipBoardEventに clipboardData: DataTransfer プロパティがあります。

spec: https://www.w3.org/TR/clipboard-apis/

// Web IDL
dictionary ClipboardEventInit : EventInit {
  DataTransfer? clipboardData = null;
};

こいつが items: DataTransferItemList をもっています。

// Web IDL
interface DataTransfer {
  attribute DOMString dropEffect;
  attribute DOMString effectAllowed;

  [SameObject] readonly attribute DataTransferItemList items;

  void setDragImage(Element image, long x, long y);

  /* old interface */
  [SameObject] readonly attribute DOMString[] types;
  DOMString getData(DOMString format);
  void setData(DOMString format, DOMString data);
  void clearData(optional DOMString format);
  [SameObject] readonly attribute FileList files;
}

なぜクリップボードの中身がリスト状の items になっているかというと、コピーしたものの表現が単一ではないからですね。

たとえば、ブラウザからのコピペはスタイルが適用されているので、 text/plain なプレインテキストと text/html なHTMLテキスト両方を含みます。画像の場合、参照URLがtext/plainで、画像のバイナリデータがimage/*で来ます。ただし、詳細はブラウザごとの違いも多く、たとえばLibreOfficeのスプレッドシートからのペーストは、Chromeだと画像化したtext/pngなitemが含まれますが、IEやFirefoxではテキストデータのみ存在します。

// Web IDL
interface DataTransferItemList {
  readonly attribute unsigned long length;
  getter DataTransferItem (unsigned long index);
}

さて、このitemsの要素は DataTransferItemで、クリップボードの中身の実体です。kindは文字列かファイルかという情報で、typeがMIME typeです。ただし、Firefoxなどitemsの存在しないブラウザもあります。まだ仕様が標準化されていないからでしょう。

// Web IDL
interface DataTransferItem {
  readonly attribute DOMString kind; // "string" or "file"
  readonly attribute DOMString type; // "text/plain", "image/png", ...
  void getAsString(FunctionStringCallback? _callback);
  File? getAsFile();
};

callback FunctionStringCallback = void (DOMString data);

ここで、ExcelのシートからChromeにペーストすると、 items の中身は text/plain, text/html, image/png が入っており、最後の画像データは該当部分のスクショになっています。Excelの要素をGitHub issuesのtextareaにExcelからコピペすると、画像が貼り付けられるのはそのためです。

画像のコピーの場合、itemstext/plain, image/png なので、text/htmlの有無が画像コピーとの違いとなります。

なので、「画像のコピーは画像としてアップロードして貼り付けて、Excelからのコピペは<table>...</table>に変換して貼り付ける」とするならば、以下のロジックでよさそうです。

  • text/plaintext/html のデータが存在して、 text/html のなかに table 要素が含まれるとき、その table 要素をペーストする

以上を加味すると、ペーストイベントをハンドルするイベントリスナは以下のようになるでしょう。

// JavaScript
var editor = CodeMirror.fromTextArea(...);

editor.on('paste', function(_, e) {
  // see https://html.spec.whatwg.org/multipage/interaction.html
  const clipboardData = e.clipboardData;

  const plainTextItem = clipboardData.getData('text/plain');
  const rtfItem = clipboardData.getData('text/rtf');
  const htmlItem = clipboardData.getData('text/html');
  const imageItem = (function (items) {
    if (!items) {
      return null;
    }

    for (let i = 0; i < items.length; i++) {
      if (items[i].type.startsWith('image/')) {
        return items[i];
      }
    }
    return null;
  })(clipboardData.items);

  console.log(clipboardData.types);
  console.log([plainTextItem, rtfItem, htmlItem, imageItem]);
  if (htmlItem && plainTextItem) {

    // rich contents, such as Excel and Power Point
    const html = new DOMParser().parseFromString(htmlItem, 'text/html');
    const tables = html.getElementsByTagName('table');

    if (tables.length) { // includes <table> tags
      const content = html.getElementsByTagName('body')[0].innerHTML;
      editor.replaceSelection(content);
      e.preventDefault();
      e.stopPropagation();
    } else {
      // TODO: ask users what to paste (HTML or plain text)
      // fallback to default
    }

  } else if (imageItem) {
    const blob = imageItem.getAsFile();
    const matched = blob.type.match(/^image\/(\w+)$/);
    if (matched) {
      const ext = matched[1]; // e.g. "png", "jpeg", or "gif"
      const filename = 'clipboard.' + ext;
      const formData = new FormData();
      formData.append('file', blob, filename);
      upload(formData);

      e.preventDefault();
      e.stopPropagation();
    }
  }
});

というわけで実装してみたものの、だいぶ複雑だしブラウザによる挙動の違いもあるのでちょっと使いづらい部分があります。

TSVやCSVをコードスニペットとして貼り付けるとtableとして表示する、というほうがいいかもしれないですね。

公開用DockerイメージにAndroid SDKを含めるのはライセンス違反という話

Android Software Development Kit License Agreementにこういう項目があります。

3.4 You may not use the SDK for any purpose not expressly permitted by the License Agreement. Except to the extent required by applicable third party licenses, you may not: (a) copy (except for backup purposes), modify, adapt, redistribute, decompile, reverse engineer, disassemble, or create derivative works of the SDK or any part of the SDK; or (b) load any part of the SDK onto a mobile handset or any other hardware device except a personal computer, combine any part of the SDK with other software, or distribute any software or device incorporating a part of the SDK.

まあ要は、変更したり再配布したりリバースエンジニアリングしたりするなってことですね。そして、Docker imageにAndroid SDKを含めて再配布するのはまさにライセンス違反というわけです。

DockerでAndroidアプリをビルドするのがそれなりに広まってきた様子ですが、Android SDKの含まれたイメージをDocker Hubで公開してはいけないということになります。

Android SDKライセンスが現状に追いついていないともいえるかもしれませんが、ライセンスはライセンスです。AndroidアプリをDockerでビルドしている各位はご注意ください。

私もうっかりDocker HubでSDK入のイメージを公開しているのですが、近日中に削除する予定です*1。これらに依存している場合はご注意ください。

削除予定のイメージ

*1:Dockerfileを公開することは問題ないので残します。

Makefileを自己文書化するハックを注入するスクリプト: inject-make-help

Re: Makefileを自己文書化する make2help | おそらくはそれさえも平凡な日々

ぼくもmakeはわりと使う方で、AndroidプロジェクトだろうとiOSプロジェクトだろうとよく使うコマンドセットをMakefileとして追加するのが大好きなんですが、self-documented Makefileは存在はしっていたもののセットアップが面倒でやっていませんでした。

じゃあ make2help はどうかというと、ただひとつのコマンドをインストールすると常self-documented Makefileを使えるという点では優れたアイデアなんですが、じゃあ今度はプロジェクトメンバーに make2help をインストールするように指示しないといけなくなってしまうのがイマイチだなあと。makeのメリットの一つは、敢えてインストールしなくてもだいたい入っているという点だと思うので。

というわけで、self-documented Makefile hackをMakefileに注入するスクリプトを書きました。まあホントはこのhackもgrep(1) とか awk(1) ではなく perl(1) で書き直したいところですが、とりあえずオリジナルのものを注入するだけです。すでに注入済みなら何もしません。

これなら、誰か一人が inject-make-help を実行したあとの Makefile をコミットしておけば誰でも make help が使えます。どうでしょう。

#!/usr/bin/env perl
# inject-make-help(1): To inject help hacks to the Makefile
use 5.10.0;
use strict;
use warnings;
use autodie;

# FIXME: use perl(1) instead of grep(1), sort(1), and awk(1)
my $help_task = q{
help:
    @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
} =~ s/^[ ]{4}/\t/xmsgr;

my $makefile = shift(@ARGV) // 'Makefile';

my $content = do {
    local $/;
    open my $fh, '<', $makefile;
    <$fh>;
};

if ($content !~ /\Q$help_task/xms) {
    $content .= $help_task;
    
    my($phony_tasks) = ($content =~ /^\.PHONY:([^\n]+)/xms);
    if (not defined $phony_tasks) {
        $content .= q{
.PHONY: help
} =~ s/^[ ]{4}/\t/xmsgr;
    } elsif ($phony_tasks !~ /\bhelp\b/xms) {
        $content =~ s/^(\.PHONY:[^\n]+)/$1 help/xms;
    }

    say "Inject help triks to $makefile";
    open my $fh, '>', $makefile;
    print $fh $content;
    close $fh;
}

ターゲットの Makefile はこんな感じ:

.DEFAULT_GOAL := help

foo: ## The foo task
  echo foo

bar: ## The bar task
  echo bar

これに対して inject-make-help をするとこんな感じになります:

.DEFAULT_GOAL := help

foo: ## The foo task
  echo foo

bar: ## The bar task
  echo bar

help:
   @grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'

.PHONY: help

.PHONY は既存のものがあればそれに対して help を追加します。

git branch の結果を時間順にソート: git branch --sort=-authordate

id:kazuho さんと「gitのbranchを消すべきか否か」という話をしていて、ぼくの「ローカルにせよリモートにせよbranchが増えすぎると目的のブランチを見つけられない」という意見に対して次のエントリを教えてもらったのでした。

git branch の結果を時間順にソート - kazuhoのメモ置き場

一理あるかもしれないと思ってこれをgitに組み込むためにgitのソースコードを眺めていたら、実はもうできるということを知りました。それがこれ:

# 新しいのが下
git branch --sort=authordate

# 新しいのが上
git branch --sort=-authordate

このソートに使えるフィールドは、 git branch --help を引くと "The keys supported are the same as those in git for-each-ref." といわれるので、 git for-each-ref --help を引くとそこにいろいろ書いてあります。

なおソースだとこのあたりで定義されているようです。

git/ref-filter.c at v2.8.4 · git/git · GitHub

追記2:

git branch のデフォルトオプションでいい気がしました。コピペ用:

git config --global alias.branch 'branch --sort=-authordate'

追記1:

.gitconfigエイリアスでも足しておくとよさそうですね。

[alias]
    br = branch --sort=-authordate

はてなブログでRust対応のアップデートをしてほしい!

お題「シンタックス・ハイライト機能で対応してほしい言語」

Rust のシンタックス・ハイライトは対応されているようですが、この日記を書いた時点だと、extern, match, where などがハイライトされていなくて、対応バージョンが古いような気がします。シンタックス・ハイライトのアップデートをお願いします!

例:

// echo.rs
extern crate getopts;

fn main() {
    let args: Vec<String> = std::env::args().skip(1).collect();

    let mut opts = getopts::Options::new();
    opts.optflag("n", "", "do not output the trailing newline");
    let matches = opts.parse(&args);

    match matches {
        Ok(m) => {
            show(&m.free);

            if !m.opt_present("n") {
                print!("\n");
            }
        }
        Err(_) => {
            show(args);
            print!("\n");
        }
    };
}

fn show<C: IntoIterator>(args: C)
    where C::Item: std::fmt::Display
{
    let mut i = 0;
    for arg in args {
        if i > 0 {
            print!(" ");
        }
        i += 1;
        print!("{}", arg);
    }
}

github.comのアカウントは仕事用と私用で分ける方がいいの?

追記(2019/04/11): sonots氏がGitHubの方と相談しつつ設計した運用方法が公開されました。

全社的に会社用GitHubアカウントを廃止した件 - ZOZO Technologies TECH BLOG

このガイドラインは今後のデファクトスタンダードになると思うのでtl;drを引用します。

  1. 個人で会社用と私用の2つの無料GitHubアカウントを持つことはGitHubの規約「非」準拠だった
  2. 会社用GitHubアカウントを廃止し私用GitHubアカウントを利用する規定に変更した
  3. セキュリティを担保するためGitHubのSSO機能を利用した

GitHubの規約的には、おそらく「会社として会社用アカウントを pro版にする」「個人が身バレを防ぐために個人アカウントをpro版にして会社用アカウントを別途作る」などの運用も可能だとは思います。しかし、GitHubというサービス自体マルチアカウントで使うような設計になっていないため、よほどのことでもないかぎりはこの「アカウントを分けない」というガイドラインでやっていくのが王道だということが示されたと思います。

以下もともとの本文は、記録のために そのまま 残しておきます(下記エントリにある「会社用アカウント」は、sonots氏のエントリによれば、(個別にpro版にしないかぎりは)フリーアカウントに該当するということが示されています)。


一行まとめ:分ける理由・分けない理由両方あるのでどちらにすべきということはない

会社で github.com (not GHE) を採用するにあたって、アカウントについてガイドラインを制定すべきなのかどうか悩んでいます*1。とりあえず現状把握のためにアンケートを取ってみました。

だいたい 1対2くらいで「分けている」と「分けてない」に別れる結果となりました。私のアカウントは「分けていない」し、周りでも分けている人をあまり見かけなかったので、分けないのが普通と思っていたのですが、意外と分けている人が多く「分けないのが普通」とはいえないなというのが第一印象です。

分けないメリットは個人にも会社にもあると思います:

  • アカウント所有者にとっては管理が単純
    • github.com はアカウント切り替えが簡単ではない(2FAを有効にしていると特に)のでなおさら
  • 「仕事でOSSにコミットする」というケースを個人の成果としても積み上げられる
  • 「プライベートでOSSにコミットする」というケースを会社のポジティブなイメージにも繋げられる

一方で、分ける方も言い分はあります。

  • 仕事とプライベートの活動を混在させたくないという思いはあって当然だと考えられる
  • 実際、家にいる時も会社のリポジトリの通知やアクティビティが見えてしまうのは嫌だという意見を聞いた
  • アカウントを分けないと実名とネット上のアイデンティティが紐付けられやすくなり、プライバシーの問題が起きうる
    • 会社のorganizationを管理する側としては、アカウント名は自由でよくても見えるところに本名を設定してほしいという願いがある
    • その結果、「会社としては、本名とハンドルネームをひも付けてほしい」ということになる(それをルールにするかどうかは別として)
    • 「身バレしたくない」という個人の願いと「管理しやすい状態であってほしい」という会社の願いが矛盾する
      • その結果として生まれるのが アカウント管理台帳 だとしたら哀しい世界だが…
  • 一般論として、クラウドサービスのアカウントは個人用と会社用で分けるべきという考えもある
    • たとえば、Google accountなどは分かれていてしかるべき(たとえGoogle Apps for Workを採用していないとしても)
    • ただしこの点では github.com は「会社としても個人としても分けないメリットがある」という性質をもつので一般論を適用する必要はないと思っています

無難なとところとしては、会社としてはルールは作らず、GitHubのアカウント管理方法を説明して「どちらでもよい」とするしかないのかなという気がします。

ここで上げていない分ける理由、分けない理由もあると思うので、もし思いついたらコメントなどいただけると幸いです。

*1:https://help.github.com/articles/github-terms-of-service/ によると、複数のfree accountは認められないとありますが、会社用アカウントはfree accountではないと考えられるのでここではアカウントを分けることは利用規約に準拠していると解釈して話をしています。

Android Instant Apps FAQをざっと眺めた

Google I/O 2016で発表されたアプリをインストールしなくても使える "Android Instant Apps" ですが、技術が不明ということで様々な憶測を呼んでいます。

developer.android.com

これについては、すでにFAQがあっていくつかの疑問には答えられていました。

https://developer.android.com/topic/instant-apps/faqs.html

まとめると

  • Android 4.1から使える
  • プロジェクトごとに成果物(APK)は通常版とinstant版の2つのビルド設定を持つ
    • "Developers simply configure the project to create two build artifacts: the installable APK and the instant version"
  • instant版は通常版と同じAndroid APIが使えるが、バックグラウンドサービスなどは利用できない
  • パーミッションモデルはruntime permissionsを使う
    • 「古いデバイス用の追加作業は不明」と書いてあるが…?
    • Google Play servicesが処理を担うからパーミッションはいらないのかな?
  • publishは通常版とおなじくGoogle Play Developer Consoleで行う

これを読んでもよくわかりませんが、専用のbuild variantでAPKを作ってpublishする感じに見えますね。