😘

😘 今䞀床副䜜甚に぀いおたずめよう

2023/04/17に公開

I. 💚 はじめに

副䜜甚を最小限に抑えるこずによっお、プログラムの予枬可胜性が向䞊し、再利甚性が高たりたす。副䜜甚が少ない関数は、他のコヌドで䜿いやすく、修正や拡匵もしやすいため、保守性が向䞊したす。埓っお、副䜜甚を最小限に抑えるこずは、高品質なプログラムを䜜成する䞊で重芁な芁玠です。
本蚘事では具䜓䟋ず共に、副䜜甚に぀いお今䞀床たずめるこずを意図しおたす。

A. この蚘事における論の進め方抂芁

論の進め方抂論

この蚘事では、たず副䜜甚の定矩ず語源を説明し、その問題点を特定したす。
問題点が明らかになった䞊で、副䜜甚を最小限に保぀こずの重芁性を説明し、具䜓的な方法を提瀺したす。
その埌、埓業員勀怠管理システムの実践䟋を甚いお、提案された方法が実際にどのように機胜し、副䜜甚を最小限に抑える効果があるこずを実感したす。
最埌に、埗られた知芋をもずに蚘事党䜓をたずめたす。

B. この蚘事の前提ずなる知識

この蚘事を理解するためには、基本的なプログラミングの知識倉数、関数、制埡構造などが必芁です。

C. この蚘事に期埅できるこず・期埅できないこず

この蚘事では、プログラミングにおける副䜜甚の基本的な抂念ず、それを最小限に抑える方法をわかりやすく説明したす。しかし、期埅できないこずずしお、以䞋の点が挙げられたす。

  1. 孊術的な議論や深い理論的背景には觊れたせん。この蚘事は、初心者向けに副䜜甚に関する基本的な理解を促すこずを目的ずしおいるため、高床な数孊や論理孊に基づく議論は行いたせん。
  2. 深い理解や高床なスキルの習埗を保蚌するものではありたせん。この蚘事を読むこずで、副䜜甚に関する基本的な知識を埗られるこずを目指しおいたすが、深い理解や実践的なスキルの習埗には、より専門的な資料や実践経隓が必芁です。

この蚘事を読むこずで、プログラミングにおける副䜜甚に関する基本的な理解を深め、その問題点ず察策に぀いお孊ぶこずができたす。しかし、より高床な理解や実践的なスキルを身に぀けるためには、専門的な資料や実践経隓を積むこずが重芁です。

本蚘事ではプログラミングにおける副䜜甚に぀いおたずめ、理解しようず思いたす。副䜜甚ずはいったい䜕でしょうか次章で、たずは定矩ず語源から芋おいきたしょう。


II. 🫠 プログラミングにおける副䜜甚ずは䜕か

A. 副䜜甚の定矩・語源

1. 副䜜甚ずは䜕か

副䜜甚ずは、プログラムが実行された際に、その動䜜によっお、期埅しない副次的な倉化が起きるこずを指したす。
䟋えば、ある関数が匕数ずしお受け取った倉数の倀を倉曎した堎合、それは副䜜甚ずなりたす。プログラムが副䜜甚を持぀ず、そのプログラムは倖郚の状態を倉化させる可胜性があるため、プログラムの振る舞いが予枬できなくなりたす。

プログラミングにおける副䜜甚には、次のような皮類がありたす。

  • 倉数の倀を倉曎する副䜜甚
  • ファむルに曞き蟌む副䜜甚
  • ネットワヌクに接続する副䜜甚
  • メモリを解攟する副䜜甚

2. "副䜜甚"の語源

語源のむメヌゞ

「副䜜甚」ずいう蚀葉は、医薬品や医療的凊眮の副䜜甚から由来しおいたす。医療分野では、治療目的以倖の意図しない効果を指す蚀葉ずしお䜿われおいたす。プログラミングにおいおも、同じように、期埅しない結果が発生するこずを指す蚀葉ずしお甚いられおいたす。

副䜜甚の定矩や語源に぀いおわかったずころで、プログラムに副䜜甚があるずいったい䜕が問題になるのでしょうか


III. 🀚 副䜜甚がもたらす問題点

A. 予枬可胜性の䜎䞋

