お知らせ

現在サイトのリニューアル作業中のため、全体的にページの表示が乱れています。
投稿日:
開発::設計

今の職場でコードを書いていてifに対して原則elseを書かないという雰囲気があるのですが、個人的にはelseを書きたいのでその話です。

世間的にelseを書かないというコーディングルールは一定の支持があるようで、まぁ一種の宗教だとは思っていますが、個人的にはどうなんかなと思っています。まぁ割と最近の流行りな気もしていますが…。(昔はなかったと思う…というとアレですが)

elseがあってほしい理由

else ifelseブロックがあると処理の関連性が見やすくなると考えています。

処理の関連性がわかりやすくなる

例えば以下のコードの場合、ifが連続しているよりelseがある方が処理の関連性が明示的に見えると思います。elseで繋げないことは基本的に処理として関連性がないはずです。

// ifのみ
export const hoge = (mode: 1|2|3) => {
  if (mode === 1) {
    // なんかの処理
    return 'hoge';
  }
  if (mode === 2) {
    // なんかの処理
    return 'piyo';
  }
  if (mode === 3) {
    // なんかの処理
    return 'fuga';
  }
}

// elseあり
export const piyo = (mode: 1|2|3) => {
  if (mode === 1) {
    // なんかの処理
    return 'hoge';
  } else if (mode === 2) {
    // なんかの処理
    return 'piyo';
  } else if (mode === 3) {
    // なんかの処理
    return 'fuga';
  }
}

予期せぬ不具合が入り込みづらくなる

ifだけで構成されたコードでは以下のようにifブロックの外に処理を入れ込むことができますが、このときA1, B1, C1のifの外にある処理は後続処理に影響します。しかしこの書き方だと処理の影響範囲が見積もりづらく、不必要なバグを生む元になるため、個人的には避けたいと考えています。(他の処理の作用に引っ張られているので、副作用のある実装ということになると思っています)

またA1, B1, C1の行数が伸びるとコードの見通しが悪くなり、if同士の関係性が分かりづらくなります。

elseを使うとこういった副作用的な振る舞いをする実装が作りづらくなり、影響範囲もブロックインデントで分かれるので、そういった心配がなくなります。

// ifのみ
export const hoge = (mode: 1|2|3) => {
  // なんかの処理 A1
  if (mode === 1) {
    // なんかの処理 A2
    return 'hoge';
  }
  // なんかの処理 B1
  if (mode === 2) {
    // なんかの処理 B2
    return 'piyo';
  }
  // なんかの処理 C1
  if (mode === 3) {
    // なんかの処理 C2
    return 'fuga';
  }
}

elseが必要なのに書き忘れることが減る

elseを書かないことに捕らわれていると以下のようなコードが生まれることがあります。

さてこのコードにおいて!validHoge(hoge) || !hasPiyoのケースはどのように処理されるのでしょうか?答えは処理されませんが、もしこのコードに対してUnit testが実装されておらず、特段のドキュメントもなければ、それが正しいのかどうかをコードから読み取ることが出来ません。

const isValidUsername = (username: string, hasInputed: boolean) => {
  if (validUsername(username) && hasInputed) {
    return requestSearchUsername(username);
  }
}

せめてこう書いてあれば判断も付くでしょう。

const isValidUsername = (username: string, hasInputed: boolean) => {
  if (validUsername(username) && hasInputed) {
    return requestSearchUsername(username);
  } else {
    // 何もしない
  }
}

因みにこの処理はユーザー登録フォームでユーザー名の書式が正しければ既に存在するユーザー名かどうかをAPIに問い合わせ、既に存在すればエラーメッセージを、存在しなければtrueを返すという内容ですが、そもそも書式が不正である場合は何もしないため、ユーザーはエラーであることを知ることが出来ません。

もしelseブロックを書いていれば考慮漏れに気づけた可能性もあったのではないかと思います。

elseを使うケースを考えなくて良くなる

ifに対して原則elseを書かないというルールがあってもelseを書かないと成り立たないケースは存在します。そう言った場合に原則ifしか書いてはならないというルールがあるとelseを書いてよいかどうか考える必要が出てきますが、元からelseも書いて良いルールであればそこは考える必要がありません。個人的に判断の余地が生じるコーディングルールはチーム開発ではない方が良いと考えています。

またこのルールの結果、本来必要だったelseを書かなかったことにより不具合が発生する可能性もあります。(実装者が軽率にelseを使わなかったことによる判断ミス)

そもそも何故elseを書いてはならないのでしょうか?コードのネストが深くなるからでしょうか?少なくともelse if相当のifには、その作用はありません。あるとしたら純粋なelseブロックはインデントが減るでしょう。しかしこのインデントはあったほうが処理の関連性が掴みやすくなると思います。

