こまぶろ

技術のこととか仕事のこととか。

『誤謬論入門 優れた議論の実践ガイド』を読んだ

3月に発売されたばかりの『誤謬論入門 優れた議論の実践ガイド』(原題:Attacking Faulty Reasoning)*1を読んだ。

原書は、非形式論理学・クリティカルシンキングの教科書として使われているもので、初版が1980年、今回の翻訳の底本となっている第7版が2013年の出版と、帯に謳われている通りの「ロングセラー」本のようである。

自分はこの分野が専門だったわけでもないのだが、論理学には学生時代少し興味があったし、どうすれば議論を実りのあるもの、平行線を辿らずに済むものにできるかということを意識する機会も多いので、この翻訳本の紹介を見てすぐ予約購入した。

「前件否定の誤謬」や「規範的前提の欠如の誤謬」といった「論理学らしい」誤謬のほかに、「藁人形論法」や「お前だって論法」といったTwitterでも見ることの多い誤謬も数多く取り上げられていることが紹介から窺えたので、読む前の期待としては「色んな誤謬の類型を知りたいな」というものだった。「これは知らなかった!」と思うような新しい誤謬が色々と掲載されていて、これからその誤謬を犯している議論を見たときに(あるいは自分自身がしてしまいそうになったときに)気づけるようになりたいということである。

しかし、一読してみると、その期待はあまり満たされなかった(たしかに様々な誤謬が紹介されているのだが、「ああそういう名前がついているのね」程度で、新しい気づきは乏しかった)のだが、それ以外の部分で面白い部分がいくつもあったので、書評を書こうと思った。

なお、本書の学術上の位置付けや、本書自体への学術的な批判については、巻末の監訳者解題が充実しているので、そちらを参照してもらえればよいと思う。

構成について

本書は以下のような全10章構成である。

  • 第1章 知的行動の規範
  • 第2章 議論とは何か
  • 第3章 優れた議論とは
  • 第4章 誤謬とは何か
  • 第5章 構造の基準に違反する誤謬
  • 第6章 関連性の基準に違反する誤謬
  • 第7章 許容性の基準に違反する誤謬
  • 第8章 十分性の基準に違反する誤謬
  • 第9章 反論の基準に違反する誤謬
  • 第10章 論述文を書く

分量の上ではおよそ1/3に当たる第4章までが概論で、第5章から第9章が(タイトルからは本編であることが期待されそうな)誤謬のカタログである(第10章は、第9章までの記述を踏まえた論述文のための簡単なガイド)。

全体で見ると400ページほどの書籍だが、章末課題の解答例と監訳者解題で50ページほどあるし、第5章以降は誤謬の具体例にも多くの紙幅が割かれているので、本論を追うだけであればそこまで時間をかけずに読むことができると思う。

知的行動の規範

第1章では、「知的態度に取り入れるべき行動原則」として、以下の12の原則が提示される(うち5つが後に論じられる「優れた議論の基準」)。

  • 可謬の原則
  • 真理追求の原則
  • 明瞭性の原則
  • 立証責任の原則
  • 寛容の原則
  • 構造の原則(=優れた議論の基準の1つ目)
  • 関連性の原則(=優れた議論の基準の2つ目)
  • 許容性の原則(=優れた議論の基準の3つ目)
  • 十分性の原則(=優れた議論の基準の4つ目)
  • 反論の原則(=優れた議論の基準の5つ目)
  • 判断保留の原則
  • 解決の原則

5つ目の「寛容の原則」は、英語ではprinciple of charityであり、これは「思いやりの原則」(伊勢田哲治『哲学思考トレーニング』p.48-49)や「善意の原理」(『岩波哲学思想事典』955L)などとも訳される。

他者の議論を再構築する場合には、論者の本来の意図だと考えられるものを損なわない形で、最も強い議論になるよう注意深く表現するべきである。議論の意図された意味や暗示的な箇所に不確かな部分があるなら、議論を提示した者に有利になるように解釈し、要望があれば修正する機会を与えなくてはならない。(p.23)

自分としては、Twitterでの不毛な議論の原因で最も多いと感じるのがこの原則に違反する一方(あるいは双方)当事者の言動である。また、仕事での議論でも意識することの多い原則で、「〜さんの言っていることはこういうことですか?」とこの原則に則りながら再構築して質問することは議論をスムーズに進める上で役立っている(もし自分の再構築した議論が本人の意図と違っていた場合も、この原則を意識していれば相手に不快な思いをさせることは少ないと思う)。

議論とは何か?

