AAIニュース
最新ニュースAI日報Hacker日報週報動画AIツールトレンド企業
AAIニュース

世界中のAI最新情報を日本語で。毎時自動収集・翻訳・要約。

コンテンツ

最新ニュースAI日報週報

分析

トレンド企業動画

サイト

についてRSSお問い合わせ
© 2026 ainew.jp — All rights reserved.特定商取引法に基づく表記
ニュース一覧元記事を開く
Chander Ramesh·2024年1月1日 09:00·約3分

IF文で考えるのをやめよう!

#ソフトウェア設計#状態管理#ユーザーインタラクション#技術的負債#複雑性管理
TL;DR

若手エンジニアのよくある間違いはシステム思考の欠如で、特にIF文の多用に現れます。

AI深層分析2026年2月25日 15:41
2
参考/ 5段階
関連性
2
新規性
3
影響度
2
信頼性
2

キーポイント

1

IF文による状態管理は複雑性が指数関数的に増大する問題がある

2

ユーザーインタラクションの多様化に対応するには設計パターンの見直しが必要

3

シンプルな実装から始まっても機能追加で技術的負債が蓄積するリスク

影響分析・編集コメントを表示

影響分析

この記事はAI/機械学習システムの開発においても重要な教訓を提供しており、複雑な状態管理や意思決定ロジックの設計において、従来の条件分岐中心のアプローチの限界を示している。特にインタラクティブなAIシステムやリアルタイム意思決定システムの開発に応用可能な洞察を含んでいる。

編集コメント

AIシステム開発においても、複雑な状態遷移や意思決定ロジックの設計には同様の課題が存在する。特に強化学習や対話システムの実装において参考になる実践的知見。

冬休みに、LitとWebComponentsを学ぶ手段として六角形チェスを開発した著者は、独自のUXを考案する代わりに、LichessやChess.comのインターフェースを模倣することにした。当初は単純に見えた。ユーザーが駒をクリックで選択し、移動先をクリックすればよい。これには、選択された駒を格納する単一のnull許容変数「selectedPiece」があれば十分で、選択駒を黄色で強調し、合法手を黄丸で表示すればよいと考えた。

しかし、プレイテストを始めると、多くのユーザーが六角形チェスのルールを知らず、単に合法手を確認するために駒をクリックし、その後で気が変わって別の駒を動かしたいというケースが頻発した。そこで著者は、selectedPieceがnullでない時に次のマウスダウンを監視し、空マスか駒かを判定。空マスなら移動を試み、駒ならselectedPieceを新たな駒に設定するロジックを追加した。

だが、今度は駒の「捕獲」の処理が問題となった。選択駒があり、新しいマスが捕獲可能でない場合はselectedPieceを更新し、捕獲可能なら捕獲を実行し、空マスなら移動する、という複雑なIF文の連鎖が生じた。煩わしいが一応完成し、再びLitの学習に戻った。

さらにプレイテストを重ねると、今度は多くのユーザーが駒を「ドラッグ&ドロップ」で動かすことを好むことが判明。これに対応するため、「dragPiece」と「currentlyDraggedOverSquare」という新たな状態変数を追加。ドラッグ中にマウスがマスに入る度に状態を更新するロジックを実装した。

しかし、ここで新たな問題が噴出した。不正なマスや盤外、他の駒の上でマウスボタンを離した場合、Chess.comのように最初の選択を維持して再試行を許すべきか? 不正な移動時はselectedPieceをnullにしないように修正したが、今度は「選択済みの駒がある状態でも、ユーザーがその駒をポインタダウンでドラッグ開始できてしまう」という矛盾が生じた。

これはわずか3つのイベントと3つの状態変数での話である。実際のLichessではゲームの巻き戻しや早送り、さらには右クリックでの矢印描画やコメント機能など、より多くのイベントと状態が存在する。IF文を連ねるアプローチでは、新しい状態変数やイベントを追加する度に、既存のロジックとの組み合わせが爆発的に増加し、全ての組み合わせをテストして正しさを保証しなければならない。コードが整理されず、拡張性に欠けるため、機能追加のたびに複雑さが指数関数的に増大してしまうのだ。