elseのないifは悪か?

ここまで散々elseを書くべきと言ってきましたが、ではelseがないifは悪かと言うと、そうは思いません。例えば、以下のような早期リターンと呼ばれる記法であればそれは良いと考えています。では何を早期リターンとするかですが、個人的には例外的に処理を継続しない場合を一つの基準にしています。私もここの感覚は上手く言語化できていないのですが、恐らく何もしないときだけelseを書かないのは問題ないと考えています。

これは本質的ではない処理のせいで、いたずらにネストが増えるのを防ぐためです。関連性がある場合にelseを使うのがコードのメリハリとして目視で読んだときの認知性の向上に繋がると考えています。

export const putLog = (message: string) => {
  if (message === '') return;

  console.log(message);
}

この点については個人的に共感できる意見があったので以下の記事を紹介させて頂きます。

else句を使わないのが良いコードなの?いや、そんなはずは・・・ · DQNEO日記

記事中にある以下の部分、特殊ケースに対してガード節を使うというところで、例外ケースでのみ早期リターンをするという部分がありますが、やはりこれが一番無難だなと思いました。

条件記述の単純化 「ガード節による入れ子条件記述の置き換え」
特殊ケースに対してガード説を使う

ただ例外ケースとは何か?それは数値化でき、チーム開発で標準的に取り扱えるものなのか?と言われると、正直私もそこまでは言語化できていないので難しい部分ではあります。そもそも人間が書くコードが完全に均一になることはないと考えているので、そこまで強い思想を持って考えてはいないです。(もしChatGPTに書かせてもバラツキは出るでしょう)

私がこの記事で言いたいのは単にelseを書いてもいいのではないかということと、その場合でも早期リターンは許容しても問題ないだろうというところなので、一旦早期リターンの基準についてはここでは考えないこととします。

そうなると結局elseなしでifだけあればいいじゃないかという話に戻ってくるとは思うのですが、正直そこは常識で考えてほしいというところです。まぁ常識も人の数だけあるので難しいですし、そんな物があればこんな記事も生まれていないわけで、ソフトウェア開発は難しいですね。

投稿日:
技術::プロトコル::HTTP

バーチャルホストを利用することで1IPに対し複数のドメインを紐付けることが出来るが、hostsに書かないとアクセスが出来ないという面倒な問題が発生する。今回はこれを回避するためにhostsの記述無しでバーチャルホストにアクセスする方法を書いておく。

やり方としては単純で、HTTPリクエストのHostヘッダーにバーチャルホストのドメイン名を指定すると、そのバーチャルホストへのリクエストを投げることが出来る。

一例:curl http://127.0.0.1/ -H 'Host: example.com'

ブートドライブをクローンしてクローン元を削除したら起動しなくなったので、その時にやったことのメモ

前提条件

  • OSがWindows 11
  • Windows 10のインストールUSBがある

事前手順

  1. SSD1からSSD2へブートディスクをクローン
  2. OSをシャットダウン
  3. UEFIを起動し、SSD2を指定してブート
  4. コンピューターの管理からSSD1のボリュームを消す
    1. EFIシステムだけは消えなかったのでdiskpartを使う方法で削除した
  5. OSをシャットダウン
  6. 電源を入れる
  7. ブルースクリーンになり0xc000000eエラーが発生

解決方法

Windows 10のインストールUSBを持っていたので、これを使ってリカバリを試みた。

リカバリ用コマンドプロンプトの起動

  1. Windows 10のインストールUSBを挿入しUEFIからインストールモードで起動
  2. 言語選択画面をそのままパスする
    1. 言語選択画面をそのままパスする
  3. 「コンピューターを修復する」を選択
    1. 「コンピューターを修復する」を選択
  4. トラブルシューティング→コマンドプロンプト

ブート情報の修復

UEFI/GPTインストールしたWindowsの「ブート領域」の復旧方法を参考にやっているのだが、途中でbootrec /fixbootが「アクセスが拒否されました」と言ってコケて中断してしまったため、この作業に意味があったのかどうかよくわかっていない。

  1. diskpartを流す
  2. list volumeで今回作成したブートボリュームとEFIシステムボリュームを特定する。この場合はVolume 2と3。
    1. 今回作成したブートボリュームとEFIシステムボリュームを特定する
  3. select volume 3でEFIシステムボリュームを選択
  4. assign letter=b:でドライブレターを割り当てる。因みにこのドライブレターは再起動で消える。
  5. exit
  6. cd /d b:\EFI\WMicrosoft\bootする
  7. ren BCD BCD.bak
  8. bootrec /Rebuildbcd
  9. bootrec /fixboot
    1. 「アクセスが拒否されました」と言ってコケた

