シグマのSAマウント終了告知が丁寧かつ真摯で素晴らしかった

SAマウントカメラ・レンズをご愛用の皆さまへ | レンズ | SIGMA|株式会社シグマ

レンズ交換式カメラを開発・製造しているシグマがカメラシステムを終了させる告知を出して、告知をすること判断自体とその告知内容がとても丁寧で心証が良かったです。

前提

カメラシステムはカメラボディ自体と交換レンズおよびフラッシュなどのアクセサリからなります。
カメラシステムの導入にはカメラボディ + レンズで最低数万、熱心なユーザーは数十万・数百万という単位でお金をつぎ込みます。

カメラシステムは複数社が展開していますが、基本的に互換はないので熱心なカメラユーザーはこれから数年・十数年に渡って数十万〜数百万のお金を使う先を吟味して選び、決定しています。

またシグマという会社は撮像センサー (フィルムカメラでいうフィルム、カメラの根幹をなすパーツ) にFOVEONという他社とは一線を画す革新的なセンサーを採用しており、そのセンサーから得られるイメージはとても熱心なファンをひきつけています。
詳しくはメーカーのテクノロジー説明を読んでもらいたいのですが、一言で表すならば技術的な独創性ゆえに「XXXと比べて画質が良い・悪い」といった他のメーカーと同じ次元には立たずに、根本的に出てくるイメージそのものが違う、といったレベルの違いがあります。

終了告知自体の潔さ

カメラシステムに限った話ではないですが、莫大な資産を投じてきた既存ユーザーを刺激しないよう明示的に開発終了はアナウンスせずに、単に既存製品をディスコン (discontinued; 生産終了) させてフェイドアウトさせるに任せる、といった方針をとる会社が多いです。

実際、ユーザーは製品のリリースサイクルなどをもとに早いうちから「緩やかな死」を感じとって他システムへ移行しますし、すべてのユーザーに納得してもらえるようなアナウンスは難しい (なにせ大金を注ぎ込んできたものがほぼ泡になる) ですから、下手に行動を打つよりはひっそりと、というのは良し悪しはともかく合理的であるといえそうです。

そういった慣行・背景がありながらもきっぱりと終了をアナウンスする姿勢からは、システムそれ自体よりもシステムを作ってきたシグマという会社を信頼してくれているという自信が見えますし、ひいてはカメラシステムという息の長いプロダクトに対するビジョンの強さが伺え、ポジティブな印象です。

しかし単にアナウンスがあったからだけではなく、その内容が実に丁寧で真摯だったからだと思います。

告知の真摯さ

SAマウントカメラ・レンズをご愛用の皆さまへ | レンズ | SIGMA|株式会社シグマ

要旨としては:

  • SAマウントは終了します
  • Lマウントという新しいシステムを開発します
    • Lマウントはこれまで要望を受けてきた製品 (フルサイズセンサー搭載のカメラ) を実現するために最適な仕様です
    • 他社とのアライアンスを通じて最高のシステムにします
  • SAマウントのレンズ生産は続けます
    • Lマウントシステムのリリースまでに空白期間は設けません
    • 既存のSAマウントをLマウントで使えるよう移行手段を用意します

……といった内容です。

この告知は、事実を端的に説明し表現を濁した点が無く、ユーザーが最も知りたい点、すなわち現行システムの将来 (いつまでに、どうなる)、新システムへの移行がどうなるか、に絞って書かれています。

簡潔でわかりやすいだけではなく、実はこの告知には「申し訳ありません」などの謝罪表現が一切使われていません。
これから作る新しいものは絶対に良い自信があるし、それに向けた滑らかな移行手段も用意するから安心して、という強いビジョンが伺えますし、それを根拠付けるシグマからのアクションが提示されているからこそ説得力のあるものになっているのでしょう。

また、新マウントへ変更してより素晴しいシステムを作っていく必要があるというシグマ側の事情も匂わせつつも言い訳がましく見えないのは、けっきょくこの判断は最高のカメラシステムをユーザーに提供したいからです、という視点に立っているからという点も見逃せないです。