本書において議論(argument)*2とは、「他の複数の主張に裏付けられた主張」であり、裏付けられる主張が「結論(conclusion)」、裏付けに使われる主張が「前提(premise)」である。さらに、前提自体を結論として裏付けるものは「補完前提(subpremise)」と呼ばれる。

議論と区別されるものとして「意見(opinion)」があり、意見は必ずしも前提による裏付けを持たない。意見としてのみ表明されている限りではその意見を受け入れるべきかどうかの判断がつかないが、裏付けのある議論として表明されればその議論の質を問うことができるというのがポイントになる。

議論の質を評価する際には、「議論の標準形式(standard form)」に論者の議論を再構成するべきだと本書は主張する。

議論の標準形式とは、論者の意図を汲み取って元の議論を明確かつ簡潔な言い回して再構成したものである。すべての暗示的な部分を明示的に表現し、結論と前提や補完前提がきちんと区別されていなくてはならない。(p.39)

相手の議論における暗示的な部分を明示的にしようとすることは(当然ではあるが)話し合いをしている際には極めて重要なことだと思う。その部分に対して実は異論があるというケースもあるし、異論はなくても、話し合いに参加している人のうちにその部分が共有されていないために、後になって不適切な議論を立ててしまうケースもみる(ex. 「あの時こういう理屈でああしたじゃないですか」「いや、あのときはかくかくしかじかの前提があったからああしたんですよ」)。

優れた議論を構築する

第3章では、(第2章までの)上記の話を踏まえつつ、前述の優れた議論の5つの基準を提示しながら、議論を優れたものにする方法を紹介する。印象に残った点をひとつだけ挙げる。

それは、「許容性の原則」に関わるものだ。許容性の原則とは以下のものである。

ある立場に賛成あるいは反対の議論を行う者は、成熟した合理的な人に受け入れられそうで、かつ許容性の標準的な基準を満たす根拠を示さなければならない。(p.60)

議論で使う根拠は、「真である」必要があると考えられる場合が多いだろう。しかし、本書ではそうではなく、根拠は「許容しうる」必要があるという。「許容しうる」という基準が「真である」という基準よりも適切である理由として、いくつかのものが挙げられているが、興味深いのは、4つ目に挙げられている、「仮にある前提が絶対的な意味で真であったとしても、それが真であるかを判断できる立場にない特定の受け手にとって許容できないものになる可能性があること」(p.61)という理由である。

たとえば、根拠として挙げられているものの専門性が高すぎて相手にとって理解不能な場合には、その議論を強化する役割をその根拠は果たせない。議論が相手に意見を受け入れてもらうことを目的としたものである以上、議論の良し悪しには相手によって左右される部分があるというのは当然ではあるのだが、明確に言語化されてみるとハッとさせられる。

誤謬の分類、誤謬ゲームのルール

第4章からはいよいよタイトルにも掲げられている「誤謬」についてである。第4章では誤謬というものをこれまでに論じてきた「優れた議論の5つの基準」の1つ以上に違反するものとして定義している。つまり、誤謬は以下の5つのうちの1つ以上の欠陥を持つものということになる。

  • 議論の構造的欠陥(「構造の原則」への違反)
  • 結論と関連のない前提(「関連性の原則」への違反)
  • 前提の許容性の基準を満たさない前提(「許容性の原則」への違反)
  • 結論を裏付けるのに総合的に不十分な前提(「十分性の原則」への違反)
  • 議論への予想される批判に対する効果的な反論の欠如(「反論の原則」への違反)

たとえば、「前件否定の誤謬」は構造に関わる誤謬であり、「伝統に訴える誤謬」は関連性に関わる誤謬である。名前のついた誤謬は数多くあるが、それらを整理できるようになるのが本書の提示している枠組みの利点であると思う。

推論における欠陥パターンの特徴に精通していれば、間違いを正しく特定し、効果的に対処できる可能性が高まる。(p.87)

誤謬の分類の提示に続いて、3種類の誤謬の突き方(自壊に追い込む、論外な反例を提示する、反証を示す)が紹介される。ここで紹介された誤謬の突き方の具体例が、第5章以降の個別の誤謬の解説のなかでも提示される。まさに原題である「Attacking Faulty Reasoning」のパートになる。