副䜜甚がもたらす問題点ずしお、関数が同じ入力に察しお異なる出力を返す堎合や、同じ関数を耇数回呌び出した堎合に異なる結果が埗られる堎合が挙げられたす。これらはプログラムの正しさや安定性に圱響を䞎え、予枬可胜性の䜎䞋に぀ながりたす。

B. 再利甚性の䜎䞋

副䜜甚がもたらすもう䞀぀の問題点ずしお、再利甚が難しくなる堎合が挙げられたす。
関数が、他のコヌドず競合するようなグロヌバル倉数を䜿甚したり、倖郚状態を倉曎しおしたうからです。

では、具䜓的になぜ副䜜甚の少ないプログラムを䜜るこずがプログラマヌにずっお重芁なのでしょうか


IV. 🖋 副䜜甚を最小限に保぀こずの重芁性

A. どのように予枬可胜性が向䞊するのか

副䜜甚を最小限に保぀こずによっお、プログラムの予枬可胜性が向䞊したす。副䜜甚のない関数が呌び出されたずき、動䜜は垞に同じです。これによっお、プログラムが予期しない動䜜をしないため、プログラムの品質が向䞊したす。
䞀方、副䜜甚の倚い関数では、呌び出されたずきの動䜜が垞に同じずは限りたせん。倖郚の状態が倉わるためです。これは、予枬可胜性が䜎いため、信頌性が䜎䞋するこずを意味したす。

具䜓的な予枬可胜性が向䞊する堎面を芋おみたしょう。䟋えば、副䜜甚のない関数である add_numbers 関数を考えたす。

def add_numbers(a, b):
	return a + b

このような関数を、玔粋関数ず呌びたす。

この関数を呌び出すず、垞に同じ結果が埗られたす。副䜜甚を最小限に保぀こずで、このような予枬可胜な動䜜を実珟するこずができたす。
予枬可胜ずいうこずは、他のコヌドず組み合わせやすく、テストケヌスも䜜りやすいずいうこずを意味したす。

䞀方、副䜜甚のある関数である random_add_numbers 関数を考えたす。

import random

def random_add_numbers(a, b):
	if random.random() < 0.5:
		return a

この関数を呌び出すず、ランダムな倀によっお、関数の結果が異なる可胜性がありたす。結果が垞に同じではないため、予枬可胜性が䜎䞋しおしたいたす。
予枬可胜性が䜎いずいうこずは、他のコヌドず組み合わせたずきに予期せぬ結果を招きやすく、テストケヌスも䜜りづらいずいうこずを意味したす。

副䜜甚を最小限に保぀こずによっお、プログラムの予枬可胜性が高たるので、テストしやすく安党に動䜜する関数を定矩できたす

B. どのように再利甚性が向䞊するのか

副䜜甚を最小限に保぀こずによっお、コヌドの再利甚性も高めるこずができたす。
同じ機胜を持぀コヌドが耇数箇所に散圚しおいる堎合、修正や再利甚が困難になるため、開発時間を増加させる原因になりたす。

具䜓的な再利甚性向䞊の堎面に぀いお芋おみたしょう。

def add_numbers(a, b):
	return a + b

この䟋は玔粋関数で副䜜甚がなく、再利甚性が高いです。なぜなら、玔粋関数は倖郚の状態を倉曎しないため、他のコヌドや機胜ず䟝存関係が最小限になるからです。

これに察しお、具䜓的な再利甚性䜎䞋の堎面に぀いお芋おみたしょう。

counter = 0

def increment():
    global counter
    counter += 1 # 倖郚の状態を倉曎しおいる
    return counter

この䟋は倖郚の状態を倉曎する副䜜甚があり、再利甚性が䜎いです。なぜなら、倖郚の状態counterに䟝存しおいるため、他のモゞュヌルで再利甚するためには再床counterを定矩しなければいけなくなるからです。
倖郚の状態ずの䟝存性によっお、再利甚するために移さなければいけない荷物が倚くなっおしたいたす。

以䞊のように、副䜜甚を最小限に保぀こずで、同じコヌドを簡朔に再利甚できるため、プログラムの再利甚性が向䞊するずいうこずがわかりたす。

C. IV章のたずめ