感想

これだけ丁寧にアナウンスしても少なからず反発はあるでしょうし、かなりハイカロリーな決断だと思いますが、シグマのプロダクトに対するビジョンの強さを感じさせ、シグマ製品を愛用している自分のシグマに対する信頼感は増しました。

アナウンスからはユーザーに対するケアだけでなく、これから作ろうとするシステムに対する強い自信を感じられます。
ユーザーに寄り添う姿勢も、新しいものに対する自信も、どちらか一方だけでは片手落ちで、両方を兼ね備えているからこそ納得感のあるアナウンスになったのでしょう。

カメラ業界的には決して大きなパイではないシグマですが、確かな地位を築いており今回のアナウンスはさらにそれを磐石にするものと思います。

いち開発者としても感じるところがたくさんあり、業界は違えど、見習いたいところばかりです。

MySQL: テーブルのデータサイズを見るときはinformation_schema.tables

こういうかんじ:

mysql> select table_name, table_rows, avg_row_length, (data_length + index_length) / 1024 / 1024 as total_mb, data_length / 1024 / 1024 as data_mb, 
index_length / 1024 / 1024 as index_mb from information_schema.tables where table_schema = '...';
+---------------------------------+------------+----------------+----------+---------+----------+
| table_name                      | table_rows | avg_row_length | total_mb | data_mb | index_mb |
+---------------------------------+------------+----------------+----------+---------+----------+
| foo                             |      10224 |            350 |        6 |       3 |        3 |
| bar                             |     391760 |            274 |      102 |     102 |        0 |
+---------------------------------+------------+----------------+----------+---------+----------+
2 rows in set (0.01 sec)

builderscon tokyo 2018で『ブログサービスのHTTPS化を支えたAWSで作るピタゴラスイッチ』という話をした

builderscon tokyo 2018で話しました。

2017に続いてスピーカーとしての登壇で光栄です。こういうイベントで何も話さないとどことなく居心地が悪くなる性分なので、スピーカー or die (不参加) となるところだったのでよかったです。

トークについて

speakerdeck.com

資料はすでに公開しています。

Hatena Engineer Seminar #10という社の名前を冠したイベントでもこのシステムについて話したのですが、けっこうおもしろいシステムができたという自負もあったしお待たせしてしまった感は拭えないのでせめて裏側を紹介して「知らなかった、を聞」いてもらえたらな、という思いもありました。
実際にbuildersconで話を聞いてもらえる機会をいただけて本当に嬉しいです。

実は後半の「ぼくのかんがえたさいきょうのピタゴラスイッチ」以降のスライドは直前に追加したものです。
今回初開催となるスピーカーディナーの会でid:devorgachemさん (今回はじめてお会いしました) とid:nkgt_chkonkさんと「設計について話そうとすると実践から離れた表層の話か、逆に応用の利きづらいドメイン特化の話になりがちでむずかしい (けどなんとかやっていきたい)」というような話をして刺激を受けて「もっと一般化された・普遍的な話ができるはずだ、したい」と思い捻り出しました。
実際できあがった話は、普段から考えていたことを咀嚼したものでかなり納得感がありました。ちょっと背伸びするきっかけができてよかったです。

あと「ぼくのかんがえたさいきょうのピタゴラスイッチ」は「ぼくのかんがえたさいきょうのうぇぶあぷりけーしょんふれーむわーく」をリスペクトしました。
スピーカーディナーでid:cho45さんとお話しできたのもすごく嬉しくて *1 、これだけでも参加した甲斐がありました。

Q&A

すっかり頭から抜けてしまったので、ツイート検索しました。ありがとうございます。
これまでのキャリアで最も質疑をたくさんいただけたトークで、とても励みになりました。やっぱり反応もらえるとうれしいです。

Q.「StepFunctionsのJSON手書きつらくならないんですか?」A.「つらいです。schemaがないので全体を把握するのがむずかしい。Goのコードを解析してschemaを作るグッズを作ろうとしている」

