Make組ブログ

Python、Webアプリや製品・サービス開発についてhirokikyが書きます。

社会って論理的じゃないよね。僕らの弱さ、そして小野マトペ氏の裁判に感じること

皆さんのコメントを読んで、反省しました

皆さん、たくさんのコメントありがとうございます。 僕自身の考えや文が稚拙であったことを反省しました。

まず、僕は「社会は論理的でないところがある」ように書きましたが、これは良くなかったなと考えを改めました。 僕の間違いは、自分は論理的に考えていると思っていたものの、社会の中にある論理や合理性を軽視していたということです。 自分に理解できないものを、論理ではないものだと考える、感情的なものでした。 さらに文自体も感情的で良くなかったと反省しております。

皆さんのコメントのおかげで気づけました。ありがとうございます。 僕は、自分以外の世界というのに少し感覚が弱かったというか、軽視していたのだと思いました。

この記事について、削除してしまおうかとも思いましたが、僕自身が反省して学びこれからに活かすため残しておこうと思います。 内容はそのままにしておりますので、それを前提に読んでいただけると幸いです。

改めて、教えていただきありがとうございました。 そしていつも読んでいただき、ありがとうございます。

本文

社会って案外、論理的じゃないよね、と感じた話をさせてください。

いえ、僕こそホントは論理的でなかったと勝手に反省した 。オチを言うとそういう話です。

小野マトペ氏の裁判が終わり、個人的に「うわぁ」と思ったので感想です。

平たくまとめてるとこういう裁判です:

  • Twitterで「俺はコロナ」とネタをツイート
  • 居酒屋に行って写真をツイート
  • 刑事事件(偽計業務妨害)になる

もとの話はこちらを: note.com

何が怖いのか

まさに自分のことだったからです。

この裁判は控訴棄却で有罪判決となりました。 「ネタであり業務妨害をする気なんてなかった(故意でない)」という点が裁判において認められなかったということですね。

でも僕自身にも、すごく心当たりがあるんですよね。 まるで自分のことかと思いました。

Twitterでその日盛り上がった話題やニュースに、ちょっぴり過激な面白いことを言いたいことってあるじゃないですか。 友だちと飲み会をして「濃厚接触!」なんて冗談を飛ばしたいときもあります(ネットには書かないネットリテラシーを発動)。

もちろん、褒められたことではありません。 でもそんな、なくもないことが刑事事件になってしまう んだなということです。 僕も反省するところです。

たしかに前後関係を繋げていけば「業務妨害になっても構わないと思ってますよね?(未必の故意である)」と追い詰められる状況になります。

社会は論理的じゃない、そして僕こそ

僕が感じる「ロジック」とは違う論理があると言うべきでしょうか。そして自分が思っているほど、自分が論理的ではなかったということです。

裁判を見ると、小野マトペ氏が「故意に業務妨害をやったぞ!」と言える決定的な証拠はないわけです。 たとえば「店を名指しした犯罪行為を感じさせるツイート」など明らかなものはありません。

さらに、民事的ないざこざではないので、刑事的な「故意に犯罪をやっているかどうか」が争点なわけですね。

ただ、社会には「社会的に見てどうか?」という倫理による力があって、(情勢も鑑みて)納得感のある正義が勝ったわけです。 僕の学びとしては「ロジカルに言えば問題ないでしょう、とは言えない」、「納得感や社会的な倫理が重要な世界なんだ」という社会の掟に気づいたことです。

でも、そう考えれば、当たり前のことを言ってしまっていますね。

僕の弱点:論理的思考だと思ってしまう

論理的思考こそ至高なのではないのですか? そうなのですが、その思考が危ういんですね。

社会や法における「論理」と僕が感じている「論理」や合理性は違うものなんだなと分かりました。 いえ、むしろ本当はエンジニアの世界にもロジックだけじゃないものが大事なはずなんです。

そうでない、社会のもつ「納得感」が、一般的な世界の枠組みにおいて重要視されるわけです。 実際に小野マトペ氏の記事を読むと、論理や「自分の中にある正義」を大切にされてると分かります。

