はじめに
はじめまして。エムスリーキャリアの坂口です。
薬剤師向けサービスのプロダクト開発チームに新卒エンジニアとして参画し、約5ヶ月が経ちました。
新卒入社エントリブログのラストバッターとなります。この5ヶ月で私が体験し、学んだことを踏まえ、表題に挙げた「プログラムコードの腐敗」というテーマについて、少し考察をしてみようと思います。
WARNING: Is your code rotting?
プログラムコードは腐るのでしょうか?
結論から言うと、ソフトウェアが腐る という概念は存在するようです。したがって、それを構成する命令文の集合体であるプログラムコードも、同様に「腐敗」という概念で捉えられそうです。
腐るという言葉は奥深いもので、それは単に年月が経つことによって形質が変化する過程を示す概念ではなく、人間の価値観に強く依存する もののようです。例えば、食品における腐敗は、科学的には発酵と同じ過程ですが、その判断は「食べられるかどうか」という人間の価値基準に依存します(参考:https://www.jstage.jst.go.jp/article/jbrewsocjapan/106/4/106_174/_pdf )
プログラムコードの腐敗
冒頭に挙げたソフトウェアの腐敗(Software rot) は、主に時間の経過に伴うソフトウェア品質の劣化 を指します。具体的には、ソフトウェア(やそれを構成するプログラムコード)が適切に保守されず、長く放置されることによって起きる予期せぬ動作 やパフォーマンスの低下 などが挙げられます。
この場合の「腐敗の基準」は、ユーザーの要求や期待をどの程度満たしているかというソフトウェアの品質 にあり、そしてこの品質の判断基準もまた、人間の価値観(ユーザーの要求や期待 )に依存しています。したがって、プログラムコードにおけるこれらの現象を「腐る」と表現することには、一種の妥当性が感じられます。
サンプルコード
ECサイト を例に挙げ、ビジネス要件の変化によりコードの品質が低下していく(ビジネス的な要求に対し最適解とならなくなる)様子をシミュレーションしてみます。
バージョン1.0:健全な状態(サービス開始時)
サービスは当初、商品の価格が変動することはなかった と仮定します。税金や送料を含む最終価格は、マスターデータ(products テーブル)で管理しており、注文時にはこのマスターデータから価格を参照するシンプルな設計でした。
class Order < ApplicationRecord
belongs_to :product
def calculate_total_price
self .product.price
end
end
サービス初期の少ないリソースと開発期間を考慮し、最低限の要件を満たす上記の設計は合理的と判断され、採択されます。
バージョン2.0:腐敗の始まり(ビジネス要件の複雑化)
サービスの成長に伴い、「期間限定セール」や「クーポン」などのマーケティング 施策が導入され、商品の価格が購入タイミングによって変動する ようになりました。
しかし、既存のOrderモデルは「商品価格が変動しない」ことを前提として設計されているため、これを踏襲するとなると以下のようにモデルを複雑化していく ことになります。
class Order < ApplicationRecord
belongs_to :product
belongs_to :coupon , optional : true
def calculate_total_price
price = self .product.price
if self .product.on_sale?
price *= (1 - self .product.sale_discount_rate)
end
if self .coupon.present? && self .coupon.valid?
case self .coupon.discount_type
when ' percentage '
price *= (1 - self .coupon.discount_value)
when ' fixed_amount '
price -= self .coupon.discount_value
end
end
price
end
end
この段階で、すでにバージョン1.0のコードはビジネスの実態を正確に反映しておらず 、保守性も著しく低下しています。かといって、「商品価格が変動する」ことを前提とした設計に刷新する には、このメソッドと依存関係にある全ての処理を見直す 必要があります。
このように、当初は「最適」だったコードでも、時間の経過やビジネス要件の変化によって価値を失い、有用でなくなってしまいます。
表題のソフトウェア(プログラムコード)が腐るという概念について、ひとまず掘り下げてみました。次に気になるのは、当然この疑問でしょう。
「どうやって、プログラムの腐敗を防ぐのか?」
Fighting the Hidden Rot!
Software Rot、時間経過によるソフトウェア品質の劣化要因として、記事で挙げられているものがいくつかありました。以下、一部を抜粋したものになります。
環境の変化
ソフトウェアが依存している外部環境(ハードウェア、OS、ライブラリ等)の変化 が起因となり、当初想定していた処理が解決されなくなる
使用頻度の低いコード
実行されることが少ない 、あるいは残存している不要なコード が、外部環境の変化や依存関係にある別のコードの変更を受け、予期せぬ動作やエラーの原因 となる
ソフトウェアエントロピー
新規の要求やバグ修正のためにソフトウェアが絶えず変更される ことで、システム構造が当初の設計から徐々に乖離 していき、保守性が低下する
ここで、上二つの要因と最後の要因は、少し異なる観点で分類できそうです。それは腐敗の性質が、顕在的 か潜在的 かという観点です。
「環境の変化」「使用頻度の低いコード」
これらの要因は、結果として
といった明確な問題(顕在的な腐敗) を引き起こす要因です。
これらは明確であるが故に腐敗していることに気が付きやすく、システムによる検知 や継続的な保守 などで改善が見込めそうです。
一方、上記の要因はシステムが継続的な変更により当初の設計から乖離していくことで、コードが複雑になったり、汎用性が失われたりする現象を指していました。これは結果として、
新規機能開発における認知負荷や開発コストを増加
セキュリティ上の脆弱性
などを引き起こす、慢性的な問題(潜在的 な腐敗) と考えられます。
このソフトウェアエントロピー は、明確な境界線を持たないという点でより「腐敗」としての性質に近く、
「いつから腐り始めたのか定かではないが、気がついたら腐っていた」
という状態になりがちで、システマ ティックに状態を監視することが難しい という課題を持っています。
これに立ち向かうにはどうすればいいのでしょうか?
エムスリーキャリアで学んだエンジニアの本質
エムスリーキャリアのエンジニア(「ワイガヤLT大会」の様子)
私はエムスリーキャリアでの体験で、この「潜在的 な腐敗」に立ち向かう技量 こそが、エンジニアに求められる本質的に重要なスキルの一つ だと感じました。
それは具体的には、以下のような能力を指すと考えます。
柔軟な設計力
入社後、最初に学んだのは将来的な保守性・拡張性 を見据えた設計力の重要さでした。
入社当初、私は設計・コードレビューを自チームのエンジニア全員からいただいていました。誰でもレビューができる=特定の個人に依存しないレビュー体制 は、多様な視点やアイデア をチームで共有し、柔軟な設計力を養うことに繋がっています。
見極めと実行力
潜在的 な技術的負債は文字通り見えにくいもので、それを見極め、顕在化させることができるのはエンジニアだけ であると思います。
私たちのチームでは、開発中に発見した負債を「技術的負債一覧シート」 に記録し、Gitで管理しています。これにより、負債を「コードベース上で可視化」 し、またこれをAIに参照させることでリファクタリング の実行までを効果的に推進する 取り組みを進めています。
事業理解に基づく判断力
事業目標を踏まえた適切なソリューションを計画・立案するディレクション スキル も重要です。
エムスリーキャリアでは、事業部側のMTG にも積極的に関わったり、「エンジニア起票」「つぎつく」といった、エンジニア発信のプロダクト改善施策を推進する取り組み があります。それは、コードを書くことに囚われない 、プロダクトにおけるITのスペシャ リストとしての責務 を醸成する文化であるといえます。
まとめ
本記事では「プログラムコードは腐るのか?」という問いをフックに、ソフトウェアの腐敗という技術的負債についての考察、そこから導き出されるエンジニアの本質的に重要なスキル について述べてみました。
学生から社会人となった今、私はプロのエンジニアとして新鮮なソフトウェアを提供する義務がある ことを実感し、日々業務にあたっていきたいと思っています。
たった5ヶ月ではありますが、入社前では想像もできないほど多くのことを学ばせていただいています 。それはエムスリーキャリアのエンジニア組織が、深いプロダクト理解と広い視野で物事を見るスキルを醸成する文化 となっているからだと感じています。
この文化を一緒に創っていく仲間を、私たちは常に求めています。
ご興味を持っていただけた方は、ぜひ下記の採用ページ をご覧ください!
https://career.m3career.com/midcareer/engineer