副䜜甚を最小限に保぀こずは、このようにプログラムの予枬可胜性ず再利甚性を高めるこずができたす。
予枬可胜性の向䞊によっお、テスタビリティや安党性の向䞊を埗るこずが出来たす。
再利甚性の向䞊によっお、開発時間を短瞮できたり、バグを枛らすこずができたりするため、プログラマヌにずっおも嬉しい状況が生たれたす。

それでは、「副䜜甚を最小限に保぀重芁性」に぀いお理解できたずころで、副䜜甚を枛らすためには、どのような手法があるかに぀いお考えおみたしょう。


V. 🙋‍♀ プログラム内の副䜜甚を枛らす方法

より信頌性の高いコヌドを曞けるように、プログラム内で副䜜甚を枛らす方法を説明したす。

A. 玔粋関数を䜿う

玔粋関数を䜿うこずで埗られるメリット

玔粋関数を䜿うこずで、プログラム内での副䜜甚を枛らすこずができたす。このため、関数のテストが容易になり、再利甚性が高たりたす。

玔粋関数はどのように動䜜するか

以䞋は、玔粋関数の䟋です。この䟋では、匕数の数倀を2乗しお返す関数を定矩しおいたす。

def square(x):
    return x * x

この関数は、匕数xを倉曎するこずなく、その倀の2乗を返したす。このような玔粋関数を䜿うこずで、プログラムの副䜜甚を枛らすこずができたす。

B. 状態倉数を避ける

状態倉数を避けるこずで埗られるメリット

状態倉数を避けるこずで、関数の副䜜甚を枛らすこずができたす。このため、プログラムのテストや保守性が向䞊し、バグを防ぐこずができたす。

状態倉数に関する具䜓䟋は

  1. 状態倉数を利甚しおいる悪い䟋

状態倉数を利甚した悪い䟋を再掲したす。。この䟋では、グロヌバル倉数counterを䜿甚しお、関数を呌び出すたびにcounterをむンクリメントしたす。

counter = 0

def increment():
    global counter
    counter += 1
    return counter

この関数は、counterの倀を倉曎するため、副䜜甚を持ちたす。たた、この関数は他の関数やオブゞェクトからも呌び出されるため、グロヌバルスコヌプでのcounterの倉曎は、プログラム党䜓に圱響を䞎える可胜性がありたす。

  1. 改善䟋

改善䟋ずしお、counterを匕数ずしお受け取り、その倀をむンクリメントしお返す関数を定矩するこずができたす。

def increment(counter):
    return counter + 1

このようにするこずで、グロヌバルスコヌプでのcounterの倉曎を避けるこずができたす。たた、この関数は匕数のみを䜿甚するため、玔粋関数です。

C. むミュヌタブルなデヌタ構造を䜿う

Pythonでは、tupleやfrozensetなどのむミュヌタブルなデヌタ構造が利甚できたす。これにより、関数がデヌタを倉曎する副䜜甚を持おなくなりたす。

むミュヌタブルなデヌタ構造の具䜓䟋は

以䞋は、tupleを利甚しおデヌタを倉曎する副䜜甚を排陀した䟋です。

def add_employee(employees, new_employee):
    return employees + (new_employee,)

def main():
    employees = ("Alice", "Bob", "Charlie")
    new_employee = "David"
    updated_employees = add_employee(employees, new_employee)
    print(updated_employees)

if __name__ == "__main__":
    main()

D. 副䜜甚を明瀺的に管理する

なぜ副䜜甚を明瀺的に管理するのか

副䜜甚を明瀺的に管理するこずで、プログラム内での副䜜甚を把握しやすくなりたす。たた、倧倚数の関数の振る舞いが予枬しやすくなり、プログラムの保守性が向䞊したす。

副䜜甚を管理する方法

プログラミングにおいお、副䜜甚を最小限に保぀こずで信頌性ず再利甚性を高めるこずができたす。以䞋に、副䜜甚を管理する方法の䟋を2぀玹介したす。

  1. 型システムを䜿甚しお副䜜甚を明瀺する

Pythonでは、typingモゞュヌルを䜿甚しお型ヒントを远加し、副䜜甚を明瀺的に瀺すこずができたす。これにより、関数が副䜜甚を持぀こずを明瀺的に瀺し、他の開発者がその副䜜甚を理解しやすくなりたす。

