執筆経緯
本格的にプログラミングを学ぶきっかけになった
独学で作成した下記の販売管理システムを元に
classの概念を無視するとエグいコードになるという知見を共有するために執筆します。
筆者は独学時代classの概念は完全に無視して実装しておりました
対象の読者像
・class使わなくても実装できるからとclassを無視して実装している方
・class使う意義がわからない方
・classを使わないとどうなるかホラー話を聞きたい方www
メール機能の失敗談
導入
作成した販売管理システムのメール送付機能は下記の図のように
・AM11時に起動するプログラム内に2機能(注文承諾・手配遅延)
・PM8時に起動するプログラム内に2機能(発送通知・レビュー依頼)
を実装しております。
インスタンス変数の重要性 ~恐怖の引数数~
def send_gmail_first(
billFirstName,billLastName,orderId,orderTime,payMethodName,shipMethodName,
shipRequestDate,shipRequestTime,shipLastName,shipFirstName,shipZipCode,
shipPrefecture,shipCity,shipAddress1,shipAddress2,shipPhoneNumber,title,
totalPrice,usePoint,shipCharge,totalCouponDiscount,settleAmount,total_cal,
billMailAddress,totalMallCouponDiscount,store_name,store_adress,store_zip,
store_url,store_mail
)
#==>呼び出す時を考えると
#村上 元矢さんにメールを送りたいとき
#def send_gmail_first("元矢","村上",...)が正解で
#def send_gmail_first("村上","元矢",...)は間違い
#<==めっちゃわかりにくい。。。
引数29個ありました...
問題点
メソッド使用時に引数の順番をテレコしてしまう可能性が超絶高いこと
作った本人の私が何回も順序テレコしたので、他の人が使用する場合を考えたら恐怖ですね。。。
classを使って下記のようにするのが良さそうです
class Mail
attr_accessor(:billFirstName,:billLastName,:orderId, ...)
def initialize()
@billFirstName
@billLastName
@orderId
...
end
def send_gmail_first
#使用するインスタンス全てがtrueの場合送付する
end
end
#==>呼び出す時を考えると
#村上 元矢さんにメールを送りたいとき
#mail = Mail.new
#mail.billFirstName = "元矢"
#mail.billLastName = "村上"
#mail.send_gmail_first で注文承諾メールを送付する
#-------------------------
#テレコ例
#mail.billFirstName = "村上"
#mail.billLastName = "元矢"
#<==テレコに気付きやすくなった!!!
クラス化することでコードの可読性が物凄く向上しました!
使用したclassの機能
インスタンス変数
ex) @billFirstName
initializeメソッド
def initialize()
end
アクセサメソッド
attr_accessor
ミドルネームを追加しよう♪(メンテナンス性) ~恐怖の多重修正~
繰り返しになりますが本システムは、クラスの概念を一切無視してメソッドのみで書き上げた代物です...
よって、メンテナンス性が異常に悪くなっております。
その例として全てのメール本文にミドルネームの概念を追加することを想定して解説していきます!
クラス化しないとこうなる
#原本
def send_gmail_first(
billFirstName,billLastName,orderId,orderTime,payMethodName,shipMethodName,
shipRequestDate,shipRequestTime,shipLastName,shipFirstName,shipZipCode,
shipPrefecture,shipCity,shipAddress1,shipAddress2,shipPhoneNumber,title,
totalPrice,usePoint,shipCharge,totalCouponDiscount,settleAmount,total_cal,
billMailAddress,totalMallCouponDiscount,store_name,store_adress,store_zip,
store_url,store_mail)
#修正例1(引数の可読性重視)
def send_gmail_first(
billFirstName,billLastName,BillMidleName,orderId,orderTime,payMethodName,
shipMethodName,shipRequestDate,shipRequestTime,shipLastName,shipFirstName,
shipZipCode,shipPrefecture,shipCity,shipAddress1,shipAddress2,shipPhoneNumber,
title,totalPrice,usePoint,shipCharge,totalCouponDiscount,settleAmount,total_cal,
billMailAddress,totalMallCouponDiscount,store_name,store_adress,store_zip,
store_url,store_mail)
#==>引数の順番が変わってるのでテレコが容易に発生する
#修正例2(引数の順番重視)
def send_gmail_first(
billFirstName,billLastName,orderId,orderTime,payMethodName,
shipMethodName,shipRequestDate,shipRequestTime,shipLastName,shipFirstName,
shipZipCode,shipPrefecture,shipCity,shipAddress1,shipAddress2,shipPhoneNumber,
title,totalPrice,usePoint,shipCharge,totalCouponDiscount,settleAmount,total_cal,
billMailAddress,totalMallCouponDiscount,store_name,store_adress,store_zip,
store_url,store_mail,BillMiddleName)
#==>メール本文側のメンテナンスは楽になるが、最初に姓名がきて
#==>27個離れて最後にミドルネームがくるのはホラーとしか言えない。。。
message_text = """
----------------------------------------------------------------------
このメールはお客様の注文に関する大切なメールです。
お取引が完了するまで保存してください。
----------------------------------------------------------------------
orderId: #{orderId}
#{billLastName} #{billFirstName} 様
この度はご注文頂きまして誠にありがとうございます。
下記の内容でご注文を承りましたので、ご確認をお願い致します。
..................
■□□□□□□□□□□□□□□□□□□□□■
■□□□□□□□□□□□□□□□□□□□□■
"""
#==>誤ってメソッド自体を修正例2,呼び出す時に修正例1にすると
#==>#{orderId}にbillMidleNameが入ってしまうことが容易に想像できます...
更にメール送付メソッドは2ファイル間に2メソッド = 計4メソッドあるので全て修正しなければなりません
異常なメンテナンス性の高さですね...
問題点
メンテナンスに要するリソースが超絶高いこと
クラス化するとメンテナンス性が一変する!!!
クラス化して、メール機能を1つの別ファイルに切り出して
呼び出しがわのファイルでrequireする形にすればメンテナンス性が大幅に向上しそうです
class Mail
attr_accessor(:billFirstName,:billLastName,:orderId, ...)
def initialize()
@billFirstName
@billLastName
@orderId
...
end
def send_gmail_first
end
def send_gmail_delay
end
def send_gmail_ship_Notification
end
def send_gmail_after_Notification
end
end
#==> attr_accessorとinitializeにbillMiddleNameを順不同で追加可能
message_text = """
----------------------------------------------------------------------
このメールはお客様の注文に関する大切なメールです。
お取引が完了するまで保存してください。
----------------------------------------------------------------------
orderId: #{@orderId}
#{@billLastName} #{@billFirstName} 様
この度はご注文頂きまして誠にありがとうございます。
下記の内容でご注文を承りましたので、ご確認をお願い致します。
..................
■□□□□□□□□□□□□□□□□□□□□■
■□□□□□□□□□□□□□□□□□□□□■
"""
このようにするとmail.rb1ファイルにインスタンス変数を1つ追加してメールメソッド4つを修正すれば良いのでメンテナンスしやすいですね♪
学び
classを無視するとメンテナンスできないシステムになる
終わりに
まだまだオブジェクト指向の触りしか理解してませんが、
クラス設計を無視して開発を進めるとえらいことになるという
失敗体験を共有できたら幸いです!