🧠

生成AIで自動テストの重要性が高まっていそうという話

2024/06/16に公開

いやいや今更やん。
と思う方もたくさんいると思うけど、思考の整理を含めて改めてということで。

生成AIでのバージョンアップの実態

昨年あたりから盛んに生成AIが活用され始めました。
生成AIのパワーでいわゆるフレームワークのバージョンアップやライブラリの書き換えというのは、かなり進むのではないか?と思ったのだけど、意外とそうでもなかったというのが個人的な感想。
1年もすれば、Next.jsのApp Routerのような変更も、生成AIのお陰でさっとできるようになっているんじゃないの?と思いましたが、そんなことはありませんでした。[1]
結局生成AIでライブラリのバージョンアップが楽になったとかはまだなくて、色々苦労しているところがほとんどなのではないだろうか。

置き換えやもっというとライブラリの移行をAIにやらせる類のサービスはちょっと見かけるようになってて[2]、JavaScriptからTypeScriptにするのだったり、Vue2 からVue3へ、果てはReactなんかに変換しようみたいなことも。

そういうのはちらほら出てきたが、どの企業もサービスも、まだまだバージョンアップだったりの問題に困ってそうで、あまり話題のなってないなーというのが正直なところで、それっぽい実績がないのだなーと思ったのだでした。[3]

なぜ?

フレームワークが処理する層と開発するビジネスロジックが密結合になっていると、テストがしづらいという課題が多くの現場のコードで見受けられるかなと思っています。
これが「思ったより役に立っていない」原因の一つではないかと思ってて、そのことが解決を難しくしているのではないかなぁと思っています。

テストがしづらいと、自動テストを書くのが難しくなり、継続的なメンテナンスも困難になります。AIがフレームワークやライブラリ以外のコードについても推論する必要があり、そこに苦労しているのではないでしょうか。

特にUI層のテストはまだまだコストが高いです。
DDDやクリーンアーキテクチャまで構造化する必要はないですが、
ビジネスロジックとライブラリ層をある程度分離することでテスタビリティが向上し、フレームワーク移行やバージョンアップに自信を持てるようになるのではないかと考えています。

AIがコーディングし易いように環境を整える

当然GitHubCopilotだったりで、そのあたりの現場のコードに対しての課題も解決されそうだけど、それがこれから1年で現場にフィットするレベルで解決されるとは思っていません。
こうなってくると自動テストがされてるプロジェクトとそうではないプロジェクトでかなり大きな生産性に対しての差が出てくるのではないかと思います。
一方は自動テストがかなりカバーされていて、AIがライブラリのバージョンアップだったりで必要な修正を自動で行って安全に、素早くどんどんバージョンアップしているプロジェクトと、
自動テストがないことで、ライブラリのバージョンアップが進まない、さらに生成AIが考えなければならないコードが多く、ライブラリのバージョンアップアップがままならない。
という2極化がより進むのではないかと考えています。

なので、現場ではテストがしづらいコードが散見されがちなので、
それらをテストがし易いようにまずはリファクタリングする
というのがWebエンジニアの生成AIの活用の一歩目なのかなと思っています。

具体的には?

例えば、古くからある、VueのOptions APIで実装されているコード(特にmethodsなど)を、
純粋関数にしてテスタビリティを高めるということを検討している。

<template>
  <div>
    <todo-item
      v-for="todo in todos"
      :key="todo.id"
      :todo="todo"
      @toggle-todo="toggleTodo"
    />
  </div>
</template>

<script>
import { deleteTodo } from './logics';
import TodoItem from './TodoItem.vue';

export default {
  components: {
    TodoItem,
  },
  data() {
    return {
      todos: [],
    }
  },
  async created() {
    this.todos = await fetchTodos();
  },
  methods: {
    async deleteTodo(todo) {
      this.todos = await deleteTodo(this.todos, todo);
    },
  },
};
</script>
type TodoId = number;
type Todo = {
  id: TodoId;
  todo: string;
  completed: boolean;
}

export const fetchTodos = async () => {
  const response = await axios.get('https://dummyjson.com/todos');
  return response.data.todos;
};

export const deleteTodo = async (todos: Todo[], todo: Todo): Promise<Todo[]> => {
  await axios.delete(`https://dummyjson.com/todos/${todo.id}`);
  todos = todos.filter((t) => t.id !== todo.id);
  return todos
};

最近ではComposition APIに移行するのが主流ですが、Options APIを使い続けるのは筆者の趣味で、もう一度くらいReactのHooksのような、コンポーネントの考え方が変わり、記法が変わることがあるかもしれないと考えているため、特定のフレームワークに依存しない方法を取っています。

Composition APIはサポートが終了したり、便利なライブラリがない限り、利用しないかなと思っています。

さいごに

色々な方法があるけど、自動テストがあったり、自動テストがし易い環境であることの重要性がもっと高まると思うので、どんどんユニットテストなどを書いていこう!!

脚注
  1. App Routerに対してどうとかはなくて、こういった悩みが残ったままなんだなという。 ↩︎

  2. https://www.second.dev/ ↩︎

  3. 個人開発なら見かけるけど ↩︎

Discussion