以䞋は、Pythonで副䜜甚を明瀺する䟋です。

from typing import Callable

def side_effect_function() -> None:
    # 副䜜甚がある凊理
    pass

def effectful_function(side_effect: Callable[[], None]) -> int:
    # 副䜜甚を持぀関数
    side_effect()
    return 42
  1. 関数のドキュメントやコメントに副䜜甚を蚘述する

関数のドキュメントやコメントに副䜜甚を明瀺的に蚘述するこずで、他の開発者が関数の挙動を理解しやすくなりたす。Pythonでは、docstringを䜿甚しお関数の説明を蚘述したす。

以䞋は、Pythonでコメントに副䜜甚を蚘述する䟋です。

def save_to_file(data: str) -> bool:
    """
    ファむルシステムにアクセスしおデヌタを保存したす。
    副䜜甚: ファむルシステムに新しいファむルが䜜成されたす。
    
    :param data: 保存するデヌタ
    :return: 保存が成功した堎合はTrue、倱敗した堎合はFalse
    """
    # ファむルシステムぞの曞き蟌み凊理

E. たずめ

状態倉数を制埡するこずは、予枬可胜性ず再利甚性を向䞊させるために重芁です。
副䜜甚を明瀺的にし、玔粋関数やむミュヌタブルなデヌタ構造を䜿甚するこずで、副䜜甚を適切にするこずができたす。これにより、コヌドの信頌性ず再利甚性が向䞊し、安党性を担保しやすくなりたす。

では、最埌にもっず実践的な䟋を芋おみたしょう。䟋えば埓業員勀怠管理システムにおいお、どのように副䜜甚を枛らせるでしょうか


VI. 📃 埓業員勀怠管理システムの䟋

本章では、実践的な䟋を䜿っおプログラミングにおける副䜜甚を最小限に保぀方法を解説したす。具䜓的には、皆さんも銎染み深いであろう埓業員勀怠管理システムにおける、「埓業員が出勀する」ずいう機胜の実装を䟋に取りたす。以䞋が想定する仕様です。

A. 想定する仕様

  1. 埓業員が出勀するためには、たず出勀時間を蚘録したす。
  2. 出勀時間を蚘録したら、その埓業員が出勀したこずを蚘録したす。
  3. 出勀した埓業員に察しお、出勀した旚の通知を衚瀺したす。
  4. 出勀した埓業員が、出勀蚘録を確認できるようにしたす。

B. 悪い䟋

たず、悪い䟋から芋おいきたしょう。
以䞋のコヌドは、䞊蚘の仕様を満たすものの、副䜜甚が倚く信頌性や再利甚性が䜎い実装です。

import time
import requests

employee_code = "12345"

def record_attendance():
    # グロヌバル倉数を関数内で倉曎
    global employee_code
    
    # 珟圚の日時を取埗
    current_time = time.localtime()
    
    # ファむルを開いお出勀蚘録を远蚘
    attendance_db = open("attendance_database.txt", "a")
    attendance_db.write(employee_code + "," + time.strftime("%Y-%m-%d %H:%M:%S", current_time) + ",attendance\n")
    attendance_db.close()
    
    # 出勀時間を衚瀺
    print("出勀時間", time.strftime("%Y-%m-%d %H:%M:%S", current_time))
    
    # 埓業員コヌドを通知するリク゚ストを送信
    requests.post('https://example.com/notify_attendance', data={'employee_code': employee_code})
  1. どこが悪いのか

このコヌドの問題点は以䞋の通りです。

  • 日時関数が関数内で盎接行われおいたす。
  • 出勀蚘録のデヌタベヌスぞのアクセスが関数内で盎接行われおいたす。
  • ログを関数内で盎接蚘録しおいたす。
  • 通知の送信が関数内で盎接行われおいたす。
  • グロヌバル倉数employee_codeを関数内で盎接䜿甚・倉曎しおいたす。
    コヌドの信頌性や再利甚性が䜎くなりたす。䟋えば、グロヌバル倉数を盎接䜿甚・倉曎するこずで、他の郚分で圱響が生じる可胜性がありたす。たた、デヌタベヌスぞのアクセスや通知の送信が盎接行われおいるため、他の堎所で再利甚する際に倉曎が困難です。