ドライブレターの修正

bootrec /fixbootがコケた時にドライブレターのせいじゃね?と思って試してみたやつ

  1. diskpartを流す
  2. Cドライブにデータドライブが入っていたので適当にドライブレターを変える
    1. select volume 0
    2. assign letter=H:
  3. Eドライブにブートドライブが入っていたのでCに変える
    1. select volume 2
    2. assign letter=C:
  4. exitで抜ける
  5. リカバリメニューに戻るので「PCの電源を切る」を選択

この後PCを通常起動したら起動するようになったので解決。起動後にHドライブはなかったので結局どれが決定打だったのかよくわかっていない。なおHドライブはEドライブ扱いになっていた。取り敢えず起動するようになったのでいっか。

この後、もう一度リカバリモードに入り、前述のブート情報の修復の手順で作成したBCD.bakを削除した。

投稿日:
ジャンル::サイト運営

気がついたら今のブログが200投稿に達していたのでその思いを書いてみます。この記事は201記事目です。

まずこのブログというか、サイトの成り立ちから書いていこうと思います。当サイトは2002-07-03 23:21に開設された、まぁまぁ運営期間の長いサイトですが紆余曲折あり当時のコンテンツはカウンターの数値くらいしか残っていません。カウンターの数値だけはずっと継承しています。

コンテンツとしては雑記や日記がメインで、取り留めもない思ったことをつらつらと書いていますが、最近は情報技術関係の記事が多めです。かつてはMMORPGの記事が多かった時代もありました。

サイト全体の系譜図としてはこんな感じで、結構URL変更やホスティングサービスの移動、サイトの統廃合なども行っています。lycolia.info以前のURLは黒歴史なので書いていませんが記録はしています。

当サイトの系譜図

というわけで、なんやかんやあり2022-06-21に現在の場所に移転してきました。移転前の記事数は120記事だったということで、移転してから80記事書いたということになります。参考までにこの集計は次のクエリで行いました。

SELECT
    COUNT(*)
FROM
    wp_posts
WHERE
    post_date < '2022-06-21'
AND post_status = 'publish'
AND post_type = 'post';

移転してきたばかりの頃は検索エンジンにインデックスされずアクセスが低迷していましたが、二年ほど経った今はだいぶ安定してきました。移転前ははてなブログを使っており、その前はWordPressを使っていて、今もWordPressなので、WordPress→はてなブログ→WordPressという感じで移転してきているのですが、ドメインの変更やURL構造の破壊的変更、リダイレクトが効かないなど様々な障害があり、サイト移転に完全に失敗しています。また、はてなブログに移転するときや、はてなブログからの移転で記事の移行が上手く行かず、結構な数な記事をロストしています。

はてなブログに移転した理由はMarkdownで執筆できるモダンな環境で、結構流行っていたからというところがあるのですが、実際に使ってみるとエディタは使いづらく、記事のタグも自分のサイト内だけを検索できる機能ではなく、何よりSEOが非常に悪く、まともに検索に引っかからないという、なんのためにやってるのかよくわからない状態だったのもあります。

あとはカスタマイズ機能がCSSとJSで魔改造する前提で、まともなセマンティクスやアクセシビリティの提供が極めて困難だったので、これがはてなブログを離れた理由でもあります。因みにはてなブログ時代はPVが多くて5/daysくらいという、サイトの歴史全体を通してみても致命的にアクセスがなかった時代でした。正直Pro契約で安くない料金を払っているのにこれはないなというので引き払いを決意し、WordPress向けのMarkdown執筆環境の構築に腐心し、今はWordPress上にそれなりの環境を作れています。

取り敢えずはてなブログから移転してきて80記事くらい書いたところでMAX 5PV/daysがAvrage 50PV/daysになったのは大分良くなったなという感じでした。はてなブログに行く前は1000PV位ありましたが、ラグマスブームの頃にヒット記事を書いてた影響なので過去を見ても仕方がないです。

過去のサイトも含めて書いてきた記事数は不明ですが、多分累計で4桁は書いてるんじゃないかなとは思います。特にROやってた時はクソほど書いてたので。最近はMMOも廃れそこまで日々熱意を持って取り組めることもないので、その時ほどは難しいですが、これからもぼちぼち書いていければなと思っています。技術記事以外の雑記とか、その辺りも増やして行って、SNSから離れて古くゆかしきインターネットに帰っていきたい思いもあります。

しかしまぁ、昔と違って常連さん的なのを作るのは難しいだろうなぁ…wなにせ特定の事柄を書かなくなってしまったのもあり、定期購読する価値が薄いサイトになってしまったというところが割とある気はしていますので…w