Kikuchy's Second Memory

つくる楽しさをもっと伝えたい。プログラムを書いていて、わからなかったこと・気付いた事を書き留めています。

GPD Winで通勤中にコーディングしたい

GPD Winが安くなっていたので衝動的に買ってしまいました。

この端末は元々ゲーム用ですが、何と言ってもボタン式キーボードがついているのが魅力。
日本の通勤電車の中でも使用できる、学生/サラリーマンの味方です。
パンタグラフ式キーボードは、立っているときに両手で使用できないので却下)

普段は家でも会社でもMacを使っていて、コードを書く場合もVimスクリプトを書くか、IntelliJJavaを書くか、という使い方をしています。
GPD WinにはWindows 10 Homeが入っているので、とりあえずBash on Ubuntu on Windowsで運用して遊んで見ることにしました。
気に食わなかったら適当にLinuxのディストリを見繕って入れるつもり。

Windowsで快適に過ごす環境を整える

Zeal

Macでは言語やライブラリのマニュアルを引くのにDashを使っています。

Windowsでも使える同じようなZealというものがあるようなので、これを使ってドキュメントを引くことにします。

Zeal - Offline Documentation Browser

フォント

SourceCode Pro for Powerlineを入れます。
Vimでlightlineを使っているので、対応したフォントを使えるのは嬉しい。

github.com

ランチャーは検討中

MacではAlfredを使っていてDashもそこから引けるようにしているので、できれば同じようなことをしたいところ。
アプリケーションランチャーとしてはスタートメニューだけで事足りるのですが、Zealを引くことのできるランチャーが果たしてあるのかはまだわかりません。


Linux環境を整える

Creators Updateを入れる

Creators UpdateからUbuntuが16.04になったらしいので、新しいものは良い、の精神で放り込みます。

放り込んだらば、WifiSSIDを認識しても接続ができない、という状態に陥ったので、Wifi Patchをあてます。

www65.atwiki.jp


あとは Bash on Ubuntu on Windows をインストールして、bashをぺちぺち叩いていきます。

git, gcc, zsh

何がなくともgitもgccもないと何もできません。
clangではないのは、この世にはgccじゃないとビルドできないものがまだまだたくさんあるから…

zshの保管機能が優秀すぎてそれなしでは生きていけない体になってしまったのでzshも入れます。

$ sudo apt install git build-essential zsh

vim

aptにはまだvim 8が来ていないので、有志が作ってくれたppaを使います。
tipsonubuntu.com

普通に install vim するとluaだとかが有効にならずneocompleteが使えないので、gnome全部込みのやつを放り込みます。

$ sudo apt install vim-gnome

dotfile

私は個人用のdotfileをgithubで管理しているので、gitもvimも入ったところでおもむろに放り込みます。

github.com


そしてvimを起動したらプラグイン類をインストール。

:call dein#install()

もしかしたら先にX Server入れておかないと、githubのユーザー名とか聞かれたときに動かなくなるかも?
githubのユーザーIDとかを聞かれて、プロンプトに入力できずタイムアウトで死んだ)

anyenvとphpenv

今書きたいプログラムはPHPなので、phpenvを入れておきます。
phpのビルドにはなんだかんだたくさんパッケージが必要なので、この際全部放り込んでおきます。

インストールはこちらを参考にしました。
qiita.com

PHP7.1.6ではbisonは最新でも問題なかったです。
あと、このままではビルドが通らなかったので、いくつかパッケージを足しました。

$sudo apt install libssl-dev libmcrypt-dev libreadline-dev libxslt1-dev libxml2-dev libbz2-dev libcurl4-openssl-dev libpng-dev libjpeg-dev libmcrypt-dev libsqlite-dev libtidy-dev libltdl-dev make autoconf automake re2c lemon libsasl2-dev pkg-config bison

Windows環境とLinux環境を上手く両立させる

WSL Terminal

流石に標準のcmd.exeではフォントとか選択肢が狭すぎるしコピペもままならないのがつらすぎるので、WindowsSSHしたりmingw使ったりしてたときに使ってたminttyを使いたいところ。

あと、Explorerで開いているディレクトリをbashでも開きたいときが多分出てくるので、そこも対策したい。
カレントディレクトリからbashを起動できるようにしてくれるWSL Terminalなるものがあるということなので、とりあえずこれを使ってみることにしました。

github.com


etc/wsl-terminal.conf にシェルを指定できる項目があるので、bashからzshに書き換えておきました。

X Server

gvimを使いたくなることもある気がするので、VcXsrvを入れてスタートアップで起動するようにしておきます。
あとはprofileの方にもDISPLAY環境変数を設定しておきます。
sourceforge.net

export DISPLAY=localhost:0.0