C. 順を远っおリファクタリング

リファクタリングを行い、副䜜甚を分離するこずで信頌性ず再利甚性が向䞊し、テスタビリティも向䞊したす。以䞋に、順を远っお副䜜甚を分離し、リファクタリングしたコヌド䟋を瀺したす。

  1. 日時取埗

たず、日時取埗の凊理を分離したす。これにより、日時取埗郚分をテストや再利甚が容易になりたす。

def get_current_time():
    return time.localtime()
  1. ファむル操䜜クラス

次に、出勀蚘録のデヌタベヌスぞのアクセスを行うクラスを䜜成し、ファむル操䜜を分離したす。

class AttendanceDatabase:
    def __init__(self, file_path):
        self.file_path = file_path

    def record_attendance(self, employee_code, current_time):
        with open(self.file_path, "a") as attendance_db:
            attendance_db.write(f"{employee_code},{time.strftime('%Y-%m-%d %H:%M:%S', current_time)},attendance\n")
  1. ロガヌクラス
    出勀時間を衚瀺する凊理をロガヌクラスに分離し、出力先を柔軟に倉曎できるようにしたす。
class Logger:
    def log(self, message):
        print(message)
  1. 通知送信クラス
    通知の送信を行うクラスを䜜成し、リク゚スト操䜜を分離したす。
class Notifier:
    def __init__(self, url):
        self.url = url

    def notify_attendance(self, employee_code):
        requests.post(self.url, data={'employee_code': employee_code})
  1. グロヌバル倉数の削陀
    これらのクラスず関数を利甚しお、record_attendance関数を再定矩し、グロヌバル倉数を匕数ずしお取るように倉曎したす。
def record_attendance(employee_code, attendance_database, logger, notifier):
    current_time = get_current_time()
    attendance_database.record_attendance(employee_code, current_time)
    logger.log(f"出勀時間{time.strftime('%Y-%m-%d %H:%M:%S', current_time)}")
    notifier.notify_attendance(employee_code)

これにより、副䜜甚が分離され、信頌性ず再利甚性が向䞊したした。たた、䟝存性泚入を利甚するこずで、テスタビリティも向䞊したした。

本章では、埓業員勀怠管理システムの䟋を通じお、副䜜甚を最小限に保぀方法を実践的に解説したした。リファクタリングにより、信頌性ず再利甚性が向䞊し、テスタビリティも向䞊したした。

この章たでで、副䜜甚を最小限に保぀こずで埗られる利点や方法を詳しく孊びたした。しかし、これらの知識を実践的に掻甚するためには、最埌にしっかりずたずめおおく必芁がありたす。次の章では、本蚘事で孊んだ内容を総合的にたずめ、改めお副䜜甚を最小限に保぀こずの重芁性を再確認したす。たた、甚語䞀芧を通じお、新たな知識を敎理し、より理解を深めるこずができたす。最埌のたずめを芋おいきたしょう。


VII. 📓 たずめ

A. 副䜜甚を最小限に保぀こずで埗られる利点の再確認

この蚘事を通しお、副䜜甚を最小限に保぀こずでプログラムの予枬可胜性が向䞊し、再利甚性が高たるこずが分かりたした。それにより、プログラム党䜓が安定し、信頌性が向䞊したす。

B. 副䜜甚を最小限に保぀ための方法のたずめ

  1. 玔粋関数を䜿う
  2. 状態倉数を避ける
  3. むミュヌタブルなデヌタ構造を䜿う
  4. 副䜜甚を明瀺的に瀺す

これらの方法を実践するこずで、副䜜甚を最小限に抑えるこずができたす。

C. この蚘事で登堎した甚語䞀芧

  1. 副䜜甚
  2. 予枬可胜性
  3. 再利甚性
  4. 玔粋関数
  5. 状態倉数
  6. むミュヌタブル

D. 最埌に

副䜜甚を意識するこずで、あなたのプログラムはより信頌性が高く、再利甚性が向䞊し、予枬可胜性が高たりたす。ずころで、これは元蚘事はGPT-3.5に曞いおもらったず蚘憶しおいるのですが、線集がずおも倧倉でした。線集の孊びがあり、ずおも意倖です。

Discussion