KENTEM TechBlog

建設業のDXを実現するKENTEMの技術ブログです。

React エンジニアが GitHub Copilot と半年暮らしてわかった。「設計する時間」が増えた話

こんにちは、Reactを中心にフロントエンド開発をしているエンジニアです。

AIコーディングエージェントが普及し始めてしばらく経ちますが、みなさんの現場ではどうでしょうか。私もGitHub Copilotを活用して半年が経ちました。

半年経った今、設計について考える時間が増えたこと。これが最も大きな変化です。

この半年の実体験を記事としてまとめました。GitHub Copilotに限らず、これからAIコーディングエージェントを導入しようとしている方の参考になれば幸いです。

課題:コーディングに時間を取られていた

納期が厳しく、タスクが積み重なっている状況で「まずは動くもの」を優先し、責務の分割や状態管理の設計を後回しにした経験はないでしょうか。

私自身、「ここは構造を整理しないと後で修正コストが高くなる」と分かっていても、締め切りを優先して「とりあえず動くコード」を書くことがありました。

設計時間の圧迫

Copilot導入以前、作業時間の多くは「構文」や「実装の詳細」に費やされていました。 「どう分割すべきか(設計)」よりも「どうすれば動くか(実装)」が優先され、「後でリファクタリングしよう」となりました。

巨大コンポーネントの発生

その結果、1つのファイルにUI・ビジネスロジック・API通信がすべて含まれる状態になります。 親から子、孫へとPropsのバケツリレーが続き、状態の変更箇所を追跡しにくくなります。これは後の機能改修やバグ修正で対応コストを増加させる要因となりました。

(※これは説明用に単純化した「Fatコンポーネント」例です)

// UIの中に「ビジネスロジック」と「通信」が混在している
const ProductCard = ({ product }: { product: Product }) => {
  const { user } = useAuth(); 
  const [isSending, setIsSending] = useState<boolean>(false);

  const handleBuy = async () => {
    setIsSending(true);
    try {
      // 問題点1:価格計算(ビジネスロジック)がUI層に直書きされている
      // 「プレミアム会員は10%OFF」というルールをUIが知ってしまっている
      const price = user.isPremium ? product.price * 0.9 : product.price;

      // 問題点2:API通信の詳細(エンドポイントやデータ構造)もUI層にある
      await axios.post('/api/purchase', { id: product.id, price });
      
      toast.success('購入しました');
    } catch  {
      toast.error('失敗しました');
    } finally {
      setIsSending(false);
    }
  };

  return (
    <div className="card">
      <h3>{product.name}</h3>
      {/* 問題点3:ここにも計算ロジックが登場(ロジックの散在) */}
      <p>価格: {user.isPremium ? product.price * 0.9 : product.price}</p>
      
      <button onClick={handleBuy} disabled={isSending || product.stock <= 0}>
        {product.stock <= 0 ? '売り切れ' : '購入する'}
      </button>
    </div>
  );
};

責務を分けるべきだと分かっていても、ファイル分割やProps定義のやり直しにかかる時間がネックでした。

導入後:実装をAIに任せ、設計に集中する

しかし、Copilotの導入で状況が変わりました。「関数の中身を書く」「型に合わせた定型コードを書く」といった実装作業をAIが短時間で処理してくれます。

その結果、システム構造の設計に時間を割けるようになりました。

以下は、「UIは購入の意志を伝えるだけで、ルールの判定は行わない」という方針で書き換えた例です。

// 価格計算は純粋関数として分離
const calculatePrice = (product: Product, user: User): number => {
  return user.isPremium ? product.price * 0.9 : product.price;
};

// 購入可否の判定も純粋関数として分離
const canBuy = (product: Product): boolean => {
  return product.stock > 0;
};

// 購入処理(副作用)と状態管理を集約
const usePurchaseAction = () => {
  const [isPending, setIsPending] = useState<boolean>(false);

  const execute = async (productId: string, price: number) => {
    setIsPending(true);
    try {
      await api.purchase({ id: productId, price });
      toast.success('購入しました');
    } catch {
      toast.error('失敗しました');
    } finally {
      setIsPending(false);
    }
  };

  return { execute, isPending };
};

// UIコンポーネントはシンプルに。条件分岐が減り、宣言的になる
const ProductCard = ({ product }: { product: Product }) => {
  const { user } = useAuth();
  const { execute, isPending } = usePurchaseAction();

  const finalPrice = calculatePrice(product, user);
  const isBuyable = canBuy(product);

  return (
    <div className="card">
      <h3>{product.name}</h3>
      <p>価格: {finalPrice}</p>
      
      <button 
        onClick={() => execute(product.id, finalPrice)} 
        disabled={isPending || !isBuyable}
      >
        {!isBuyable ? '売り切れ' : '購入する'}
      </button>
    </div>
  );
};

以前は「オーバーエンジニアリングではないか」と避けていた設計にも、時間を割けるようになりました。

まとめ

設計に時間を使えるようになり、コードに対する向き合い方が「どう動くか」から「どうあるべきか」へと根本的に変わりました。

「配列の操作」や「非同期処理」といった実装の詳細はAIが処理してくれます。その分、私たちは以下のような本質的な問いに時間を割けるようになります。

  • この変数は、システム内でどのような意味を持つか

  • このコンポーネントは、どのような状態を表現すべきか

  • このコード構造で保守性は担保できるか

責務の分離やドメインモデルの整理に注力できるようになった結果、コードの見通しと品質が向上したと感じています。

「AIで実装時間を短縮し、人間は設計に集中する」。このアプローチが、エンジニアリングの質を高めると私は実感しています。

おわりに

KENTEMでは、様々な拠点でエンジニアを大募集しています! 建設×ITにご興味頂いた方は、是非下記のリンクからご応募ください。 recruit.kentem.jp career.kentem.jp