今のままだとgvimのメニューなど日本語部分が文字化けするので、Windowsで使えるフォントを放り込んでフォントキャッシュを再作成します。
こちらを参考に行いました。
d.hatena.ne.jp


これで無事にgvimも使えるようになりました。
WindowsデスクトップにUbuntuのウィンドウが出てるってなんだか新鮮。

現在の感想

CPUがAtomなので、非力さは否めない感じ。
コンパイルとかとても時間がかかるので、もしできることなら別のマシンでクロスコンパイルしたものを持って来たい気分になる。

キーボードは全体的に端末の左側寄りに配置されているので、右手はいつも突っ張った感じになる。
ホームポジションにポッチがあるのでタイピングはそこそこしやすい。
WindowsではAlt + F4をよく使うけれども、Function類はFn + 数字キーでの入力なので、とても入力できない。せめてAltとFnが隣同士になっていてくれれば良いのだけれど…

ジョイパッドはそこそこよい操作感。
細かいマウス操作は慣れが必要。
スクロールは上下しかできないので、左右にもできたらもっと嬉しかった。

画面がタッチパネルなのは嬉しい。
ブラウザで前のページに戻るときや、いちいちマウスカーソルを移動させるには遠かったりするときに、指で操作しちゃうと便利。
というか日々スマホを使っていると「手持ち端末の画面は触るもの」という意識になっているので自然と触ってしまうので、触れるのは嬉しい。

しばらくはこのまま運用してみたいと思います。
飽きたら…どのLinuxディストリを試そうかなぁ。

一つ、父を超えた

とてもとても技術とか関係のない話ですし、とてもしみったれた小さな話ですが、個人的に感慨深かったので忘れないように。



Google I/O 17で、KotlinがAndroidの公式開発言語になったという発表がありました。

www.publickey1.jp




早くから(それこそ1.0が出る前から)この言語は主流になると思ってプロダクトに取り入れる活動などをしていたので、実際に主流になったというのは感慨深いものがあります。


さて、感慨深いと同時に、「父を超えた」ことができたと思いました。

      • -


私の個人的な考えでは、「子供は親を超えるもの」だと思っていますし、子供はそれを目指すべきだと思っています。
老いては子に従え」と言いますが、親を導くためにはそれなりの子供になっていないと、と思っているわけです。

私の父は技術者(と言ってもメカの設計が専門で、情報系のエンジニアではありませんでした)で、家電好きでもありました。
父はもう15年ほど前に他界しましたが、それまでの間、最新の家電や電子機器をいくつも(母親が許す範囲で)家に導入していたものです。

中にはいくつかの規格が覇権を争っている最中に購入したものもあります。
特に私の記憶に残っているのはこの2つです。

  • VHSとBetaが争っていたとき -> Betaのビデオデッキを購入
  • MOとCD-RWUSBメモリが争っていたとき -> MOドライブを購入

ことごとく「スペックは良いが派遣を握れなかった」ものを選んでいました。
技術者としてスペックが良いものを選ぶのは自然な思考だと思いますが、どうにもその先行きまでは見通せていなかったようでした。


父を超えた、と思うのは、覇権を争うものの中から覇権を取るものを選べたこと。

私が会社で開発していたプロダクトにKotlinを導入しようとしていたとき、Alt-Java言語としては他にも

などの候補がありました。
特にScalaは当時はKotlinより知名度が断然高く、case classなどボイラープレートを省略する文法、便利なライブラリ、強力な型システム、サーバーサイドでの利用実績が魅力的でした。

Alt-Java言語を使いたかったのは、Javaの冗長さを疎んでのことでした。


それでも「導入してしまえばこの先数年は使い続けることになる(そしてAndroid開発での主流にならなければ負債にしかならない)」という視点は大事です。
Kotlinは、Javaとは大きく変わらないけれどもとても便利になっている文法と型システムを持っていたのが「この言語は使われるようになる」と考えた決め手でした。

導入から1年近くたち、結局KotlinはAndroid開発言語の公式言語にのし上がりました。

父は技術のその先を見通せなかった(かもしれない)が、私は(少なくとも今回は)見通すことが出来た。
果てしなく小さな一歩でしたが、父を超えられたと思いました。
少なくとも父よりは大衆に認められるものを見極める力があるぞと。


まだまだ超えられない父の壁はたくさんありますが、これからも精進していきたい所存です。
これからも空の上から見守っていてくれたら、嬉しいです。

読みやすいコードとワーキングメモリ

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

3年ばかり前に『リーダブルコード』という本を図書館で借りて読んだ(ので詳細な内容を忘れてしまった)のですが、
こういった本が出版されるほどに、エンジニアは読みやすいコードを求めているのだと感じます。