この経験から著者が指摘する核心は、IF文による直線的な状態管理の限界である。システムが複雑化する中で、柔軟に新機能を追加しつつ既存動作を壊さないためには、状態遷移を体系化された方法(例えば状態機械やデザインパターン

原文を表示

Chander Ramesh Over winter break I built Hexagonal chess, as a way to learn about Lit and WebComponents. Rather than come up with my own UX, I decided to emulate Lichess and Chess.com.

It certainly seemed simple enough at the time; users can click to select a piece, and click to move it. This set up only requires a single nullable variable — selectedPiece. Easy enough, just highlight the selected piece in yellow and show the legal moves with a yellow dot.

But as I began to play test, it became obvious that most people had no idea what the rules of Hexagonal chess were, and often times they’d click on a piece just to see what the legal moves are, but then change their mind and want to move another piece instead.

Ok no problem — whenever selected piece is not null, the next time they mouse down check to see if they’re selecting an empty space or a piece; if it’s an empty space, try and make a move, otherwise set selectedPiece to the new piece.

Oh, wait. What about captures? Ok fine, if selectedPiece is not null and the new square cannot be captured, set selectedPiece to the new square, otherwise perform the capture; and if it’s an empty sell, just move the piece. Annoying, but ok we’re done — back to learning Lit and Web Components.

Then I began to play test some more, and it turns out, most people actually preferred to drag the pieces from one square to another. So I added a couple new variables called dragPiece and currentlyDraggedOverSquare. If dragPiece was null, just ignore all pointermove events. If it was not null, then every time the mouseenter event fired, update currentlyDraggedOverSquare. Easy!

But what if they mouseup-ed on an illegal square? Or outside the board? Or on top of another piece? Well, Chess.com keeps the initial selection, letting the user try again. Ok no problem — if mouseup fires on an illegal move, don’t set selectedPiece to null. But now we have another problem. Until now, pointerdown has only ever been fired when selectedPiece is null… but now the user can pointerdown and drag it, even though there’s already a selectedPiece.

This is just with 3 events and 3 state variables. Lichess actually allows users to rewind and fast forward the game to see prior moves. What happens if the user clicks on a piece when they’re rewinding? What happens if the user clicks on a piece when it’s not their turn? What if they have a piece selected but click outside the board? And actually, turns out users want to be able to right click on square and drag to draw arrows and make commentary on other games…

Are you starting to see the problem?

How do we allow the software flexibility to add more events and more states without breaking the previous ones? The problem with if statements like these is that the complexity grows exponentially. Since the code isn’t organized or well thought out, the only way to guarantee correctness is to test every combination of variables and assert their behavior. Every new state variable introduces 2n new states!

This amount of work is crippling for velocity, and nobody can keep this many states in their head. So you rapidly get to a state where nobody can describe how the system is supposed to behave, let alone how it actually behaves.

Enter state machines. Here is the full, complete state machine for HexChess when making moves and rewinding / fast forwarding. This doesn’t include resigning, offering a draw, or drawing arrows.

There’s three main benefits to this way of thinking.

Perhaps most obviously, it’s extremely easy to add new states and transitions because you’re allowed to compartmentalize the complexity away. When you’re dealing with pawn promotions, the only state variables you have to care about are which pawn is being promoted. When you break down the problem like that, it’s actually quite easy to know what to do when a mousedown or mouseup event happens.

It’s not uncommon to realize that, when adding a new state for a new feature, the old states also need a new variable added. Halfway through I decided I needed to start keeping score, so I can show who has captured more pieces. And actually track all the moves that had been made thus far, so we can rewind and fast forward.

This is precisely what state machines were made for. Simply add the new variables and add a couple lines to each unit test.

Second, because all of this has nothing to do with how the component is being rendered — it’s all pure business logic — you can ensure high test coverage with basically no effort!

This screenshot is from when I was only halfway through the project; I was simply writing tests as I was going along, precisely because the state machine made it so easy.

Too many codebases muddle business and rendering logic in the same file or the same component. This is particularly easy to do with React codebases. But creating a state machine is a forcing function to separate that out. Now, there’s a single variable called state which holds all the complexity, and any tr

この記事をシェア

関連記事

Chander Ramesh2025年6月12日 09:00

黄金時代

Chander Ramesh2025年2月8日 09:00

あなたが人生と呼ぶすべて

Chander Ramesh2025年2月3日 09:00

中核的価値観

今日のまとめ

AI日報で今日の重要ニュースをまとめ読み

ニュース一覧に戻る元記事を読む