以上が第4章の本論に当たる部分だと言えそうだが、章末に置かれた「誤謬ゲームのルール」も本書には欠かせない記述である。そこでは、効果的な話し合いを実現するために必要な12の行動原則(前述)とは別に、スポーツマンシップに相当するルールとして以下が提示されている。

  • 誤謬発見器にならない
  • 相手に推論の欠点を指摘するのは、優れた議論の基準に違反したことで根拠のない結論に達したと確信した場合や、結論を受け入れがたい理由を説明したい時だけにする
  • 自分自身の誤謬を指摘された際には、それを認めて考え方を適切に修正する
  • できれば"誤謬"という言葉は一切使わない

本書のような書籍を手に取る読者は、論理や誤謬について関心を持っている人が多いだろう。そして、本書で紹介されているような誤謬やその突き方を学ぶと、日常の話し合いの中でも「あ、この人はあの誤謬を犯したな」と気づき、指摘したくなってしまうことがあると思う。しかし、そのような行動は相手との関係を悪化させてしまい、優れた議論によって実現されるべき知的進歩や対立の解消を阻害してしまう。実際、著者の論理学の授業を受けた学生にも、周囲の人との関係性が以前よりも悪化してしまったという人がいたとのことで、このセクションを設けることは著者にとっては必要不可欠だったのだと思う。

誤謬のカタログ

第5章以降は誤謬のカタログである。先述の通り、紹介されている誤謬にはそこまで新規性を感じなかった(定番ものを押さえているという見方もできる)。しかし、それは第5章以降が無駄であるということを意味しない。このパートの白眉は、それぞれの誤謬の解説の末尾に付け加えられている「誤謬を突く」のセクションである。

第5章から第9章の5つの章(違反している「優れた議論の基準」に対応している)では、60個(!)の誤謬について、定義と解説、いくつかの具体例に加えて、その誤謬への対処法が紹介されている。この誤謬への対処法が、非常に実践的なのである。

たとえば、「お前だって論法」(「特定の行為に関する論者の批判や議論について、論者が似たような行為を行っていることを理由に、真摯に評価したり反論したりする義務を回避すること。」p.315)については、以下のように記載されている。

議論や批判の内容と行動に一貫性がないと批判されたからといって、黙り込まなくてはならないわけではない。その指摘が正しければ素直に認め、一貫性のなさをとりあえず置いておいて、批判や議論の中身を検討してほしいと言おう。(p.315)

このように、単に誤謬を指摘する論理を紹介するにとどまらず、どのように相手に伝えるかというところまでを含んだ対処法を紹介しているのが面白い。純粋な学術書ではなく、教育的な著作としての色が出ている部分だと思う。

まとめ

以上、『誤謬論入門 優れた議論の実践ガイド』の感想を述べてきた。頭の整理に役立つ書籍で、教育的でもあり、ロングセラーとなっているのも納得であった。また、記事ではあまり言及しなかったが、政治的・社会的テーマについての議論から日常の発言における議論まで幅広い題材から採られている具体例も豊富で、「あるある〜」と思いながら読むことができる。目から鱗が落ちる系の書籍ではなく、「それはそうでしょう」という記述も多々あるが、記事で紹介したような目を引くポイントもあり、全体としてみると価値のある書籍だと思う。

*1:以下、「本書」と呼ぶ。また、以下で特に書名を記載せずにページ数のみで指示する場合は本書の参照を意味する。

*2:なお、議論という言葉は日本語ではdiscussionの意味でも使う(むしろ日常語ではdiscussionの意味で使われる場合の方が多いだろう)ので、本書を読み進める上では注意が必要だと感じた。

Scrum Developers Night! を初めてオンサイトで開催しました

12月14日に、運営を務めている勉強会「Scrum Developers Night!」を初めてオンサイトで開催しました。

smn.connpass.com

会場

会場は、(運営メンバーの長岡さんの勤務先である)ヤフー株式会社内のスペース「LODGE」です。新型コロナ以前は勉強会やイベントの打ち合わせなどで度々利用させてもらっていた会場で、僕自身とても懐かしく感じました。会場提供ありがとうございます。

※2022年12月現在は一般利用の受付はしていないとのことです。

lodge.yahoo.co.jp

Scrum Developers Night! について

Scrum Developers Night! は、2020年の夏ごろから始めた勉強会です。この勉強会については以前サブのブログの方に書いたことがあります。

komad.hatenablog.com

なんでオンサイトで開催したのか

新型コロナの流行以降に始まった勉強会だったので、当初から一貫してオンライン(Discord)での開催を続けてきました。僕自身、フルリモートで働いているので、夕食後の時間に家から参加できるのが便利でしたし、Discordにも慣れているのであまり不便さを感じず、オンサイトへのこだわりはありませんでした。

