😈

プログラムにおける依存ってなんだ?

に公開

10分ぐらいで読めると思います。

☕️ はじめに

プログラムでは「依存は良くない」とよく言われていますが、「プログラム」と「依存」という言葉は結びつきにくく、イメージしづらいです。

「薬物」「恋人」などであれば、「依存」と結びつきやすいと思いますが、生き物ではないパソコンやプログラムが、別の何かに「依存」するというのは想像しにくいです。

そこで今回は、
・プログラムにおける「依存」とはどういうことなのか
・どうしたら「依存」を軽減できるのか
について書いていこうと思います。

※本記事では、Typescript, Reactを例に使用しています。

📕 依存の定義

依存とは、何かに対して絶えず必要とする状態、またはその対象がなければ正常な機能や活動ができない状態を指す言葉である。

引用

一般的な例だと、薬物や恋人への依存が挙げられるかと思います。

薬物がないと動けない、恋人に甘えすぎて自分では何もできない。

これが「依存」です。

💊 プログラムにおける依存

同じように、プログラムでも「何かに対して絶えず必要とする」という状態が存在します。

端的なコードで表すと、

import { funcA }  from "YYY";

funcA();

これが「依存」しているプログラムです。

YYYが無くなったり大きく変わると、エラーとなりプログラムが動かなくなります。
このプログラムは、YYYを絶えず必要としていて、正常な機能や活動ができない状態と言えます。

つまり、YYYに依存していることになります。

依存の具体例

具体例として、dayjsを例に、依存しているコードの書き方をしてみようかと思います。

dayjsを使用したReactのコンポーネントを作ってみました。

import dayjs from "dayjs";
import "dayjs/locale/ja";
dayjs.locale("ja");

type UserProfileProps = {
  name: string;
  /** ISO文字列 or "YYYY-MM-DD" など */
  birth: string | Date;
};

export const UserProfile = ({ name, birth }: UserProfileProps) => {
  const birthText = dayjs(birth).format("YYYY年M月D日");
  const age = dayjs().diff(dayjs(birth), "year");

  return (
    <div>
      <p>名前:{name}</p>
      <p>生年月日:{birthText}{age}歳)</p>
    </div>
  );
};

このコンポーネントでは、import dayjs from "dayjs";dayjsに依存しています。

  const birthText = dayjs(birth).format("YYYY年M月D日");
  const age = dayjs().diff(dayjs(birth), "year");

dayjsが更新されたり、dayjsがなくなったりすると、このコンポーネントはエラーを出して機能しなくなります。

👿 依存の何が悪いのか

薬物や恋人への依存もそうですが、「適度」に「依存」できているのであれば悪くはありません。
悪いのは「過度な依存」です。

プログラミングも同じで、ライブラリに「依存」するのは悪くないです。

しかし、このように複数のソースでライブラリを利用している場合はどうでしょうか?

A
import { funcA } from "YYY";

funcA();
B
import { funcB } from "YYY";

funcB();
C
import { funcC } from "YYY";

funcC();

この状態で、もしYYYに変更が入ったり、使えなくなったりしたら
全てを修正する必要があります。

この3つだけと分かっていれば良いですが、他に何箇所もYYYが利用されていると
大量の修正を行う必要があり、修正漏れがないかの確認作業も発生してしまいます。

🧑‍⚕️依存を軽減するにはどうするか

上記のように、プログラムでも「過度な依存」はデメリットがあります。

では、この依存を軽減するにはどうすれば良いでしょうか?

1つの方法として、依存をまとめることです。

@libs/date.ts
import dayjs from "dayjs";
import "dayjs/locale/ja";
dayjs.locale("ja");

export const formatDate = (d: string | Date, p = "YYYY年M月D日") =>
  dayjs(d).format(p);

export const diffYears = (a: string | Date, b: string | Date) =>
  dayjs(a).diff(dayjs(b), "year");

このように、dayjsの処理を1ファイルにまとめます。

もしdayjsに変更などが入ったとしても、このファイルを編集するだけですみます。

// import dayjs from "dayjs";
// import "dayjs/locale/ja";
// dayjs.locale("ja");

import { formatDate, diffYears } from "@/libs/date";

type UserProfileProps = {
  name: string;
  /** ISO文字列 or "YYYY-MM-DD" など */
  birth: string | Date;
};

export const UserProfile = ({ name, birth }: UserProfileProps) => {
  const birthText = formatDate(birth);
  const age = diffYears(new Date(), birth);

  return (
    <div>
      <p>名前:{name}</p>
      <p>生年月日:{birthText}{age}歳)</p>
    </div>
  );
};

このように import dayjs from "dayjs"というのが無くなり
依存先が@/libs/dateに変わって、外部のライブラリではなく内部モジュールに依存することになりました。

これで外部のdayjsではなく内部モジュール@/libs/dateに依存が集約されます。dayjsに変更が入っても、直すのは@/libs/dateだけでUserProfileを触る必要はありません。

おわり

今回は、プログラミングの依存についてまとめてみました。

  • プログラミングの依存先の1つは、外部のライブラリ
  • 依存している外部ライブラリを1つのファイルにまとめることで、依存を軽減できる

調べたところ他にも色々な依存があったり、依存への対応策もあるみたいなので
また別の角度からも記事を書いてみたいと思います。

もし良ければですが、みなさんの依存へのお考えなどありましたらコメントくださると嬉しいです!

ASTRSK

Discussion