社会的な倫理観や、情勢、思惑や納得感を考える(おもんばかる)のも重要なんですね。 人の気持ちや常識、そしてそれらを動かす修辞や弁論も重要なわけです。

論理的思考は僕たちの世界においては絶対の理!と考えるのも、むしろいびつなんでしょうね。 正直、僕自身も上手に生きられてるとは思いません。

僕が学ぶこと

僕が学ぶこととしては、論理的思考だけで物事は決まらないと受け入れるだと思います。 実際に世の中は社会的な倫理観や納得感、そしてそれらを動かすレトリック(修辞)や弁論術やリテラシーが重要なようです。

飛躍してしまえば「有罪かどうかも修辞や弁論に左右される」ということですよね。 「いやいや、そのために弁護士がいるんでしょ!」と思った方は、そのとおりです。 小野マトペ氏のまとめ記事にも、弁護士を選ぶことが相当重要であったと反省が書かれています。

むしろそれこそが学びです。

「己の潔白と事実を説明して共感してもらえば分かってもらえる」と思っていませんか? そんなことはなかったんですね。 そもそも、社会的な通念を重んじるのも大切なんですね(当たり前のことですが)。

僕は、自分の「論理が正しい」思考を改める必要があると思いました。 そして合理的な時代の今だからこそ、修辞学(レトリック)や弁論術、そして法学や倫理こそ学ばないといけないのかな、ということです。

おわりに

ぜひ小野マトペ氏のまとめ記事を前半から読んでください。

あと、これに関したおすすめの本です。 このリンクから買ってくれると嬉しいです:


執筆:Kiyohara Hiroki (@hirokiky)Shodoで執筆されました

DjangoのQuerySetでグループごとに最大・最小のデータのみ取得する

DjangoのQuerySetでグループごとに最大・最小のデータのみ抽出する方法を紹介します。 この記事はDjango Advent Calendar 2021 3日目の記事です。

グループごとの最大・最小のデータとは何でしょうか?

たとえば以下のような場合に必要となります。

  • ブログ記事ごとに最新のコメントのみ取得
  • ユーザーごとに金額が最大の購入履歴のみ取得
  • ページごとにリビジョン番号が最大の差分データのみ取得

実際に仕事をしているとたまに欲しくなりますよね。

今回は Parent モデルというグループごとに、 Child モデルの number が最大になる Child の一覧を取得します。

class Parent(models.Model):
    pass
    
class Child(models.Model):
    parent = models.ForeignKey(Parent)
    number = models.IntegerField()

Meta__str__ は表記上省略)

QuerySetでグループごとに最大・最小のみ取得する

最大のみ取得する処理は以下のようになります(解説は後述します)。

children = Child.objects.all()
sub_qs = children.filter(
    parent=models.OuterRef("parent"),
    number__gt=models.OuterRef("number"),
)
qs = children.filter(~models.Exists(sub_qs))

実際に動作を確認してみましょう。 p1p2というグループごとに最大の値を持つ c1_4c2_2 のデータを作りました。

>>> p1 = Parent.objects.create()
>>> p2 = Parent.objects.create()
>>> c1_1 = Child.objects.create(parent=p1, number=1)
>>> c1_2 = Child.objects.create(parent=p1, number=2)
>>> c1_3 = Child.objects.create(parent=p1, number=3)
>>> c1_4 = Child.objects.create(parent=p1, number=4)
>>> c2_1 = Child.objects.create(parent=p2, number=1)
>>> c2_2 = Child.objects.create(parent=p2, number=2)
>>> children.filter(~models.Exists(sub_qs))
<QuerySet [<Child: 1-4>, <Child: 2-2>]>

Child: 1-4c1_4)とChild: 2-2c2_2)の取得を確認できました。

SQLは以下のようになりました(読みやすいよう改行を追加しています)。

SELECT "child"."id", "child"."parent_id", "child"."number"
FROM "child"
WHERE NOT EXISTS(
    SELECT (1) AS "a"
    FROM "child" U0
    WHERE (
        U0."number" > "child"."number" AND
        U0."parent_id" = "child"."parent_id"
    ) LIMIT 1
)