ただ、年の瀬ということもあり、普段一緒に運営をしているメンバーと「忘年会くらいしたいですよね、せっかくだからオンサイトでイベント開催しますか?」という話をして、オンサイトでの開催をしてみようということになりました。

オンサイトで開催してみてどうだったか

上述の通り、オンライン開催に不便を感じていなかったのですが、オンサイト開催はやっぱり全然違いました。OST形式の勉強会なのですが、オンラインだとどうしても同時に喋るのは1人か2人になってしまいがちなところが、オンサイトだと横から入っていきやすいんでしょうね。聴いているだけの参加者がほぼいませんでした(聴いているだけでも気楽なのが逆にオンラインの良さでもあるのでしょうけれど)。わざわざ足を運ぶだけのモチベーションを持って参加していただいているのでということもあるのでしょうけれど、やっぱり話しやすいのかなとは感じたところです。ホワイトボートもかなり積極的に活用されていました。

当日の様子は以下のScrapboxにまとめています。

scrapbox.io

今後について・・・は考え中です

今回のオンサイト開催の体験が良かったので、オンサイトもやっていけたらなという思いはあります。一方で、オンラインの気楽さ・地理的な制約のなさも捨て難く感じます。運営メンバーの中でも相談しながら今後については考えていければと思っています。続報をお待ちください。

MySQL Advent Calendar 2022 の 13日目の記事として「MySQLのセミジョイン最適化」について書いた

MySQL Advent Calendar 2022 の 13日目の記事として、MySQLのセミジョイン最適化について調べた記事を書きました。こちらのブログに書いてもよかったのですが、今回は会社のブログに書きました。

qiita.com

tech.bm-sms.co.jp

昨年はアドベントカレンダーはどうだったんだっけ?と確認してみたところ、1本だけ記事を書いていました。もう1年になるんですね。

ky-yk-d.hatenablog.com

今年は書く予定がなかったのですが、ちょうどいいタイミングで書けることができたのでよかったです。ブログもあまり書けていないですし、だいぶコミュニティの出入りも少なくなってしまっているので、来年はまた少し変えてみられるとよいかなぁなどと思っています。

コミュニティといえば、明日(!)、久しぶりにオフラインの勉強会に運営側として参加するので、ぜひご参加ください。

smn.connpass.com

pom.xmlの特定の要素をxmllintで書き換える

CIからpom.xmlを自動で更新するような仕組みを入れようと思って、pom.xmlを書き換える方法を調べたのでメモ。

ポイントとしては、

  • 名前空間付きのもののときは *[local-name()='hoge'] を使う
  • 同名のタグが複数ある場合に特定のノードのものを選択するには and を使う

になる。

例題

以下のようなpom.xmlで、 maven-compiler-plugin のバージョンを変えたい。

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>junit5-jupiter-starter-maven</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>${maven.compiler.source}</maven.compiler.target>
    </properties>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.junit</groupId>
                <artifactId>junit-bom</artifactId>
                <version>5.9.1</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <dependencies>
        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
            </plugin>
            <plugin>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>3.0.0-M6</version>
            </plugin>
        </plugins>
    </build>

</project>

