👾

カーゴカルトをやめたい!初学者の反省と学び             ( Zod 編 )              

に公開

はじめに

こんにちは!株式会社ソニックムーブでフロントエンドエンジニアをしている 石黒 です。

正直な話、これまでで「とりあえず 〜 をつければいい」「とりあえず 〜 してから考える」と、深く考えずにコードを書くことがありました。

初学者であるが故に、少ない知識の中から実装方法が思いついて「これ以上の実装方法は思いつかない!」と決めつけて新しい可能性を考えなかったり、検索・引用した実装方法の検証部分(セキュアな実装かどうか等)がわからず、そのまま使用してしまうなど・・・

でもそれって実は「カーゴカルト・プログラミング」と呼ばれる状態だと知って、少しドキッとしました。

今回は、そんな私が「カーゴカルト・プログラミング」から脱却するために学んだことを共有したいと思います!

カーゴカルト・プログラミングとは?

「実際の目的には必要のないコードやプログラム構造が儀式的に含められているという状態で特徴づけられる悪習である。カーゴ・カルト・プログラミングは、プログラマが、自身が解決しようとしている課題やバグ、明らかな解決策を理解していないことを示す兆候である」

これを「カーゴカルト・プログラミング(Cargo Cult Programming)」と呼ぶそうです。(Wikipedia

やったこと

今回は、事前知識がなく最近触れる機会のあった、TypeScript向けのスキーマバリデーションライブラリである Zod をテーマに進めていきます。

❌ よくあるカーゴカルト的な使い方

とりあえず」で Zodの公式ドキュメント を参考にスキーマを定義してみます。

//とりあえず書いてみたzod schema
import { z } from 'zod';

const wrongSchema = z.object({
  name: z.string(),
  age: z.number(),
});

例えば上記に、次のようなデータを渡してみます。

const userData = {
  name: 'Ishiguro',
  age: '23', // age は string 型
};

const user = wrongSchema.parse(userData);

この上で、どのような結果が得られるか結果を出力する部分を実装してみます。

try {
  const user = wrongSchema.parse(userData);
  console.log('User age:', user.age);
} catch (e) {
  if (e instanceof z.ZodError) {
    console.error('Validation errors');
  } else {
    console.error('Unexpected error:');
  }
}

実行すると

Validation errors

とでました。

ageは、年齢だからnumberでいいだろうという仮定からコピー & ペーストで z.number() でスキーマを「とりあえず」組んでしまった結果、文字列で年齢が渡った場合にエラーが出てしまいました。

const rightSchema = z.object({
  name: z.string(),
  age: z.coerce.number(), // string から number に自動変換
});

このように、文字列の場合も想定して実装することで解決することができます。
また、zod.coercenumberの他に変換できるかどうかということや、下記のようなできないことを調べてわかる範囲で理解しておくことが大切です。

const userData = {
  name: 'Ishiguro',
  age: 'twenty-three', 
};

const user = rightSchema.parse(userData); // エラーが出る

今回使用したコード全体


import { z } from 'zod';

//とりあえず書いてみたzod schema
const wrongSchema = z.object({
  name: z.string(),
  age: z.number(),
});

const rightSchema = z.object({
  name: z.string(),
  age: z.coerce.number(), // string から number に自動変換
});

const userData = {
  name: 'Ishiguro',
  age: '23', // age は string 型
};

try {
  // wrong の場合
  // const user = wrongSchema.parse(userData);

  const user = rightSchema.parse(userData);
  console.log('User age:', user.age);
} catch (e) {
  if (e instanceof z.ZodError) {
    console.error('Validation errors');
  } else {
    console.error('Unexpected error:');
  }
}

以上となります。・・・・














と言いたいところではありますが、これだけではありません。生成AIチャットサービスである ChatGPT を下記の部分で使用してます。

try {
  // wrong の場合
  // const user = wrongSchema.parse(userData);

  const user = rightSchema.parse(userData);
  console.log('User age:', user.age);
} catch (e) {
  if (e instanceof z.ZodError) {
    console.error('Validation errors');
  } else
    console.error('Unexpected error:');
  }
}