この処理では「グループごとに最大・最小の値が複数ある場合に両方とも取得される」点に注意してください。

解説

今回のSQLでは「よりnumberが高い値のある行を除外する」という方法で、グループごとの最大値を取得しています。直感的にはGROUP BYで最大値を計算するサブクエリーを書きたいところですが、実行速度が速い方法を紹介しました。

Djangoではこのサブクエリーを書くために、 OuterRefExists を使っています。OuterRef を使えば外側のクエリー中のフィールドを参照できますので、サブクエリーを簡単に書けます。 今回の場合は OuterRef("parent") でグループにする Parent を指定し、 OuterRef("number") で除外対象の number を指定しています。

実際の環境で高速に動作するかどうかは、データベースの実行計画を確認してください。 データベースやデータの内容によって変わってくると思いますので、仕事の環境で使う場合は実行計画を見ましょう。

GROUP BYを使った書き方も紹介しておきます。

他の書き方

参考として、GROUP BYとサブクエリーを使った方法も紹介します。

children = Child.objects.all()

sub_qs = children\
    .filter(parent=models.OuterRef("parent")) \
    .values("parent") \
    .annotate(max_number=models.Max("number")) \
    .values("max_number")
qs = children.filter(number=models.Subquery(sub_qs))

SQLは以下のようになります。

SELECT "child"."id", "child"."parent_id", "child"."number"
FROM "child"
WHERE "child"."number" = (
    SELECT MAX(U0."number") AS "max_number"
    FROM "child" U0
    WHERE U0."parent_id" = "child"."parent_id"
    GROUP BY U0."parent_id"
)

この処理はサブクエリー内で number の最大値を求めたうえで、その値を条件として Child の一覧を取得しています。こちらのほうが NOT EXISTS を使った書き方よりも理解しやすいですが、処理としては遅くなると思います(実際のデータや環境でお試しください)。

おわりに

DjangoOuterRefSubqueryExists を使ってグループごとに最大・最小の値のみを取得しました。 昔は「Djangoで凝ったSQLを書けない」という印象もありましたが、今のDjangoではクエリーの表現が多彩ですので、今回のようなサブクエリーも直感的に書けます。

ぜひ、業務の中でも活用していただけると嬉しいです (実行計画の確認はしてください)。

ちょっと聞いてください