あともうちょっと質問いただいた気がします。録画見て思い出そうと思います……。

聞いたトーク

正直いうと他のトークほとんど聞けていないのが心残りです。ただでさえ発表前でナイーブになっているところへ関西にものすごい台風が来たり、地元の北海道で大きな地震が起きたりして、けっこう堪えました。
特に北海道の地震は仕事でもプライベートでも大きな打撃があって冷や冷やしました。

また、会場へ出向いても満員御礼だったということが多かったのもやや残念です。SmartHR社のマルチテナンシーの話はおもしろそうだったので生で聞きたかった……!

事前知識なしで理解する、静的検査のいろは - builderscon tokyo 2018

昨年のビルコンで僕も「Goで実装する軽量マークアップ言語パーサー」というトークをして興味のある分野だったので聞きました。
というのと、iOSDC 2018でベストスピーカー賞2位とのことで、プレゼンテーションが上手な方の話を聞いてみたいという興味もありました。

実際、幅広いトピックを密度高く紹介するというプレゼンテーターとしては難易度の高い話だったと思いますが、細かい粒度でまとめを挟んだり、構文木など難しい概念はグラフィカルに説明することを徹底されており、唸りました。

内容自体だけでなくプレゼンテーションそのものが勉強になりました。

JavaCardの世界 - builderscon tokyo 2018

興味の範囲がWebを中心としている限りおよそ出会うこともなかろうトピックだったので聞きました。

AIDなどの払出しがISOだったり、中央集権っぽいのが組み込みっぽいというかWebっぽくなくて新鮮ですね。

運営スタッフのみなさまへフィードバック

  • スピーカーディナーよかったです
    • お酒入ってたこともあり1分間ピッチの反応が思ったより良くて発表前にちょっと自信がつきました
    • 規模感がちょうどよく、いろんな人と話しやすかったです
  • 満員御礼で見れないトークが多く残念でした><
    • 街頭ディスプレイみたいな、コンサートホールのホワイエで見れるやつみたいな、立ち見席みたいなのもあると嬉しいかも、とおもいました

とはいえ部屋に入れなかったらHUBへ行くことができて、そこはそこでおもしろい話ができました。
僕のトークの裏番組になってしまい聞けなかった遠いようで身近なサウンドエンジニアリング - builderscon tokyo 2018もスピーカーである id:karupanerura さんとイベント後のHUBでゆっくり話ができたのもいい思い出です。

ビルコンも3度目ですが、毎度、これだけの規模のイベント運営されるみなさまには頭が下がります。ありがとうございます……!

*1: ここだけの話、自分がエンジニアを目指すきっかけになったのでたいへん尊敬しているのです

aws-cdk探訪: AppsとStacksの関係

最近、TypeScriptで癒されたさ重視でaws-cdkを見ています。

aws-cdkはCloudFormation (以下CFn) をよりプログラマブルに扱う高級な・抽象的なライブラリと見てよく、概念もほぼ対応しているのですが、Appsという概念はaws-cdkに固有のもので特色たりえるものに見えるので、これについてメモします。

基本的に公式ドキュメントに書いてあることの咀嚼しなおしなので、既に読んで理解している人には新しい情報は無いです。

ざっくりとした捉え方

  • aws-cdk Stacks = CFn stacks
  • aws-cdk Apps = 複数のaws-cdk stacksをまとめたもの
  • 変更のデプロイはappに含まれる特定のstackを指定するとよい

aws-cdk Appsとは

公式ドキュメントによると:

The main artifact of an AWS CDK program is called a CDK App. This is an executable program that can be used to synthesize deployment artifacts that can be deployed by supporting tools like the AWS CDK Toolkit, which are described in AWS CDK Tools.

Apps — AWS Cloud Development Kit

……とのこと。

この説明はランタイムとしてのaws-cdkに寄った説明でどういった概念なのか掴みづらいです。

