空想犬猫記

※当日記では、犬も猫も空想も扱っておりません。(旧・エト記)

Burgmüller 25 Progressive Pieces, Op. 100

最後の更新から一年半。もはや日記としての機能もないが、後から読み返す自分のために説明しておくと、数ヶ月前からコロナ禍でリモートワークが始まったのであった。元々「世界中どこに居ても出来る仕事」が仕事を選ぶ条件であったので、リモートであること自体には特に支障がなく、普通に仕事をこなしている。

景気は良くないけれど、悪いことばかりではなかった。通勤のために燃やしていたガス代が節約され、住宅ローンの金利がここ数年で最低を更新し、借り換えによって月々の返済額が減った。

そして大きかったのが、必要のなくなった行き帰りの通勤時間ぶん約1時間強の自由時間が新しく生まれたことだ。元々通勤時間の車の運転も音楽や講義の視聴も、それなりに充実していたはいたが、せっかく家で何でも出来るのだからということで、細々続けていたピアノの練習を再開したのだった。これは第一に自分のためでもあると同時に、なかなかピアノの練習が習慣付かない子供たちに、毎日続けることの大切さを見せて、啓発する狙いもある。

ハノンは毎日、10曲ずつくらい、Burgmüller は1週間に1曲通して弾けるようにして、覚えた曲は毎日弾くという方針。ハノンは80 bpm くらいから始めて、慣れたら 2 bpm ずつくらい速度を上げ、現在 92 bpm でしっかり弾けるように練習している。このあたりの練習法は森本麻衣さんの動画を始め、YouTube に上がっているいくつかの解説を参考にした。なぜ Burgmüller なのかというと、初めから挫折しない程度の難易度で、興味を持った子供たちにも手が届いて、かつ一つ一つの練習曲が音楽的に面白いと思ったからである。

実際に練習を始めると、子供の頃には気づかなかった発見がいくつもあった。今後、リモートワークが続く限り、進捗を一つ一つを書き留めていけたらと思う。

楽譜はこれ。教師が居ないのでCD付きなら間違いないだろうという安直な理由で選んだ。

Clean Architecture

色々な場所で話題に上がっていた Clean Architecture(原著)を読んだ。

自分自身、実は「自称・アーキテクト」として10年以上、とあるソフトのアーキテクチャを請け負っているので、自分の中に言語化されていないノウハウがそれなりにあった。私にとってうれしかったのは、それらの言語化できていたかったノウハウが多少言語化されて整理されていたことと、この本自体が割と広く有難がられていることである。個人的に役立ったのは Chapter 13 の Component Cohesion についてだった。

プログラムの設計を議論する場合、正論と正論が矛盾するという厄介なことがしばしば起こる。経験の浅い頃は、なぜそういうことが起こるのか分からず、結局最後までネチネチ煙に巻く人の意見が通ってしまい、後で苦労することになることがあった。あるいは、正論を盾に責任を果たそうとしない口達者にも手を焼いた。経験を積んでからは「ごもっともだけど、それは今重要じゃない」と言えるようになった。この本を読めば、REP-CCP-CRP 原則のテンション・ダイアグラムを持ち出して、何をすべきかをより明確に説明できることだろう。何よりも、3つの原則がそもそも緊張関係にあることが前提なところから話が始められるようになったこと、また、アーキテクトの仕事が一つの完全な正解を導くのではなくて、与えられた境界条件から、開発効率を最大化するためにパラメータを調整することであることを、共通の言葉で説明できるようになったことが大きい。

振り返ると、基盤中の基盤ライブラリは、社内向けであっても REP の原則を最初から厳守していたし、派生プロダクトのコードをフレームワークに追加するときには CCP の原則で外に括りだすことをお願いしたこともあった。そのような数々の技術的決断を、後から答え合わせする形で再定義できた。

新たな製品をデザインするときに、コアのロジックの議論に集中したいときに「バックエンドデータベースはどうしますか?」みたいな話が出たら、「The Database Is Detail. この本読んで」。みたいな使い方ができて捗るかもしれない(しないけど)。

あ、そうそう、この本できっちりと「a software architect is a programmer; and continues to be a programmer. (p.136)」と言い切ってくれたのも、この本が使える信用できると思った理由の一つだ。

告白すると、一応、タイトルに冠されてる Clean Architecture の章まではちゃんと読んだが、以降は斜体で強調されているステートメントと結論以外は斜め読みした。その他、コンポーネントの依存関係で、なぜ circular dependency が良くないかは、それらのコンポーネント群が、結局一つの塊としてコンポーネントになってしまって管理コストが上がることは、子供のおもちゃを使ってもっと簡単に説明できると思った。コールバックメカニズムを用いて依存性問題を解消する実装上のテクニックを dependency inversion と言って仰々しくするとってつけたようなコンサルタント用語の類も、頭の片隅に入れておけば十分である。それらは言語化されているという点で便利な概念だけど、まだ本質を掠めている程度であるからだ。蛇足を承知で言うと、導入の章でソースコードの行数をもって生産性の指標にしているのは単純化しすぎと感じた。なぜならば、コーディング技術が向上したりプログラミング言語そのものがバージョンアップして改良されたりすることで行数が圧縮されるのは、生きているソフトウェアでは起こりうることだからだ。そしてそれはアーキテクチャとは関係がない。

個人的には仕事柄この本はとても有益だった。一方で、この本を読んでポカンとして何も響かなくても、別にそれがダメとも思わないし、むしろ本書に出てくるキーワードでマウントをとるアーキテクトにならないようにしようと心に刻んだのだった。