(コードは https://github.com/junit-team/junit5-samples/blob/f7029d7b9e5c73a8f3615a761d51e6e756e3e09d/junit5-jupiter-starter-maven/pom.xml のもの)

対応方法

たとえば以下のように記述すればよい。

VERSION=3.9.0
xmllint --shell pom.xml << EOF
cd /*[local-name()='project']/*[local-name()='build']/*[local-name()='plugins']/*[local-name()='plugin' and *[local-name()='artifactId']/text() = 'maven-compiler-plugin']/*[local-name()='version']
set $VERSION
save
EOF

名前空間付きのタグに対しては local-name() を使う

タグ名は実際には名前空間付きなので、テキストファイル上の名前を使って /project/build/... のように指定することはできない。local-name() を使って対象のタグを指定する必要がある。

同名のタグが複数ある場合に特定のノードのものを選択するには and を使う

書き換えたい要素は <plugins> 配下に複数ある <plugin> のうちの特定のものなので、条件を追加して指定する必要がある。以下の部分。

*[local-name()='plugin' and *[local-name()='artifactId']/text() = 'maven-compiler-plugin']

<plugin> で、かつ <artifactId> の内容が maven-compiler-plugin であるものを選択するためにこのような記述をしている。

local-name() を何度も書きたくないときは

何回も local-name() を書くのは見た目的にもわかりづらくなるので、ルートノードからの厳密なパスを指定せずに // を使って指定することもできる。

VERSION=3.9.0
xmllint --shell pom.xml << EOF
cd //*[local-name()='plugin' and *[local-name()='artifactId']/text() = 'maven-compiler-plugin']/*[local-name()='version']
set $VERSION
save
EOF

参考

atmarkit.itmedia.co.jp

techblog.zozo.com

MySQLの実行計画で Using intersect (...)な index_merge には要注意

実行計画での typeカラムに index_mergeが出たら

MySQLで、WHERE句で複数の条件をANDやORで繋いでいるクエリの実行計画をとると、 type カラムに index_merge というのが出ることがある。これはインデックスマージ最適化というものが使われるということを示している。

dev.mysql.com

インデックスマージ最適化とは

インデックスマージ最適化とは、本来は単一のクエリではインデックスが1つしか利用できないところ、複数のインデックスを使ってそれらをマージすることで最終的な結果を得るというアルゴリズムを使う最適化だ。

これに対し、MySQL 5.0 以降のバージョンでは、クエリが両方のインデックスを使用でき、それらを同時にスキャンして結果をマージできる。OR条件の和集合、AND条件の積集合、2つの組み合わせの積集合の和集合という3種類のアルゴリズムがある。 (『実践ハイパフォーマンスMySQL 第3版』168ページ)

3種類のアルゴリズムのうちのどれが使われるかは、実行計画のExtra カラムで知ることができる。

  • Using union(...): 和集合アクセスアルゴリズム
  • Using intersect(...): 共通集合アクセスアルゴリズム
  • Using sort_union(...) : ソート和集合アクセスアルゴリズム

「最適化」だから安心していい?

これらは「最適化」なので、一見すると「ありがとうMySQL」となりそうなのだが、実際にはその名に反して、クエリに問題があることを示唆しているケースがある。

インデックスマージ戦略が非常にうまくいくこともあるが、実際には、テーブルがうまくインデックス付けされていないことの裏返しであることのほうが多い。

(『実践ハイパフォーマンスMySQL 第3版』169ページ)

たとえば、 Using intersect(...) であれば、これはWHERE句で指定しているすべてのカラムを含んだ複合インデックスが作られているべき場面に個々のカラムへのインデックスしかない場合に出ていることがある。具体例として、以下のようなクエリを考える。

SELECT *
FROM products
WHERE category_id = 1
AND publication_year = '202209';

このクエリの実行計画で、 Using intersect(...) となっているとしたら、それは category_idpublication_year のそれぞれのカラムにインデックスが付いている場合だろう。その場合、個々のインデックスをスキャンし、category_id のインデックスについては category_id = 1 だが publication_year が 202209 ではない部分、publication_year のインデックスについては publication_year = '202209' だが category_id が 1 ではない部分も、それぞれ一旦(インデックススキャンの結果として)取得され、その後で共通部分をとって(マージして )、テーブル本体にアクセスすることになる。

それぞれのインデックスの選択性が高ければ大きな問題にはならないが、選択性の低いインデックスの場合は、途中のインデックススキャンの段階で無駄なリソースを消費し、パフォーマンスも悪くなってしまう危険性がある。

このクエリの場合、category_id, publication_year のような複合インデックスがあれば、最初からインデックス上の category_id = 1 かつ publication_year = '202209' の部分のみを使ってテーブルにアクセスでき、パフォーマンスの改善につながるケースがある。

Using intersect(...) を見過ごしてしまいやすい理由

ここまで書いたことは、実行計画の typeカラムを見て index_merge になっていることに「おや?」と思えれば調べられるだろうが、あまり詳しくない人は見逃してしまう危険性がある。

実行計画を見て、 typeALL になっていたり、 rows に巨大な数値が出ていたりすれば、「このクエリはまずそうだ」と思いやすいが、 index_mergeUsing intersect(...) となる場合、 rows カラムに出る数値はあくまで「最終的に読み込まれる行数の見積り」なので、先述したインデックスマージの途中で読み取られるインデックスの範囲のうちマージ時に(共通部分ではなかったために)除外される部分については rows カラムの数値には含まれない。 rows カラムに小さな値が出ているからといって、パフォーマンスが良いとは限らないというわけだ。

www.percona.com

実行計画を見るというのは、ある程度DBを触っていると基本的な仕草になってくるが、どこまで細かく見られるかというのはかなり違いがある(自分もとても詳しいわけではない)と思われ、「あれ?このクエリ?」と思うことがあったら都度勉強しなおしていきたい。