コードの品質については様々な要素があります。その中に、可読性というものも入るでしょう。

可読性の高さは、コードの理解を容易にします。
コードの理解が容易であれば、変更も加えやすく、拡張もしやすくなる可能性があります。

その可読性も、いくつかの要素から成り立っているようです。

  • トークン単位 ... 命名は妥当か。値やメソッド名、クラス名から挙動などの想像がつくか。
  • 式単位 ... プリミティブな命令の単位。どのような命令なのか、見てわかるか。
  • 制御文、スコープ、メソッド単位 ... この文やスコープの意味するところは何なのかを、想像できるか。
  • クラス、モジュール、ファイル単位 ... 理解しようという気になるか。


これらすべての根底には、読者にかかる認知的負荷を低くできるかどうか、という問題が横たわっています。
認知的負荷というのは、一時記憶(ワーキングメモリ)の圧迫と言い換えられるでしょう。
要は、覚えておけるかどうか、です。

人間の一時記憶は 7±2 個のことがら(チャンク)しか貯蔵できないと言われています(マジカルナンバー・セブン)。
コードを書いている本人ならともかく、読む人はたくさんのことがらを記憶できません。

しかし、記憶できることがら(チャンク)は、意味のある一かたまりであれば、ある程度記憶がしやすくなるのです。

例えば数字列。

097153754865

これを覚えろ、と言われてもなかなか難しいかもしれません。
数字一つひとつを記憶しようとしても、12個あるわけですから、7±2 を明らかに逸脱しています。

では、こちらは?

0971 - 5375 - 4865

まだ覚えやすいですね。
例えばこれが紙に書かれた電話番号だったとして、番号を打ち込むのが少しは楽になりそうです。
一つの塊は4桁ですから、塊ごとに記憶するのは容易。
その塊も3つですから、数字を一つずつ覚えこもうとするよりかははるかに楽になります。

コードについても同じことが言えます。
なるべく、単純化・抽象化した塊で捉えることで理解が楽になるわけです。

// 昔メンテナンスしていたプロダクトでこんな感じのコードを見たことがあります
boolean ret;
if (isSucceeded(results)) {
    if (results.targets.size() > 0) {
        ret = true;
    } else {
        ret = false;
    }
} else {
    ret = false;
}
return ret;



// 変数が減れば、頭に入れておくべきことが減ります。
// 行数や制御構文が減れば、「このまとまりが何をしているのか」を少ない労力で考えられます。
return isSucceeded(results) && (results.targets.size() > 0);

ある特定の操作をメソッドに抽出する、というのも有効な手段です。

// ナイーブに実装すると
int index = -1;
for (int i = 0; i < elements.size(); i++) {
    Element e = elements.get(i);
    if (e.id != target.id && e.name.equals(target.name)) {
        index = i;
        break;
    }
}




// 特定の操作をメソッドに置き換える -> 抽象化する ということです
int index = indexOf(elements, () -> e.id != target.id && e.name.equals(target.name));
/* (ラムダ式部は、以下の省略形です)
new Predicate<Element> {
    boolean test(Element e) {
        return e.id != target.id && e.name.equals(target.name);
    }
}
*/