Clean Architecture 達人に学ぶソフトウェアの構造と設計 (アスキードワンゴ)

Clean Architecture 達人に学ぶソフトウェアの構造と設計 (アスキードワンゴ)

Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series)

Clean Architecture: A Craftsman's Guide to Software Structure and Design (Robert C. Martin Series)

Firefox設定メモ(2018年1月版)

Firefox設定メモ ~MS PゴシックをMeiryo UIに置換~ - 空想犬猫記 を久々にアップデート。

Firefox Quantum では使えなくなる可能性はあるものの、現状の Firefox 57 では、まだ userContent.css によるフォントの置換テクニックが有効であった。(参考: Modifying the Default Skin - Mozilla | MDN

最新の設定では、置換先のフォント名は明示的には書かず、すべて sans-serif にしておき、一方で sans-serif のフォント設定を、自分が一番読みやすいフォントに設定しておくという方式にした。個人的には Yu Gothic UI がお気に入り。

@charset "UTF-8";
@font-face {
  font-family: "MS Pゴシック";
  src: local("sans-serif");
}

@font-face {
  font-family: "MS PGothic";
  src: local("sans-serif");
}

@font-face {
  font-family: "MS P明朝";
  src: local("sans-serif");
}

@font-face {
  font-family: "MS PMincho";
  src: local("sans-serif");
}

@font-face {
  font-family: "MS UI Gothic";
  src: local("sans-serif");
}

Rust雑感

年初から、また少しだけ Rust(The Rust Programming Language)というプログラミング言語を覚え直していた。リンク先のサイトには以下のような特徴が挙げられている。

  • zero-cost abstractions
  • move semantics
  • guaranteed memory safety
  • threads without data races
  • trait-based generics
  • pattern matching
  • type inference
  • minimal runtime
  • efficient C bindings

平たく言うと、メモリ安全で、データ競合も起こらず、C言語並みに軽くて速いという。さらに調べてみると、ジェネリクスはもちろん、trait objects を使った仮想関数テーブルによるポリモーフィズムに加えて、メンバ変数を持てる enum と match 文でパワータイプによるポリモーフィズムもサポートされているという尖りまくりの言語であることがわかった。

しかしながら、

trait objects は、なんかちょっと欲張って取ってつけた感が否めない。
途中から出てきた ref キーワードも、なんか必然性を感じない。
ところどころでシンタックスが美しくない(例:多次元配列の定義 [[u8;9];9])

このように現時点では C/C++ に取って代わりうる言語の中で、頭一つ抜き出ているものの、少し不安な要素もある。VSCodeプラグインや、開発支援ツールの充実度でも、某G言語にはまだまだ遠く及ばない感じ。Go言語のような巧みなシンタックスのデザインと Rust の厳密で突き抜けた部分を合わせると最強のシステム記述言語になり得るのではないだろうか。現状はまだまだ人柱を絶賛募集中といったところか。

return throw 問題

今日ハマったC++の落とし穴。次のコードの出力結果を予想してください。

#include <iostream>
#include <exception>

using namespace std;

static void assertZero(int i)
{
  if (i == 0)
    return

  //
 // I'm sure it is not a zero!!
  //
  throw exception("Not a zero");
}

int main()
{
  try
  {
    assertZero(0);
    cout << "0 is zero.\n";
  }
  catch (...)
  {
    cerr << "0 is not zero.\n";
  }

  try
  {
    assertZero(1);
    cout << "1 is zero.\n";
  }
  catch (...)
  {
    cerr << "1 is not zero.\n";
  }

  return 0;
}

これは

0 is zero.
1 is not zero.

となって欲しいところだけど、実際には以下のようになる。

0 is not zero.
1 is zero.

これ見て紅茶を噴きかけたのだが、こうなった原因は、assertZero 関数の return 直後にセミコロンをつけ忘れたことにある。C++の仕様によれば return の後には式を書くことができて、throw は void 型の式だったんですな。つまり返り値が void 型の関数において return throw exception("..."); と書くのは仕様上セーフであるらしい。結果として assertZero 関数は

static void assertZero(int i)
{
  if (i == 0)
    return throw exception("Not a zero");
}

と解釈され、めでたく全く意図とは正反対の挙動をするというわけでした。Go や TypeScript など、セミコロンの要らないモダンな言語に侵食されると、この手のミスが増えることが予想されます。これを機に中括弧を省略しない宗派に切り替えることも検討中。

(再現環境:Visual Studio 2017)

一時オブジェクトの寿命

先輩にバグじゃないの?と指摘されたコード。

class MyString
{
public:
  MyString();
  MyString(const std::string& s);
  :
};

extern const std::string& GetName(int idx);

int main()
{
  for (int i = 0; i < N; ++i)
  {
    const MyString& s = GetName(i);
    // この後、forのスコープ内で文字列 s を使うのは安全か?
  }
  
  return 0;
}

このコードは、以前、レガシーな std::string を使ったコードを国際化対応した文字列クラスに一括置換したときに生じたものだ。まだプロダクションには使われていないが、一瞬、嫌な汗をかいた。結論から言うとこれは合法だった。コンパイラも完全にスルーしていたので気付かず。

何が起こっているかというと、GetName() で std::string の参照が返った後、MyString の変換コンストラクタ MyString(const std::string&) が呼ばれ、一時オブジェクトが作られる。一時オブジェクトをconst参照で受けた場合、一時オブジェクトはconst参照に束縛されるというルールがあり、const参照変数のスコープまで延命される。したがってfor文のスコープ内で使うことができる。

まぁ、参照で受けてコピーを作らないという意図も叶っておらず、単にややこしいだけなので、早々に直したほうが良いだろう。