実はStacksの説明のほうがわかりやすくて、以下のように書いてあります:

Most production apps consist of multiple stacks of resources that are deployed as a single transaction using a resource provisioning service like AWS CloudFormation.

Stacks — AWS Cloud Development Kit

ここでいう Most production appsaws-cdk Appsを指します (恐らく)。
大抵のAppsは複数スタックからなるでしょう、ということです。

さらにAppsのドキュメントにあるコード例がわかりやすいです:

import { App } from '@aws-cdk/cdk'
import { MyStack } from './my-stack'

const app = new App(process.argv);

const dev = new MyStack(app, { name: 'Dev', region: 'us-west-2', dev: true })
const preProd = new MyStack(app, { name: 'PreProd', region: 'us-west-2', preProd: true })
const prod = [
    new MyStack(app, { name: 'NAEast', region: 'us-east-1' }),
    new MyStack(app, { name: 'NAWest', region: 'us-west-2' }),
    new MyStack(app, { name: 'EU', region: 'eu-west-1', encryptedStorage: true })
]

new DeploymentPipeline(app, {
    region: 'us-east-1',
    strategy: DeploymentStrategy.Waved,
    preProdStages: [ preProd ],
    prodStages: prod
});

process.stdout.write(app.run());
Apps — AWS Cloud Development Kit

上記コードは1つのappにdev, preProdといった開発環境用のstackを追加しています。
これらステージごとのstackなどの集合がappであるという捉え方です。

デプロイはどうするか

これもCLIのヘルプを読めばわかりますが、各コマンドは対象となるstackを指定することができます。

cdk deploy Dev
...
Apps — AWS Cloud Development Kit

指定しなければ紐付くすべてのstackが更新されます。

aws-cdkの基礎にCFnが存在し、CFnの基本デプロイ単位はstackであることを思い出すと理解しやすい挙動だと思います。

私の環境ではdev, staging, productionといった環境ごとにデプロイは分けていたので cdk deploy dev-app のように実行するのがよさそうということがわかりました。

aereal.orgをGoogle Cloud Platformに移した w/Cloud DNS, Cloud Storage, Deployment Manager

aereal.org

長らくさくらのVPSホスティングしていたのだけれども運用がめんどうになったのでこれを機にGCPへ移行した。

登場人物は:

……の4つ。

Google Cloud Storage

GCP版S3みたいなオブジェクトストレージ。使い勝手はかなり似ていて、S3同様にウェブサイトとして公開する設定もある。

ここにindex.htmlとか画像を置いて後述するGoogle Cloud CDNのoriginにする。

Google Cloud Load Balancing

AWSでいうALB/NLBにあたるもの。ALB相当がHTTP(S) Load Balancingになる。
余談だけど日本語ドキュメントでは「HTTP負荷分散」と訳されていて、動名詞なのかプロダクト名なのかわかりにくい。

パスやホストに対してルールベースでbackendへリクエストを送ることができる。
使い込んでいないけれどALB/NLBと機能の差異はそんなにないようにみえる。

Google Cloud CDN

GCPが提供するCDNサービス。AWSでいうCloudFront.

invalidation APIがあったり、普通なかんじ。

Cloud CDNに限らないけれど全体的にGCPは安めな気がする。

Google Cloud Deployment Manager

AWSでいうCloud Formationみたいな構成管理するグッズ。

YAMLを使うのはCFnと同じだけれども、変数展開などはJinja2というAnsibleでも使われているテンプレートエンジンを採用している。
既存のよくできた技術を再利用する筋のよさは後発のGCPならではってかんじ。