カーゴカルト・プログラミング」から脱却するためには、この部分についても初学者が理解し説明できるか、コードが正しいか、検討できていないポイントがないか考える必要があります。
より良い、「カーゴカルト・プログラミング」から脱却するための全体のコードとしては、以下になると考えました。

✅ 今回使用したコード全体(カーゴカルト・プログラミングなし)

//TypeScript向けのスキーマバリデーションライブラリ の import
import { z } from 'zod';

//とりあえず書いてみたzod schema
//zod.object で オブジェクト型のスキーマを定義できる
const wrongSchema = z.object({
  name: z.string(),
  age: z.number(),
});

const rightSchema = z.object({
  name: z.string(),
  age: z.coerce.number(), // string から number に自動変換
});

const userData = {
  name: 'Ishiguro',
  age: '23', // age は string 型
};

//例外処理
try {
  //parse でバリデーションができる。失敗でZodErrorがthrow
  // wrong の場合
  // const user = wrongSchema.parse(userData); 

  const user = rightSchema.parse(userData);
  console.log('User age:', user.age);
} catch (e) {

 // 変数 e が z.ZodError のインスタンスかどうかを判定している。これにより、他のエラーと区別できるようになる。
  if (e instanceof z.ZodError) {
    console.error('Validation errors');
  } else {
    console.error('Unexpected error:');
  }
}

初学者が少しでも不安な部分に、調査した上で自分自身でコメントするだけでも「カーゴカルト・プログラミング」から脱却することができると思います。
コメントを入れて、自分よりも知識豊富な人に確認・添削してもらうことで

  • 初学者が理解をしているかどうか
  • 初学者が検討できていない部分・勘違いしている部分

が知識豊富な人の視点でわかりやすいというメリットがあります。

また、「コメントのない部分はすでに理解できている部分です」という指標となるため理解確認の回数が少なくなるメリットもあります。

初学者視点での「カーゴカルト・プログラミング」になってしまう理由

  • 時間がないと感じている(実装を精査する、勉強をする)
  • 信じて疑わない(参考にした実装を信じすぎてしまう等)
  • 何を他に検討したらいいかわからない

があると考えてます。

これに対して、初学者は

  • 「時間がないと感じているので、時間が欲しいです!」と伝える あるいは 時間を作る
  • 「これでいいと思っちゃってます!」と伝える あるいは 「これでいいのか・・・?」と疑う
  • 「見落としありそうで自信ないんですけど、どうですか?」と伝える あるいは 検討できそうなことを考える

などといった行動をとる必要があると思います。これまでやったことがなくても、勇気を出して行動してみましょう。
きっと、成長できるはずです。(自己暗示)
恥ずかしくもない!(自己暗示)

あくまでも作業するのは人間になるので、全てを精査・確認するのは知識的にも体力的にも時間的にも限界があるためできる範囲だけでもやりましょう。私もそうします。

初学者の反省と学び

反省としては、自分自身が思っていた以上に

  • 「知識を深めようとしていなかった」
  • 「型にこだわりすぎていた」
  • 「既存のものを信じすぎていた」
  • 「伝える勇気がなかった」

です。これからでも遅くない、頑張ろう。

今回、述べたかったことは

  • 事前に準備をする
    -「間違っていたとしても、実装内容と理由を説明できるようにしておこう」
    -「実装して終わりではなく、他に考えるべきことがないか検討・確認しよう」
    -「時間をかけてでも理解に努めよう」

  • 正直になる
    -「説明できない実装の方法は実装しないようにしよう」
    -「わからない部分はわからないと認めよう」
    -「相談できる環境であれば、わかりませんと相談しよう」

ということです。

まとめ

生成AIや自分の偏った知識に頼りすぎてしまい「とりあえずで書いてしまう」ことが初学者の一部にはあります。

そのため、「理解していないこと」を周知することや「理解しようとする姿勢が重要です。

「不必要な実装」をしてしまったり、「わかっているようでわかっていないエンジニア」が誕生してしまうので、「見よう見まね」ではなく、意図と用途を理解することが大切だと学びました。

次回の記事は、「確認してますか? 初学者の反省と学び」になりそうです。
次回も、お楽しみに。

株式会社ソニックムーブ

Discussion