// 最終的な行数は増えますが、こちらのメソッドの実装は頭に入れなくても良いでしょう
// 「特定の条件を満たす要素が格納されているインデックスを探し出す」という役割だけを覚えておけばいいのですから
public boolean <T>  indexOf(List<T> list, Predicate<T> predicate) {
    for (int i = 0; i < elements.size(); i++) {
        T t = list.get(i);
        if (predicate.test(t)) {
            return i;
        }
    return -1;
}


単純なことを複雑に実現することは楽なのです。
なぜなら「実現する」という最低限がすでにできているのに、「単純化する」という+αに頭を使わなくて済むから。
書いた行数が増えれば、なんだか仕事した感じにもなりますし。

単純なことを単純に実現する
できないことではないのですが、疲れるタスクです。
書いた行数が成果とされるような(Web系でそんな職場は存在しないと信じたいですが)ところだと、マイナスに働くかも。
ですが、書いた自分がやっておけば、今後のこされたコードに触る人全員の労力を削減できます。
また、それだけ考えることができる人だと周囲も認識してくれますし、それが自信をつけることにも繋がるでしょう。

読む人に苦労をかけないコードを残していきたいものですね。

モジュール設計のGood UI/ Bad UI

意図しない誤操作を誘発したり、意図する操作を実行することが困難だったりするUIのことを、私はBad UIと呼んだりしています。

一度プロダクトとしてBad UIが出来上がって、出荷もされてしまうと、使う側はプロダクトのUIを変えることができないので、どうにか利便性を向上させようと工夫をこらします。

で、ここがBad UIのBadたる所以ですが、利便性を上げようとしても、どうも頓珍漢な方向に人間を導くのです。
時々Twitterなどで見かける、説明書きのシールが所狭しと貼られたセブンカフェのコーヒーメーカーとかが顕著な例だと思います。


http://twicolle.com/wp-content/uploads/2015/01/B8f9m6aCAAAnInF.jpg
引用元: twicolle.com


どうも人というのは、安易に言葉による説明を行いがちな気がします。
セブンカフェの例であれば、言葉で全てを表示しようとするから、上記写真のように愉快な悲惨なことになるのではないでしょうか。

ではBad UIの反対のGood UIはどんなものかと言いますと、私個人としてはレゴブロックが一番よいUIであると思っています。

http://s3-ap-northeast-1.amazonaws.com/topicks/article_thumb/21181_original.jpg
引用元: http://topicks.jp/21181

いかにも組み合わさりそうな、凸部分に凹部分があります。
それらをを押し当てれば、想像通り、二つのブロックがくっつく。
そこに言葉はいらない訳です。見るか触るかすれば機能と使いかたを想像できます。
説明不要&期待通り。それがGood UIだと考えています。



さて、プログラミングについても同じことが言えるのではないでしょうか。

ある働きをするクラスやメソッドの入力値にかかる制約を、「ドキュメントコメントに書いているから」とそれで満足していませんか?

// Bad API


/**
 * 日時から曜日を算出します。
 *
 * @param year     年。正の整数
 * @param month 月。0-11の値、1月は0、12月は11
 * @param day      日。1以上31以下の整数
 */
public String nameOfDayOfWeekFromDate(int year, int month, int day) {
    ...
}

/**
 * 曜日が休日かどうか判断します。
 *
 * @param dayOfWeek 曜日名。"mon", "tue" などの省略形
 */
public boolean isHoliday(String dayOfWeek) {
    ...
}

...

// 書いた人以外の人が読んだらどう思うでしょうか。
// 引数に数値ならなんでも入っちゃうけど大丈夫?
// 10月なんだろうけれど、1を引いている意図は?
// 戻り値は一体どんな形式?
String dow = nameOfDayOfWeekFromDate(2016, 10 - 1, 20);

// 引数には曜日入れるっぽいけれど、どんな文字列入れていいの?
if (isHoliday(dow)) {
    ...
}


あるいは、レゴブロックのように「組み合わさるからOK」というインターフェースにはできないでしょうか。

// Good API

/**
 * 曜日を表現します。
 */
public enum DayOfWeek {
    MONDAY,
    TUESDAY,
    ...
}

/**
 * 日時から曜日を得ます。
 *
 * @param date 日付
 */
public DayOfWeek dayOfWeekFromDate(Date date){
    ...
}

/**
 * 曜日が休日かどうか判断します。
 *
 * @param dayOfWeek 曜日
 */
public boolean isHoliday(DayOfWeek dayOfWeek) {
    ...
}

// 引数はDateをとる…日付が必要なんだな。考えることが少なくて良い。
// 戻り値は曜日を表すわけだな。表現形式とか気にしなくていい。
DayOfWeek dow = dayOfWeekFromDate(new Date());

// DayOfWeekオブジェクトしかはいらないから、これを入れよう。おっ、ちゃんと動くぞ!
if (isHoliday(dow)) {
    ...
}

レゴブロックの凹凸に相当するもの。

です。

intやStringなど、汎用的すぎる型で必要なデータを取りそろえようと思ったら、制約条件をコメントに書くしかない、使う人に読んで理解して記憶して気をつけておいてもらわないといけない。
すなわち、使う側の人間に認知的負荷をかけなければいけない、ということになります。

そこで、もう少し表現を特殊化した型を用意してはいかがでしょう?
「この引数にこのメソッドの戻り値が当てはまるから入れて見る」という、ほとんど考えなくてもできるような作業でも、その結果として適切に動く可能性を飛躍的に向上することができるのです。
しかもチェックするのはコンパイラわざわざ人の力を借りる必要はありません

全てが型でどうにかなるわけではないですが、それでも使える範囲で使っていきたいものです。

最近ではKotlinやSwiftが型でnullableであることを表現できる(Optinal型)ようになっているので、null値を許容するのかしないのか、安全なのかそうでないのか、これも是非とも型で表現したいですね。してくださいマジで。

Androidオールスターズ2で発表してきました

硬めのお話は会社ブログで書いた通りです。
↓ よんでね

developer.diverse-inc.com


が、ブログの趣旨から外れるから会社ブログに書けなかったけれど誰かに伝えたいよもやま話があるので、つれづれと書いておきます。
自分が忘れないように。

続きを読む