リソースのプロパティ定義は既存のREST APIのリクエストパラメータと同じ名前・同じスキーマなのでそちらを参照せよというドキュメントになっており親切。
(例: REST Resource: targetHttpsProxies  |  Compute Engine  |  Google Cloud

gcloud deployment-manager types list で使えるリソース定義の一覧が得られるので、これでDeployment Managerで対応しているか確認できる。
前述の通りプロパティ定義はREST APIと一致しているので、このリソース定義名からREST APIのドキュメントを引けばよくて便利。

aereal.orgのデプロイ設定は GitHub - aereal/gcp-deployment-aereal.org に置いたのでご覧ください。

感想

GCPはぼちぼち触っていたけれどDeployment Managerはよく出来ているし筋がいい印象を持った。

会社ではAWSを使っているのでおもしろさ重視でGCPでもっと遊んでいきたい。

aws-cdkを見ている: policyの変換がすごい

aws-cdkを見ている。TypeScriptもしくはJavaAWSの構成管理ができる。CloudFormationのプログラマブルなやつと考えるとよい。

TypeScriptは癒しなので癒されました。今日は感動ポイントをご紹介。

policyの変換がすごい

CFnのなかでもS3のbucket policyを書くのは最もダルい作業のうちのひとつに数えられると思いますが、aws-cdkだとこう書ける:

    const bucket = new Bucket(...);
    const policy = new PolicyStatement(PolicyStatementEffect.Allow);
    policy.addAction("s3:GetObject");
    policy.addResource(this.arnForObjects("*"));
    policy.addPrincipal(new Anyone());
    bucket.addToResourcePolicy(policy);

これが cdk synth でこうなる:

    XxxBucketPolicy81AF88BF:
        Type: 'AWS::S3::BucketPolicy'
        Properties:
            Bucket:
                Ref: XxxBucketEDCC903C
            PolicyDocument:
                Statement:
                    -
                        Action: 's3:GetObject'
                        Effect: Allow
                        Principal: '*'
                        Resource:
                            'Fn::Join':
                                - ""
                                -
                                    -
                                        'Fn::GetAtt':
                                            - XxxBucketEDCC903C
                                            - Arn
                                    - /
                                    - '*'
                Version: '2012-10-17'

すごい!

JavaScriptのtemplate literalでよいかんじに変換されていそう。

よくあるワンソースで適当に変換エンジン作りましたというかんじではなく、ちゃんとTypeScript (ECMAScript) でネイティブにいいかんじに実装していこうという気概が感じられて、今後に期待が持てますね。

その他

cdk synth で出力するYAMLが、既存のCFnのYAMLと完全に互換を保てたら脱出も楽になるからいいな〜とおもっているのだけれど、そういうオプションはざっと見たかんじなさそう。

migration pathみたいなissueはあるのでなにも計画がないわけではなさそうだけど、あれだったらP-Rを送っていきたい。

tslintで有効になっているruleをpreset由来も含めて一覧する

const { resolve } = require('path');
const { Linter, Configuration: { findConfiguration } } = require('tslint');

const tslintJsonPath = resolve(__dirname, '../tslint.json');
const { results: config } = findConfiguration(tslintJsonPath);

const formatRule = (rule) => `${rule.ruleName}:${rule.ruleSeverity}`;

const linter = new Linter({ fix: false });
const rules = linter.getEnabledRules(config, false);
rules.map(r => formatRule(r)).sort().forEach(r => console.log(r));

presetをextendsするのが主流だけど、このpresetってデフォルトでどういう設定を提供するんだっけ? と調べはじめたりしてまあまあ不毛だし、そういうのとってくるAPIあるでしょと思い調べたらやはりあった。

内部向けっぽいAPIを無理矢理使っているわけでもないので、まあまあ安定しそう。

BPMと音価を入れるとディレイタイムを計算してくれるやつをReactで作った

Reactでちょっとした計算機を作ろうと思い、せっかくなのでStorybookを試してみることにした。

できたもの

GitHub - aereal/delay-time-calc

f:id:aereal:20180521112626p:plain

BPMとフィードバックさせたい音の音価を入れるとディレイタイムがミリ秒で出力される。

BPM 120で8分ディレイをかけたかったら250msec.にすればいい、みたいなことが手軽に計算できる。

いま触って気付いたけど付点8分のときの計算まちがっている気がする……。

使ったもの

create-react-appで雛形を作り、Storybookのドキュメントを読んでセットアップをした。
TypeScriptでstoryを書くのに一手間必要だったが、ものはできた。

変更内容は以下の通り。自動生成するコマンドの実行結果と手作業で加えた変更はコミットを分けているので、わりとわかりやすいのではないかと思う:
https://github.com/aereal/delay-time-calc/compare/94b844e12a73fd91b52d21a542b3566e19ab9151...eb106a6dda7e606a40de1453a56d4e642554ae14

TypeScriptでstoryを書くためのあれこれは typescriptでReact Storybookを試す。 - Qiita が参考になった。

感想

  • storybookは便利
    • コンポーネントがたくさんある・たくさん作っていくプロジェクトではカタログとして十分便利そう
    • storybookがあることで、ここで触るのに過不足ない
    • addonを入れるとMaterial-UIのスタイリイングをstorybook上でプレビューできるのめちゃくちゃ便利
  • とりあえずはじめるときはcreate-react-appを使うとよさそう
    • `npm run eject` できるしWebpackの設定をだいたいいいかんじにしてくれるし
    • まあこの先メンテしていけるかっていう話はあると思うが、少なくとも初速は出る・差分アップデートで習得できる、というところをよしとできるなら
    • scripts/test.jsとか、テスト実行をいじりたいと思ったときにメンテできるのかは既に不安ではあるが……

HTTP::Message#content($bytes)を呼んでもcontent-lengthは計算されない

HTTP::Request#content($bytes) もしくは HTTP::Request#add_content($bytes) を呼んでもcontent-lengthは自動で計算されず、0になる。

なのでそのままリクエストを送ると、ちゃんとcontent-lengthだけbodyを読む実装はボディが空だとみなすのでちゃんとcontent-lengthを計算しなければいけない。

Plackの実装に慣れていたのでびっくりした。

    my $req = HTTP::Request::Common::POST($url);
    my $json = JSON::XS::encode_json($payload);
    $req->content($json);
    $req->as_string;

HTTP::Request#as_string した結果:

POST http://example.com/api/issuance
Content-Length: 0
Content-Type: application/json

{"status":"success","expires_at":"2018-04-09T12:19:26+09:00"}

Content-Length: 0 になっていることが確認できる。

AWS CloudFormationメモ

  • aws cloudformation package はS3にfunctionとかいいかんじにアップロードして、そのARNが埋められてそのまま aws cloudformation deploy 実行可能なテンプレートを出力してくれる
    • そのパスを指定する引数が --output-template-path
  • cloudformation自体はS3になにをアップロードするのは不可欠ではない、lambda functionとか追加のファイル (local artifacts) が必要なときはpackageするとよい
  • lambdaとかつかわない場合はいきなりdeployできる

id:dekokun ++

参考:

Go: 外部ライブラリを使ったコードをいいかんじにDIしてテストする話

結論

  • 実装ではなくインターフェースに依存させる
  • Goのinterfaceは実装の明示が必要ないので便利

aws-sdk-goのスタブ

外部ライブラリの例としてaws-sdk-goを使ったこういったコード例を考える:

type CertificateFetcher struct {
  client *dynamodb.Client
}

func New(client *dynamodb.Client) *CertificateFetcher {
  return &CertificateFetcher{client: client}
}

func (f *CertificateFetcher) GetCertificate(domain string) (string, error) {
  resp, err := f.client.GetItem(...)
  if err != nil {
    return "", fmt.Errorf("...")
  }
  key := resp.Item["key"]
  if key == nli {
    return "", fmt.Errof("...")
  }
}

DynamoDBと通信させずにエラーのハンドリングや *dynamodb.GetItemOutput から値を取り出す処理などについてテストしたいが、そのためには *dynamodb.Client を差し替える必要がある。

実装を差し替える範囲が広すぎると実際に実行されるコードに対するカバレッジが低くなりテストの意味がなくなるので、適切な境界を見つけてそこで差し替えられるとよさそう。

実際にどうやるか、結論としては CertificateFetcher*dynamodb.Client ではなく必要なメソッドが定義されたinterfaceに依存させるとよい。

例:

type DynamoDBClient interface {
  GetItem(item *dynamodb.GetItemInput) (*dynamodb.GetItemOutput, error)
}

type CertificateFetcher struct {
  client DynamoDBClient
}

func New(client DynamoDBClient) *CertificateFetcher {
  return &CertificateFetcher{client: client}
}

func (f *CertificateFetcher) GetCertificate(domain string) (string, error) {
  resp, err := f.client.GetItem(...)
  if err != nil {
    return "", fmt.Errorf("...")
  }
  key := resp.Item["key"]
  if key == nli {
    return "", fmt.Errof("...")
  }
}

テストコード例:

func TestGetCertificate(t *testing.T) {
  stubClient := &StubDynamoDBClient{}
  fetcher := New(stubClient)
  // ...
}

type StubDynamoDBClient struct {}

func (c *StubDynamoDBClient) GetItem(item *dynamodb.GetItemInput) (*dynamodb.GetItemOuput, error) {
  // ...
}

Goのinterfaceは所与のメソッドを実装していれば特別なアノテーションをつけずとも構造体がinterfaceを実装しているとみなされるので、実装を変更できない外部ライブラリに対してアドホックにinterfaceを定義できるので便利。

このようにインターフェースに依存させてDIしやすくするというのは、たとえばScalaにおけるcake patternなど他にも例があります。

吉祥寺.pm mini #012 に参加した

kichijojipm.connpass.com

 

参加した。酔った勢いで参加登録し、新幹線と宿を予約をし、東京は吉祥寺に舞い降りました。

ライブと仕事でしか東京に行かないので西のほうに行くのは新鮮。

 

設計というテーマもさることながらしんぺいさん (id:nkgt_chkonk) を見に行くチャンスなので京都から参加登録した。

 

設計という抽象的な話題についてうまく他人とコミュニケートできる・それだけのプレゼンテーションができるというのはすごいことだと思っている。

参加して設計についてもちろん深い考察が得られたらいいと思っていたけれど、それ以上に自分が感じる「設計についていいかんじに他人にプレゼンテーションするために必要な能力は何なのか」について手掛かりが得たいと思っていた。

 

結論から言うと、それは得られた。簡単にまとめてみると:

  • 議論に参加する人間が解決できる (結論を出せる) 単位まで問題を分解する
  • 分解された子孫テーマ間の繋りを補強・説明する知識を持っている

……という能力およびそれの効果的な発揮に裏打ちされているのだと理解した。

具体的には:

  • 「良い設計とは何か」というテーマを、たとえば「DRY原則をいいかんじに適用する例とはなにか」くらいに分解する
  • さらに「DRY原則を適用していいかんじになっている」状態を「他の設計原則に違反せず達成されているか」くらいにさらに分解する

……という風に表れている。

「今あえてDRY原則に向き合う」というスライドはよかったです。

speakerdeck.com

こうして考えてみるとティーチングに対しても問題解決の原則を持ち込んでいるということであって、目新しさはない。ないが、当たり前のことを当たり前にやるということを実践できることは非凡ではないと思う。

 

京都からいきなりやってきたけど非常に楽しく参加させてもらえてありがたかったですし、個人的にはインターネットで見かけたおもしろそうな人を見に行くために出かけるのはインターネット原体験っぽさがあってよかった。

終電がなくなって吉祥寺から宿をとった京橋までタクシーに乗ったら「京橋? (舌打ち)」って言われたり「京橋ってどこですか?」って言われたり、深夜の急カーブ高速道路を120km/hで駆け抜けて恐怖を感じたり久しぶりにメチャクチャな目にあったけどそれもよかった、また吉祥寺いきます。

GoのデバッグはdelveとVisual Studio Codeが便利

delveとは

Go向けのデバッガで、ステップ実行とかブレイクした行のレキシカル変数が見えたりといった基本的な機能を提供しつつ、dlv debugコンパイルしつつ実行 (go run) したりgo(1)とほどよく統合されている。

後述するheadlessモードがあっていわゆるリモートデバッグが可能。

delveをmacOSにインストールする

公式のドキュメントではbrew install go-delve/delve/delve一発で済むように書かれているが実際はうまくいかなかった (´°̥̥̥̥̥̥̥̥ω°̥̥̥̥̥̥̥̥`)

==> Installing go-delve/delve/delve
==> Downloading https://github.com/derekparker/delve/archive/v1.0.0.tar.gz
==> Downloading from https://codeload.github.com/derekparker/delve/tar.gz/v1.0.0
######################################################################## 100.0%
security: SecKeychainSearchCopyNext: The specified item could not be found in the keychain.
==> Generating dlv-cert
==> openssl req -new -newkey rsa:2048 -x509 -days 3650 -nodes -config dlv-cert.cfg -extensions codesign_reqext -batch -out dlv-cert.cer -keyout dlv-cert.key
==> [SUDO] Installing dlv-cert as root
==> sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain dlv-cert.cer
Last 15 lines from /Users/aereal/Library/Logs/Homebrew/delve/02.sudo:
2018-02-28 11:11:35 +0900

sudo
security
add-trusted-cert
-d
-r
trustRoot
-k
/Library/Keychains/System.keychain
dlv-cert.cer


If reporting this issue please do so at (not Homebrew/brew or Homebrew/core):
https://github.com/go-delve/homebrew-delve/issues

These open issues may also help:
Upgrade to delve fails https://github.com/go-delve/homebrew-delve/issues/20

紹介されているissueを見てみると証明書を生成してインポートするスクリプトを手で実行したらうまくいったと書いてある。

実際に実行した手順はこういうかんじ:

✘>﹏<✘ < cd $(brew --cache)/
✘╹◡╹✘ < tar xzf delve-1.0.0.tar.gz
✘╹◡╹✘ < cd delve-1.0.0
✘╹◡╹✘ < bash ./scripts/gencert.sh
✘╹◡╹✘ < brew install go-delve/delve/delve

delveをインストールしたら sudo pkill taskgated を実行してtaskgatedを再起動する。
プロセス間通信を監視するデーモンらしく、bash ./scripts/gencert.shで生成・インポートした証明書を読み込みしなおす必要がある。

Visual Studio Codeとvscode-go

Visual Studio Codeは便利、GoやTypeScriptを書くとき最近はもっぱらこれ。

vscode-goというGoを書くときの各種便利サポートを追加してくれる拡張を入れる。

Debugging Go code using VS Code · Microsoft/vscode-go Wiki · GitHubが詳しい。

Visual Studio Codeでデバッグ

Visual Studio Codeでリポジトリを開きつつ Debug → Open Configurations でデバッガの設定 (JSON) を開く。

設定中の moderemote にする。remoteにすると別プロセスで既に起動しているデバッガーに接続する。

Debugging Go code using VS Codeにあるように、シェルで dlv --listen=:2345 --headless -- などと実行してデバッガーを起動する。

あとはVisual Studio Codeの Debug → Start Debuggingを押すとデバッガー開始できる。

gyazo.com

行頭を押すとブレイクポイントを設定できまるでIDEのよう〜。

ステップ実行もできるしレキシカル変数も見れて便利!!!!

Dockerのコンテナ内でapt-cache searchしてパッケージが見つからないとき

rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* してないか確認する。

コンテナのプロビジョニングを試行錯誤しているときに docker-compose run --rm app bash とかやりがちだけど、最初の方に apt-get update && apt-get install && rm -rf /var/cache/apt/archives/* /var/lib/apt/lists/* しているとaptのキャッシュもリポジトリも消えるので、あるべきリポジトリが見つからないように見えることがある。

探すときはpackages.debian.orgを見るとかするとよい。