このブログ記事は私の会社で開発しているShodo(https://shodo.ink/)を使って執筆されました。 Shodoは書いた文章をAIがリアルタイムにチェックしてくれるWebサービスです。

ただのAI校正ツールではありません。 エンジニアの皆さまにも嬉しい特徴がたくさんあります。

と、お勧めできます。

さらにGitHubのようなワークフローで記事を書けるのも特徴です:

  • 記事を書く日程やステータスを管理したり
  • 複数人で記事のレビューコメントやレビュー依頼をしたり
  • 共有リンクからたくさんの人にコメントをもらったり

そんな便利なWebサービスです。

今ならなんと!技術アドベントカレンダーの期間中、Shodoを無料で使えるキャンペーンを実施しています。 これから技術ブログを書く皆さん、ぜひShodoで技術記事を書いて知識やノウハウを共有しませんか?

クーポンコードはこちらから。 ぜひお試しください。

blog.shodo.ink

執筆:Kiyohara Hiroki (@hirokiky)Shodoで執筆されました

「若者エンジニア」が30歳になりました。老いが急激に加速するのはなぜ?

こんにちは。hirokikyです。

僕の個人的な話をしますが、4分ほどで誰でも気軽に読めるようまとめました ので、ぜひお付き合いください (5分の動画より短いです)。

今日の 2021年11月5日で、30歳になりました。 そしてこのブログも、もう10年以上やっていることになります。

僕は20歳のころからプログラミング(Python)界隈と関わりを持っていました。 当時は「若者Pythonエンジニア」と受け入れられたように覚えています。2011年ごろはまだRubyの全盛期で、わざわざPythonを選ぶのは少し変わった人たちでした(ChefやCoffeeScriptが流行り始める時代感です)。 そこに現れた20歳の僕や、同年代のPythonエンジニアはさらに珍しかったのです。

2012年のPyCon JPで併設カンファレンスを開催したとき

(2012年の併設カンファレンスでの懇親会)

「若者エンジニア」という名札は便利でした (正直に言ってしまうと)。

あれこれと技術について質問をしても、多少過激なことを言っても、周りは温かく受け入れてくれます。むしろ、その少し攻めた姿勢も良かったのでしょうか。臆せず質問や登壇、イベントの主催ができたように思います。親切な皆さんに助けていただいたり、一緒に仕事をしたり、イベントをやったりと楽しい日々でした。他にも自社で企画開発したWebサービスをお客様に買っていただいたり、そして起業したりと良い20代だったように思います。

DjangoCongress JP 2019の集合写真

主催したDjangoCongress JP 2019での写真(また皆んなで集まりたいね)

でもそんな若者エンジニアも、今日で30歳になります。

つまり、若さという免罪符が失効してしまったのです。

これからは大人の生き方を考えなければいけません。

...

と、文が続くと思ったのではないでしょうか。

いや、そんなことはありません。 若者らしさがなくなるのは、僕としてはどうでも良いのです(実を言えば27歳くらいから若者ではないですし)。

僕の中で困ったことは他にあるのです。

重鎮感 です。

何か「年上や先輩として気を遣われている感」、「界隈で歴の長い人として大切にされている感」です。 ときおりヌルリと感じるこの「圧」を、ここ数年感じていました。

たとえば軽い気持ちで「よしやってみよう」と言ったつもりで、周りの人がガッツリと作業に入っていた、などです。 他にもTwitterで「ああいうことやっても意味ないよ」とツイートすれば、知らないところで誰かが傷ついていたとか。

どちらにしろ僕が悪いだけです。

あと、少しうぬぼれすぎかもしれません。 僕はそこまで影響力のある人間ではないです(すいません)。

ですが、皆さんも何か心当たりがあるのではないでしょうか?

  • 「軽い気持ちで言ったのに、思ったより大事な発言になっていた」
  • 「いつの間にか、会議で発言が待たれている」

規模の大小はあれ、年を重ねたり、同じ業界でずっと頑張っていると誰しもが重鎮らしくなるわけです。 より一般化して言うと 「他人はあなたを、ロールに収めたがっている」 ということです(たとえば「決めてくれる人」)。 僕自身も他人にそれを期待してしまっています。

正直、若さを失うことはどうでも良いです。

ただ、 実際の現実は若さがなくなるだけでなく「老けさせようという圧力」がある んです。 より具体的に言うと 「他人が期待するあなたの姿へ、あなた自身を押し込む圧力」ということ です。

30歳くらいになった人が、急に老けてくる現象ってありますよね。 あれは、一度確立した自分の姿や「先輩としての自分」で留まると起こるのかな?と最近思います。 昔は尖ってカッコよかったのに、今は時事ネタのご意見番になった知識人などもそのタイプだと思います。

この力はおそらく人間心理的なものなのかなと思います。 責任や発言力、信頼や立場などというものが絡み合って、周囲が求める「あなた」という像が固定化されたのでしょう。あなた(そして僕)自身も誰かにそれを期待しているわけです。

でも僕は、 周囲が期待する僕に飲み込まれるのはカッコよくないな と思うわけです。 「適度に周りが気持ちいいことを言っていればいい」と迎合したり、「あの人が動いてくれるだろう」と無思慮に他人へ期待することです。そうすると、何も考えなくても案外生きられてしまうんです(現状への過学習というか、局所最適化というか)。

その他人が求める役割に浸っていると、人は急速に老いるわけです。 それがおそらく、30歳前後にある1つの分岐点なのでしょう。

若さがなくなるのは別に構わないんです。気遣いを勘違いしたり、自分が確立した自分に収められる力へ負けると、急激に老いる気がします。 努力した分だけ「先輩の威厳」や「重鎮感」まで追加されます。でもそれは相手の優しさであって、あなた(僕)のすごさではないんです。

なので、僕はなるべく初めて会う人や話してくれる人に、なるべく相手の立場を考えて話そうと思います。 そして、他の人にもロールや名札に落とし込んだような話し方はしないでおこうと思います。

世の中に、接しやすい先輩や、イジりやすい年上の人っていますよね?あの人たちは謙虚なんじゃなくて生存戦略としてああやってるんです。自分を重鎮扱いして固定化しないでくれよー!老いさせないでくれよー!というアピールなんですね。役割を捨てたピュアな関わりを、あなたと持ち続けたいんです(僕はどうにも絡みにくい人間になりがちなので、尊敬します)。

若さを失うことは怖くないですが、老けさせようという圧力は恐ろしいものです。 そして僕はこれからも抗っていきたいと思います。

そんなことを感じる、元、若者エンジニアでした。

ハッピーバースデー僕!

これからも頑張って良いものを作りますので、応援いただけると嬉しいです。

そんなわけで

そんなわけで、老いに抗っている僕が作っている新しいWebサービスがこちらです。

ブログ記事やプレスリリースを執筆する 「当たり前」のやり方を変えたい と思っています! まだまだ至らないところはありますが、頑張ってどんどん良くしていきます。

shodo.ink

以上です!

ここまで読んでくれてありがとうございます。


執筆:Kiyohara Hiroki (@hirokiky)Shodoで執筆されました

JavaScriptのグローバルマッチする正規表現でtest()、exec()すると状態が残る

今日はちょっとしたメモ書きです。

JavaScriptでグローバルマッチの(gオプションを付けた)正規表現で、 正規表現.test() をすると実行した状態が残ります。

> const FOO_REGEX = new RegExp('fo+', 'g')
> FOO_REGEX.test('fooooo is foo')
true
> FOO_REGEX.test('fooooo is foo')
true
> FOO_REGEX.test('fooooo is foo')
false

正規表現.exec() でも同様です。

> FOO_REGEX.exec('foooo is foo')
[ 'foooo', index: 0, input: 'foooo is foo', groups: undefined ]
> FOO_REGEX.exec('foooo is foo')
[ 'foo', index: 9, input: 'foooo is foo', groups: undefined ]
> FOO_REGEX.exec('foooo is foo')
null
>

グローバルマッチする正規表現.lastIndex というプロパティに、「今現在どこまで処理したか」を記録します。 .test().exec() ではその場所から次にマッチするまで処理されるので、このような挙動になります。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test#using_test_on_a_regex_with_the_global_flag

ローカル変数の場合に問題はありませんが、 グローバル変数にグローバルマッチする正規表現を置いている場合には状態が残るので注意しましょう。主に 正規表現.replace() のために使うのでグローバルマッチが良いけど、該当の文字が存在するかのチェックだけで使いたい場合などが考えられます。

対処法の考察

ここは単純にグローバルマッチをやめるのが良いと思います。

> const FOO_REGEX = new RegExp('fo+')

FOO_REGEX.lastIndex = 0 のようにすると状態を初期化できますが、グローバル変数の状態を更新するのは美しくない印象です。

「でも主に .replace() を利用したいのでグローバルマッチを付けておきたい!」ということもありますが、この場合は、うーーーん??!!! 正規表現の文字列をグローバル変数に定義しつつ、2種類の正規表現も定義するとか?ちょっと他のアイディアもあれば教えてくれると嬉しいです(すいません)。

他には 文字列.match(正規表現) を使う方法もあります。文字列全体を検証した結果が返されるので、存在のチェックだけをしたい場合に無駄な処理が多くなります。短い文字列しかない前提であれば、これでも良いかと思います。

> 'foooo is foo'.match(FOO_REGEX)
['fooo', 'foo']

まとめ

グローバルマッチする正規表現.test().exec()正規表現に状態が残るという話をしました。

執筆:Kiyohara Hiroki (@hirokiky)Shodoで執筆されました

村社会はどこにでも

ふと思ったのですが資本主義も一歩引いて考えると村社会と言えるのではないでしょうか。

資本家が多くの力や発言力を持っているというのは、周知の事実だと思います。 この資本主義も多くの人が参加しているようで、実は狭い範囲の人がそのルールを握っています。

「村社会」 集落に基づいて形成される地域社会。特に、有力者を中心に厳しい秩序を保ち、しきたりを守りながら、よそ者を受け入れようとしない排他的な社会をいう。しきたりに背くと村八分などの制裁がある。 同類が集まって序列をつくり、頂点に立つ者の指示や判断に従って行動したり、利益の分配を図ったりするような閉鎖的な組織・社会を1にたとえた語。談合組織・学界・政界・企業などに用いる。

goo国語辞書「村社会」 https://dictionary.goo.ne.jp/word/村社会/

たしかに資本主義はよく機能するシステムですし、僕は社会主義共産主義が良いと話を展開する気はありません。 資本主義の問題について論じるのも、マイケル・サンデルマルクス・ガブリエルに譲ります。

でも僕が怖いなと思うのは、皆が実はジョーンズタウンで生活しているのでは?という疑念です。 規模が大きいだけの村やエコーチェンバーの中にいるのでは?という仮説です。

ジョーンズタウンは、アメリカ合衆国キリスト教新宗教(カルト)・人民寺院によってガイアナ北部に開拓・設立された町(コミューン)。(中略) 1978年11月18日、この人里離れたコミューンで計918人の集団自殺を決行したことで世界的に著名になった。

Wikipedia「ジョーンズタウン」 https://ja.wikipedia.org/wiki/ジョーンズタウン

もちろんこれは少し悲観的すぎる見解です。ですが「僕たちは案外狭い社会的価値観の中で生きているのでは?」と疑うことはできます。そして多くの人が言う 「お金が欲しい」というのは実のところ資本主義という村から脱出したい という願望にさえ思えます。

というよりも資本主義にしろ、日本社会、Twitter、コミュニティ、スタートアップ界隈にしろ、規模が違えど 村社会らしさはどんな集団も持っている ということです。

たとえば資本主義は一部の人(資本家)の声が大きくなりやすいシステムです。実際に力も持っていて人も動かせます。 TwitterなどのSNSも、それを作る人やレコメンドのAI、バズりやすい世俗的な記事の価値観が支配的になり得ます。 オープンさを大切にするコミュニティでも実は「中心となる人に好かれないと居心地が悪い思いをする」ような閉鎖性を持っていたりします(常にオープンな心で人と接するのは誰しも難しいものです)。

日本の閉鎖性を批判するひろゆきが、ファンに囲われた閉鎖的な村を形成していったように、どこにもそれは現れます。 極端な例ではオウム真理教サティアンや、連合赤軍の山岳ベースがありますが、その異常な状況も歴史を見れば徐々に歪んでいったことが分かります。

僕たちは案外、排他的で小さな村の中に生きています。資本主義という村、日本という村も、大きなようで実は小さく狭い価値観に左右されています。

なので、少し過激なくらいオープンで反発的なほうが良いのかもしれません。 人間の心には、閉鎖的になりたい欲求が常にあるからです。

執筆:Kiyohara Hiroki (@hirokiky)Shodoで執筆されました

僕の飼育員を募集しています(FANBOXを始めました)

pixivFANBOXを開設しました。

hirokiky.fanbox.cc

Make組ブログでは比較的ちゃんとした内容を書いていますので、より緩やかで内容を保証しないものは今後FANBOXで書く予定です。 このブログにも書いているような「考え方」タグの記事なども、今後はFANBOXで書くかもしれません。

ぜひ支援、フォローいただけると嬉しいです。

FANBOXで投稿することや内容については以下からご確認ください。

www.fanbox.cc

執筆:Kiyohara Hiroki (@hirokiky)Shodoで執筆されました

イーロンマスクの「開発の5ステップ」をまとめました - あなたの要件はアホだし、そのプロセスも要らない、すぐ最適化するな。

イーロンマスク氏がスペースXを案内するという動画(Starbase Tour with Elon Musk PART1)の中で語られた「開発の5ステップ」が僕的に衝撃でしたのでまとめます。

この内容、心底素晴らしいのですが、元動画では話が少しとっ散らかっていますし専門的すぎます。 僕自身、何度も内容を思い返して役に立ったのですが、見直すたび読解に苦労するので自分のためにまとめ直しました (ありがとう、僕!愛してるよ!)。

以降については、イーロンマスク氏が語る開発の5ステップについてまとめています。 余力があれば、自動字幕ありで動画を見ながらのほうが、イーロンマスク氏の熱意を感じられて楽しいと思います(下の動画では、この話が始まる辺りから始まるようにしています)。

youtu.be

イーロンマスク、開発の5ステップ

開発の中では以下の順序を必ず守らないといけません。

  1. 要件をアホのままにしないこと。誰しもがアホにするので疑う
  2. プロセスを削除する。無駄なのを積みたがるので徹底的に減らす
  3. シンプル化・最適化する
  4. サイクルを速くやる
  5. 自動化する

絶対に逆行してはいけません。

ステップ1:要件は必ずアホになる。アホのままにするな

要件は必ずアホになります 。それはあなたが書いても、誰が書いてもそうなります。 なので疑い、アホのままにしないでください。

とくに優秀な人が書いた場合、誰もが「完璧だ」と錯覚してしまい、質問できなくなるので危険です。 常に疑う必要があります。「その要件はなぜ必要なのか?」、「意味があるのか」と。

そして要件には署名すべきです。その要件を決めた人が責任を持って行動しなければいけません。たとえば2年前のインターン生が、その要件の説明責任を果たせるでしょうか?ランダムに思いついた要件を、責任を取らずにいなくなってしまいます。

(注)

ここでいう要件はロケットに必要な耐荷重性能であったり、発生する振動の許容量などのことだと思われます。

ソフトウェア開発の世界でも要らない機能や、無視して良いデータフォーマットの都合、満たすべきでもないリクエスト量の基準などたくさん要らない要件・制約が出てきます。 誰かがなぜか「必要」とした要件がすぐに発生します。疑いを持たないと、それらアホな要件をすぐ許容してしまいます。

この話が興味深いのは 「要件定義をしろ」ではなく「要件をアホなままにするな」と言っている点です 。誰がやっても最初はアホになるから疑えということです。

ステップ2:とにかくプロセスを削除する

要件に対して 人は必要なプロセスを積みたがりますが、ほとんどが不要です

「この要件ならこれも考慮しないと、あれも作ってカバーしておかないと」となりますが、削除してください。

私たちはタイトなマージンでやらないといけません(そうしないと軌道には乗りません)。そのためにプロセスは削除しないといけません。必要なら後で追加できます。むしろ、 追加し直していないのであれば、十分に削除していません

たとえばロケットのグリッドフィンも折り畳む必要はありません。シミュレーションして、迎え角が小さければ問題ないことを確認しています。追加のエンジン出力も必要ありません。そうすれば折り畳みに必要なモーターも機構もすべて不要になります。

(注)

ここでのプロセスをソフトウェア開発でいうと、具体的な動作や画面、モデルやテーブルのことでしょう。どうしてもアレコレと足してしまいがちですが、不要だとイーロンマスクは言います。追加し直すレベルに至ってないのであれば、まだ削除が足りていません。

この話、 常識的に考えればグリッドフィンは折り畳み可能としておきたい気持ちになります 。飛行機が飛び立った後には、タイヤを収納したい気持ちになりますよね?それと似た発想です。ですがそのプロセスそのものを削除してしまった、ということです。スペースXは宇宙に飛び立つ前に、常識という宇宙に穴を開けてしまっています。すごすぎます(グリッドフィンについてはイーロンマスク氏以外の人が思いついたものらしいです)。

ステップ3:やっと、シンプル化・最適化する

シンプル化・最適化を1つ目にしてはいけません。3ステップ目です。 優秀なエンジニアは「そもそも存在するべきでないもの」を最適化しがち です。

なぜ人はそうするのかというと、学校(中学校・高校)では問いに答えることを教えるからです。人は学校で問いに答えるべきであると刷り込まれ、問いそのものを疑うことを忘れています。問いを疑うと、成績を落とされてしまうからです。

なので人は、存在しないものを最適化したがります。

(注)

これは私を含めてエンジニアがすぐにやりたくなるやつです。

  • データ設計やクラス設計をより良くする
  • デプロイの過程を無駄なくする
  • 画面の使い心地・手触りを良くする
  • アクセシビリティを高める

要件やプロセスを削除してしまえば、これら全ては不要になります。「ここのボタンは『OK』じゃなくて『次へ』のほうが良いだろう」なんて、存在するべきでないポップアップや画面・機能、要件について議論しても無駄という話です。

ステップ4:速くやる

上記3ステップを忘れずに速くやります。サイクルの時間を加速しましょう。 あまりにも遅いときは、速く動いてください。ただし3ステップを忘れると、自分の墓を急いで掘ることになります。 とにかく、いつであっても早く・速くやることはできます。

ステップ5:自動化する

最後に、自動化してください。

(注)

この点について詳しく話されていませんが、前後の話から考えるにロボットを使って自動で作る工程を整備することでしょう。 ソフトウェア開発で言うならCIを導入したり、自動デプロイを整備したり、E2EテストやA/Bテスト・BlueGreenデプロイを整備することでしょうか。

イーロンマスクの失敗:モデル3のグラスファイバーマット

私(イーロンマスク氏自身)も、これについて何度も失敗しました。自動化し、速くやり、最適化し、削除したんです。 モデル3の製造であった、3つのバッテリーパックの上にグラスファイバーマットを敷くという生産ラインが、全体を阻害していました。バッテリーパックの生産、ひいてはモデル3の生産ライン全体を阻害していました。

失敗したのは、まずオートメーションを直したことです。ロボットの動作を速くし、経路を短くし、トルクを強くして改善しました。そして速く仕事をし、グラスファイバーマット用の糊を減らすよう最適化しました(糊は全体に塗る必要がなく、糊が延びることを加味して中心部に塗るだけで良かったのです)。

最後になって「これは何のためのグラスファイバーマットなんだ?」と疑問を持ちました。私がバッテリーセフティーチームに聴くと「ノイズと振動低減のためです」と答えたんです。でも彼らはバッテリーに責任があるはずですよね?そこでノイズと振動のチームに聴くと「火災防止のためです」と答えました。お互いが交差することを言っています!まるでDilbertの漫画です!Dilbert漫画のシミュレーションの中にいるのか?と思いました。

よし、わかったと。グラスファイバーマットがある車・ない車で、マイクを積んで走らせました。試して聴き比べると、「で、どっちがどっち?」となりました。違いがなかったんです。結果としてそのグラスファイバーマットは削除したんです。

過程を逆に行ったことで、それまでの自動化や最適化などすべてが無駄になってしまいました。存在すべきでないものを最適化したんです。

終わりに

これは本当にすごい洞察だと思います。まさにリーン的な発想というか、MVP(Minimum Viable Product)を求める姿勢そのものだなと感じます。

「機能を追加しよう」、ではなぜなのか?何のためなのか、どういう数値や体験を改善したいのか。 はたまた、その数値や体験の改善に意味はあるのか?

グリッドフィンを折り畳まないような発想ができているのか? グラスファイバーマットを敷いてるんじゃないか? そもそも存在すべきでないものを最適化してるんじゃないか?

とくに、エンジニアから出発したPdMや起業家は頭に入れておくべきことです。 イーロンマスク氏も言っているように、誰であれアホな要件を出すんです。プロセスを足したがるし、最適化したがるんです。

未来の僕、ぜひ読み直して、頭に入れておください。 動画を見た後に、失敗してたなって思ったでしょ?その後の仕事で何回も役に立ったでしょ?このステップをまとめておいたから、見返して思い出してね。

執筆:Kiyohara Hiroki (@hirokiky)Shodoで執筆されました