ホームページ > ウェブフロントエンド > jsチュートリアル > クリーンなコード: 関数型プログラミングによる副作用の管理

クリーンなコード: 関数型プログラミングによる副作用の管理

Mary-Kate Olsen
リリース: 2025-01-10 22:29:45
オリジナル
368 人が閲覧しました

Clean Code: Managing Side Effects with Functional Programming

副作用により、コードが予測不能になり、保守が困難になる可能性があります。関数型プログラミングがそれらを効果的に処理するのにどのように役立つかを見てみましょう。

副作用とは何ですか?

関数が入力を取得して出力を返す以外のことを行う場合、副作用が発生します。一般的な副作用には次のようなものがあります:

  • グローバル変数の変更
  • 入力パラメータの変更
  • ファイルまたはデータベースへの書き込み
  • API 呼び出しを行う
  • DOM の更新
  • コンソールへのログ記録

副作用が問題を引き起こす理由

問題のある副作用を示す例を次に示します:

let userProfile = {
  name: "Alice Johnson",
  email: "alice@example.com",
  preferences: {
    theme: "dark",
    notifications: true
  }
};

function updateUserTheme(newTheme) {
  userProfile.preferences.theme = newTheme;
}

function toggleNotifications() {
  userProfile.preferences.notifications = !userProfile.preferences.notifications;
}

// Multiple functions modifying the same global state
updateUserTheme("light");
toggleNotifications();

console.log(userProfile); // State is unpredictable
ログイン後にコピー

このコードにはいくつかの問題があります:

  1. グローバル状態を使用します
  2. 複数の関数で同じデータを変更できる
  3. 変更の追跡が困難になる
  4. テストが複雑になる

純粋な機能を備えたより良いソリューション

関数型プログラミングの原則を使用した改良版は次のとおりです。

const createUserProfile = (name, email, theme, notifications) => ({
  name,
  email,
  preferences: {
    theme,
    notifications
  }
});

const updateTheme = (profile, newTheme) => ({
  ...profile,
  preferences: {
    ...profile.preferences,
    theme: newTheme
  }
});

const toggleNotifications = (profile) => ({
  ...profile,
  preferences: {
    ...profile.preferences,
    notifications: !profile.preferences.notifications
  }
});

// Usage
const initialProfile = createUserProfile(
  "Alice Johnson",
  "alice@example.com",
  "dark",
  true
);

const updatedProfile = updateTheme(initialProfile, "light");
const finalProfile = toggleNotifications(updatedProfile);

console.log(initialProfile); // Original state unchanged
console.log(finalProfile);   // New state with updates
ログイン後にコピー

実践例: ファイル操作

関数型プログラミングを使用してファイル操作で必要な副作用を処理する方法は次のとおりです。

// Separate pure business logic from side effects
const createUserData = (user) => ({
  id: user.id,
  name: user.name,
  createdAt: new Date().toISOString()
});

const createLogEntry = (error) => ({
  message: error.message,
  timestamp: new Date().toISOString(),
  stack: error.stack
});

// Side effect handlers (kept at the edges of the application)
const writeFile = async (filename, data) => {
  const serializedData = JSON.stringify(data);
  await fs.promises.writeFile(filename, serializedData);
  return data;
};

const appendFile = async (filename, content) => {
  await fs.promises.appendFile(filename, content);
  return content;
};

// Usage with composition
const saveUser = async (user) => {
  const userData = createUserData(user);
  return writeFile('users.json', userData);
};

const logError = async (error) => {
  const logData = createLogEntry(error);
  return appendFile('error.log', JSON.stringify(logData) + '\n');
};
ログイン後にコピー

関数型プログラミングによる副作用の処理

  1. 純粋関数
   // Pure function - same input always gives same output
   const calculateTotal = (items) => 
     items.reduce((sum, item) => sum + item.price, 0);

   // Side effect wrapped in a handler function
   const processPurchase = async (items) => {
     const total = calculateTotal(items);
     await saveToDatabase(total);
     return total;
   };
ログイン後にコピー
  1. 関数構成
   const pipe = (...fns) => (x) => 
     fns.reduce((v, f) => f(v), x);

   const processUser = pipe(
     validateUser,
     normalizeData,
     saveUser
   );
ログイン後にコピー
  1. データ変換
   const transformData = (data) => {
     const addTimestamp = (item) => ({
       ...item,
       timestamp: new Date().toISOString()
     });

     const normalize = (item) => ({
       ...item,
       name: item.name.toLowerCase()
     });

     return data
       .map(addTimestamp)
       .map(normalize);
   };
ログイン後にコピー

純粋な関数のテスト

純粋関数を使用するとテストがはるかに簡単になります:

describe('User Profile Functions', () => {
  const initialProfile = createUserProfile(
    'Alice',
    'alice@example.com',
    'dark',
    true
  );

  test('updateTheme returns new profile with updated theme', () => {
    const newProfile = updateTheme(initialProfile, 'light');

    expect(newProfile).not.toBe(initialProfile);
    expect(newProfile.preferences.theme).toBe('light');
    expect(initialProfile.preferences.theme).toBe('dark');
  });

  test('toggleNotifications flips the notifications setting', () => {
    const newProfile = toggleNotifications(initialProfile);

    expect(newProfile.preferences.notifications).toBe(false);
    expect(initialProfile.preferences.notifications).toBe(true);
  });
});
ログイン後にコピー

最終的な考え

関数型プログラミングは、副作用を管理するための強力なツールを提供します。

  • コアロジックを純粋かつ予測可能に保つ
  • アプリケーションのエッジで副作用を処理します
  • コンポジションを使用して関数を組み合わせる
  • 既存の状態を変更する代わりに新しいデータを返す

これらの実践により、コードのテスト、理解、保守が容易になります。


関数コードでの副作用はどのように処理しますか?コメントであなたのアプローチを共有してください!

以上がクリーンなコード: 関数型プログラミングによる副作用の管理の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ソース:dev.to
このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
著者別の最新記事
人気のチュートリアル
詳細>
最新のダウンロード
詳細>
ウェブエフェクト
公式サイト
サイト素材
フロントエンドテンプレート