حالت تاریک
فصل ۲ — بازآرایی پایگاه داده
بهمحض اینکه طراحی را منجمد میکنید، منسوخ میشود.
— Fred Brooks
این فصل مفاهیم بنیادین پشت بازآرایی پایگاه داده را مرور میکند؛ توضیح میدهد بازآرایی چیست، چگونه در تلاشهای توسعهٔ شما جای میگیرد، و چرا اغلب انجام موفق آن دشوار است. در فصلهای بعدی، فرایند واقعی بازآرایی طرحوارهٔ پایگاه داده را با جزئیات توصیف میکنیم.
۲.۱. بازآرایی کد
در کتاب Refactoring، Martin Fowler (1999) تکنیک برنامهنویسی به نام بازآرایی را توصیف میکند؛ روشی منضبط برای بازساختاردهی کد در گامهای کوچک. بازآرایی به شما امکان میدهد کد را بهآرامی و در طول زمان تکامل دهید و رویکرد تکاملی (تکراری و افزایشی) به برنامهنویسی داشته باشید. جنبهٔ حیاتی بازآرایی این است که معناشناسی رفتاری کد را حفظ میکند. هنگام بازآرایی قابلیت جدید اضافه نمیکنید و چیزی هم حذف نمیکنید. بازآرایی صرفاً طراحی کد را بهبود میدهد — نه بیشتر و نه کمتر. مثلاً در شکل ۲.۱، بازآرایی Push Down Method را اعمال میکنیم تا عملیات calculateTotal() از Offering به زیرکلاس آن، Invoice، منتقل شود. این تغییر در ظاهر ساده است، اما ممکن است لازم باشد کدی که این عملیات را فراخوانی میکند هم تغییر کند تا با اشیای Invoice بهجای Offering کار کند. پس از این تغییرات میتوانید بگویید واقعاً کد را بازآرایی کردهاید چون دوباره مثل قبل کار میکند.
شکل ۲.۱. انتقال یک متد به زیرکلاس.
بهوضوح به روشی سیستماتیک برای بازآرایی کد نیاز دارید، از جمله ابزارها و تکنیکهای مناسب. بیشتر محیطهای توسعهٔ یکپارچه (IDE) امروز تا حدی از بازآرایی کد پشتیبانی میکنند که شروع خوبی است. با این حال، برای اینکه بازآرایی در عمل جواب دهد، باید مجموعهٔ تست رگرسیون بهروزی هم بسازید که تأیید کند کد هنوز کار میکند — اگر نتوانید با اطمینان معقول مطمئن شوید چیزی را نشکستهاید، جسارت بازآرایی کد را نخواهید داشت.
بسیاری از توسعهدهندگان چابک، و بهویژه Extreme Programmerها (XPers)، بازآرایی را یکی از شیوههای اصلی توسعه میدانند. بازآرایی بخشی از کد بهاندازهٔ افزودن یک دستور if یا حلقه رایج است. باید بیرحمانه کد را بازآرایی کنید چون وقتی روی کد منبع باکیفیت کار میکنید بیشترین بهرهوری را دارید. وقتی قابلیت جدیدی برای افزودن دارید، اولین پرسش این است: «آیا این کد بهترین طراحی ممکن برای افزودن این قابلیت است؟» اگر بله، قابلیت را اضافه کنید. اگر نه، ابتدا کد را بازآرایی کنید تا بهترین طراحی ممکن شود، سپس قابلیت را اضافه کنید. در ظاهر کار زیادی به نظر میرسد؛ اما در عمل، اگر با کد منبع باکیفیت شروع کنید و برای حفظ آن بازآرایی کنید، خواهید دید این رویکرد فوقالعاده خوب عمل میکند.
۲.۲. بازآرایی پایگاه داده
بازآرایی پایگاه داده (Ambler 2003) تغییری ساده در طرحوارهٔ پایگاه داده است که طراحی را بهبود میدهد و هم معناشناسی رفتاری و هم اطلاعاتی را حفظ میکند — به عبارت دیگر، نمیتوانید قابلیت جدید اضافه کنید یا قابلیت موجود را بشکنید، و نمیتوانید دادهٔ جدید اضافه کنید یا معنای دادهٔ موجود را تغییر دهید. از دید ما، طرحوارهٔ پایگاه داده شامل جنبههای ساختاری — مانند تعاریف جدول و view — و جنبههای عملکردی — مانند stored procedure و trigger — است. از این پس، اصطلاح بازآرایی کد را برای بازآرایی سنتی مطابق Fowler و بازآرایی پایگاه داده را برای بازآرایی طرحوارهٔ پایگاه داده به کار میبریم. فرایند بازآرایی پایگاه داده، که در فصل ۳ با جزئیات توضیح داده میشود، همان اعمال این تغییرات ساده بر طرحوارهٔ پایگاه داده است.
بازآرایی پایگاه داده از نظر مفهومی از بازآرایی کد دشوارتر است: بازآرایی کد فقط باید معناشناسی رفتاری را حفظ کند، اما بازآرایی پایگاه داده باید معناشناسی اطلاعاتی را هم حفظ کند. بدتر آنکه بازآرایی پایگاه داده میتواند بهدلیل میزان جفتشدگی (coupling) ناشی از معماری پایگاه داده — که در شکل ۲.۲ مرور شده — پیچیدهتر شود. جفتشدگی معیاری از وابستگی بین دو مورد است؛ هرچه دو چیز بیشتر به هم جفت باشند، احتمال بیشتری وجود دارد تغییر در یکی، تغییر در دیگری را بخواهد. معماری پایگاه دادهٔ تکبرنامهای سادهترین حالت است — برنامهٔ شما تنها برنامهای است که با پایگاه داده کار میکند و میتوانید هر دو را همزمان بازآرایی و مستقر کنید. چنین موقعیتهایی وجود دارند و اغلب برنامهٔ مستقل (standalone application) یا سیستم لولهای (stovepipe system) نامیده میشوند. معماری دوم بسیار پیچیدهتر است چون برنامههای بیرونی زیادی با پایگاه داده کار میکنند و برخی خارج از کنترل شما هستند. در این حالت نمیتوانید فرض کنید همهٔ برنامههای بیرونی یکجا مستقر میشوند؛ بنابراین باید دورهٔ گذار (transition period) — که دورهٔ منسوخسازی (deprecation period) هم نامیده میشود — را پشتیبانی کنید؛ دورهای که طرحوارهٔ قدیم و جدید بهصورت موازی پشتیبانی میشوند. بعداً بیشتر دربارهٔ این موضوع میگوییم.
شکل ۲.۲. دو دستهٔ معماری پایگاه داده.
اگرچه در سراسر کتاب محیط تکبرنامهای را هم بررسی میکنیم، بیشتر روی محیط چندبرنامهای تمرکز داریم؛ جایی که پایگاه داده در تولید است و برنامههای بیرونی زیادی — که کنترل کمی یا هیچ بر آنها ندارید — به آن دسترسی دارند. نگران نباشید. در فصل ۳، راهبردهای کار در چنین موقعیتی را توصیف میکنیم.
برای قرار دادن بازآرایی پایگاه داده در بافت، یک مثال سریع را مرور کنیم. چند هفته روی یک برنامهٔ بانکی کار کردهاید و چیز عجیبی در جداول Customer و Account — که در شکل ۲.۳ نشان داده شده — دیدهاید. آیا واقعاً منطقی است ستون Balance بخشی از جدول Customer باشد؟ نه؛ پس بیایید بازآرایی Move Column (صفحهٔ ۱۰۳) را برای بهبود طراحی پایگاه داده اعمال کنیم.
شکل ۲.۳. طرحوارهٔ اولیهٔ پایگاه داده برای Customer و Account.
۲.۲.۱. محیطهای پایگاه دادهٔ تکبرنامهای
با مثالی از انتقال ستون از یک جدول به جدول دیگر در محیط تکبرنامهای شروع میکنیم. این سادهترین موقعیتی است که خواهید داشت، چون کنترل کامل بر طرحوارهٔ پایگاه داده و کد منبع برنامهای که به آن دسترسی دارد دارید. پیامد این است که میتوانید همزمان طرحواره و کد برنامه را بازآرایی کنید — نیازی نیست هر دو نسخهٔ طرحوارهٔ اصلی و جدید را موازی پشتیبانی کنید چون فقط یک برنامه به پایگاه داده دسترسی دارد.
در این سناریو پیشنهاد میکنیم دو نفر بهصورت جفت (pair) کار کنند؛ یکی مهارت برنامهنویسی برنامه و دیگری مهارت توسعهٔ پایگاه داده داشته باشد، و ایدهآل این است هر دو مجموعه مهارت را داشته باشند. این جفت ابتدا تعیین میکند آیا طرحواره نیاز به بازآرایی دارد. شاید برنامهنویس دربارهٔ نیاز به تکامل طرحواره یا بهترین روش انجام آن اشتباه کرده باشد. بازآرایی ابتدا در sandbox توسعهدهنده ساخته و تست میشود. وقتی تمام شد، تغییرات به محیط یکپارچهسازی پروژه promote میشوند و سیستم دوباره ساخته، تست و در صورت نیاز تعمیر میشود.
برای اعمال بازآرایی Move Column (صفحهٔ ۱۰۳) در sandbox توسعه، جفت ابتدا همهٔ تستها را اجرا میکند تا ببیند پاس میشوند. سپس — چون رویکرد توسعهٔ رانشمحور تست (Test-Driven Development — TDD) دارند — یک تست مینویسند. تست محتمل: دسترسی به مقداری در ستون Account.Balance. پس از اجرای تستها و دیدن شکست، ستون Account.Balance را — همانطور که در شکل ۲.۴ میبینید — اضافه میکنند. دوباره تستها را اجرا میکنند و میبینند اکنون پاس میشوند. سپس تستهای موجود را بازآرایی میکنند تا تأیید کنند واریز مشتری با Account.Balance بهجای Customer.Balance درست کار میکند. میبینند این تستها شکست میخورند؛ بنابراین عملکرد واریز را طوری بازکار میکنند که با Account.Balance کار کند. تغییرات مشابهی در سایر بخشهای مجموعهٔ تست و برنامه — مانند منطق برداشت — که فعلاً با Customer.Balance کار میکند اعمال میکنند.
شکل ۲.۴. طرحوارهٔ نهایی پایگاه داده برای Customer و Account.
پس از اینکه برنامه دوباره اجرا شد، برای امنیت از دادهٔ Customer.Balance پشتیبان میگیرند و سپس داده را از Customer.Balance به ردیف مناسب Account.Balance کپی میکنند. دوباره تستها را اجرا میکنند تا تأیید کنند مهاجرت داده امن انجام شده. برای تکمیل تغییرات طرحواره، گام نهایی حذف ستون Customer.Balance و سپس اجرای دوبارهٔ همهٔ تستها و تعمیر هر چیز لازم است. وقتی تمام شد، تغییرات را — همانطور که پیشتر گفته شد — به محیط یکپارچهسازی پروژه promote میکنند.
۲.۲.۲. محیطهای پایگاه دادهٔ چندبرنامهای
این موقعیت دشوارتر است چون انتشارهای جدید برنامههای مختلف در یک سال و نیم آینده در زمانهای متفاوت مستقر میشوند. برای پیادهسازی این بازآرایی پایگاه داده، همان نوع کاری را انجام میدهید که در محیط تکبرنامهای کردید، بهجز اینکه ستون Customer.Balance را فوراً حذف نمیکنید. در عوض، هر دو ستون را در طول دورهٔ گذار حداقل ۱.۵ سال موازی اجرا میکنید تا تیمهای توسعه فرصت بهروزرسانی و استقرار مجدد همهٔ برنامهها را داشته باشند. بخشی از طرحواره در دورهٔ گذار در شکل ۲.۵ نشان داده شده. توجه کنید دو trigger، SynchronizeCustomerBalance و SynchronizeAccountBalance، در تولید در دورهٔ گذار اجرا میشوند تا دو ستون همگام بمانند.
شکل ۲.۵. طرحوارهٔ پایگاه داده در دورهٔ گذار.
چرا دورهٔ گذار اینقدر طولانی؟ چون برخی برنامهها فعلاً روی آنها کار نمیشود، در حالی که برخی چرخهٔ توسعهٔ سنتی دارند و فقط سالی یکبار یا کمتر منتشر میکنند — دورهٔ گذار باید تیمهای کند را هم مثل تیمهای سریع در نظر بگیرد. علاوه بر این، چون نمیتوانید روی بهروزرسانی هر دو ستون توسط برنامههای مختلف حساب کنید، باید مکانیزمی — مانند trigger — برای همگام نگهداشتن مقادیر فراهم کنید. گزینههای دیگری هم هست، مانند view یا همگامسازی پس از وقوع، اما همانطور که در فصل ۵ «راهبردهای بازآرایی پایگاه داده» بحث میکنیم، trigger بهترین عمل میکند.
پس از پایان دورهٔ گذار، ستون اصلی بهعلاوهٔ trigger(ها) را حذف میکنید و به طرحوارهٔ نهایی شکل ۲.۴ میرسید. این موارد را فقط پس از تست کافی برای اطمینان از امنیت بودن حذف میکنید. در این نقطه بازآرایی کامل است. در فصل ۳، پیادهسازی این مثال را با جزئیات مرور میکنیم.
۲.۲.۳. حفظ معناشناسی
هنگام بازآرایی طرحوارهٔ پایگاه داده باید هم معناشناسی اطلاعاتی و هم رفتاری را حفظ کنید — نباید چیزی اضافه یا حذف کنید. معناشناسی اطلاعاتی به معنای اطلاعات درون پایگاه داده از دید کاربران آن اطلاعات اشاره دارد. حفظ معناشناسی اطلاعاتی یعنی اگر مقادیر دادهٔ ذخیرهشده در ستونی را تغییر دهید، مشتریان آن اطلاعات نباید تحت تأثیر قرار گیرند — مثلاً اگر بازآرایی Introduce Common Format (صفحهٔ ۱۸۳) را روی ستون شماره تلفن مبتنی بر کاراکتر اعمال کنید تا دادههایی مانند (416) 555-1234 و 905.555.1212 به ترتیب به 4165551234 و 9055551212 تبدیل شوند. اگرچه قالب بهبود یافته و کد سادهتری برای کار با داده لازم است، از نظر عملی محتوای واقعی اطلاعات تغییر نکرده. توجه کنید هنوز شماره تلفن را با قالب (XXX) XXX-XXXX نمایش میدهید؛ فقط آنطور ذخیره نمیکنید.
تمرکز بر عملگرایی (practicality) هنگام بازآرایی پایگاه داده مسئلهٔ حیاتی است. Martin Fowler دربارهٔ «رفتار قابل مشاهده» (observable behavior) در بازآرایی کد صحبت میکند؛ منظورش این است که در بسیاری از بازآراییها نمیتوانید کاملاً مطمئن باشید معناشناسی بهشکل جزئی تغییر نکرده — فقط میتوانید تا جایی که ممکن است فکر کنید، تستهایی بنویسید که کافی به نظر میرسند، و آنها را اجرا کنید تا تأیید کنید معناشناسی تغییر نکرده. در تجربهٔ ما، مسئلهٔ مشابهی هنگام حفظ معناشناسی اطلاعاتی در بازآرایی طرحواره وجود دارد — تبدیل (416) 555-1234 به 4165551234 ممکن است در واقع معنای آن اطلاعات را برای برنامهای بهشکل ظریف و ناشناخته تغییر داده باشد. مثلاً شاید گزارشی وجود داشته باشد که فقط با ردیفهایی که شماره تلفن با قالب (XXX) XXX-XXXX دارند کار میکند و به آن واقعیت متکی است. اکنون گزارش اعداد را با قالب XXXXXXXXXX خروجی میدهد و خواندنش سختتر است، هرچند از نظر عملی همان اطلاعات خروجی داده میشود. وقتی مشکل کشف شود، شاید لازم باشد گزارش برای قالب جدید بهروز شود.
بهطور مشابه، دربارهٔ معناشناسی رفتاری، هدف حفظ عملکرد جعبهسیاه (black-box) است — هر کد منبعی که با بخشهای تغییریافتهٔ طرحواره کار میکند باید بازکار شود تا همان عملکرد قبلی را انجام دهد. مثلاً اگر Introduce Calculation Method (صفحهٔ ۲۴۵) را اعمال کنید، شاید بخواهید stored procedureهای موجود دیگر را بازآرایی کنید تا آن متد را فراخوانی کنند بهجای پیادهسازی مجدد همان منطق. در کل، پایگاه داده همان منطق را پیاده میکند؛ فقط منطق محاسبه اکنون در یک جا متمرکز شده.
مهم است بپذیرید بازآراییهای پایگاه داده زیرمجموعهای از تبدیلهای پایگاه داده (database transformations) هستند. یک تبدیل پایگاه داده ممکن است معناشناسی را تغییر دهد یا ندهد؛ بازآرایی پایگاه داده نمیدهد. چند تبدیل رایج را در فصل ۱۱ «تبدیلهای غیربازآرایی» توصیف میکنیم چون فهم آنها مهم است و اغلب میتوانند گامی درون یک بازآرایی باشند. مثلاً هنگام اعمال Move Column برای انتقال ستون Balance از Customer به Account، باید تبدیل Introduce Column (صفحهٔ ۱۸۰) را بهعنوان یکی از گامها اعمال میکردید.
در ظاهر Introduce Column بازآرایی کاملاً مناسبی به نظر میرسد؛ افزودن ستون خالی به جدول تا وقتی قابلیت جدید از آن استفاده نکند معناشناسی جدول را تغییر نمیدهد. با این حال، آن را تبدیل (نه بازآرایی) میدانیم چون ممکن است ناخواسته رفتار برنامه را تغییر دهد. مثلاً اگر ستون را وسط جدول اضافه کنیم، هر منطق برنامهای که دسترسی موقعیتی دارد (مثلاً کدی که به ستون ۱۷ اشاره میکند نه نام ستون) میشکند. علاوه بر این، کد COBOL متصل به جدول DB2 اگر به طرحوارهٔ جدید rebind نشود میشکند، حتی اگر ستون در انتهای جدول اضافه شود. در نهایت، عملگرایی باید راهنمای شما باشد. اگر Introduce Column را بازآرایی بنامیم، یا «Yabba Dabba Do»، آیا نحوهٔ استفادهٔ شما از آن تغییر میکند؟ امیدواریم نه.
چرا از همان ابتدا درست طراحی نکنیم؟
اغلب از متخصصان داده میشنویم راهحل واقعی این است که همهچیز از ابتدا مدل شود و دیگر نیازی به بازآرایی طرحواره نباشد. اگرچه این دیدگاه جالب است و در چند موقعیت دیدهایم جواب میدهد، تجربهٔ سه دههٔ گذشته نشان داده این رویکرد برای کل جامعهٔ IT در عمل خوب کار نمیکند. رویکرد سنتی مدلسازی داده رویکرد تکاملی روشهای مدرن مانند RUP و XP را منعکس نمیکند، و این واقعیت را هم که مشتریان کسبوکار با سرعت فزاینده قابلیت جدید و تغییر در عملکرد موجود میخواهند. روشهای قدیمی دیگر کافی نیستند.
همانطور که در فصل ۱ «توسعهٔ تکاملی پایگاه داده» بحث شد، پیشنهاد میکنیم رویکرد Agile Model-Driven Development (AMDD) را بپذیرید؛ مقداری مدلسازی سطحبالا برای شناسایی «چشمانداز» کلی سیستم، سپس model storm جزئیات بهصورت just-in-time (JIT). از مزایای مدلسازی بهره ببرید بدون هزینهٔ overmodeling، overdocumentation، و بوروکراسی نگهداشتن مصنوعات زیاد بهروز و همگام. کد برنامه و طرحوارهٔ پایگاه داده با رشد درک دامنهٔ مسئله تکامل مییابند و کیفیت را از طریق بازآرایی هر دو حفظ میکنید.
۲.۳. دستهبندی بازآراییهای پایگاه داده
شش دستهٔ مختلف بازآرایی پایگاه داده را — همانطور که در جدول ۲.۱ توصیف شده — از هم تمایز میدهیم. این استراتژی دستهبندی برای سازماندهی این کتاب و امیدواریم برای سازماندهی ابزارهای آیندهٔ بازآرایی پایگاه داده معرفی شد. استراتژی دستهبندی ما کامل نیست؛ مثلاً بازآرایی Replace Method With View (صفحهٔ ۲۶۵) میتواند هم در دستهٔ Architectural و هم Method جای بگیرد. (ما آن را در دستهٔ Architectural قرار دادهایم.)
جدول ۲.۱. دستههای بازآرایی پایگاه داده
| دستهٔ بازآرایی پایگاه داده | توضیح | مثال(ها) |
|---|---|---|
| ساختاری (فصل ۶) | تغییر در تعریف یک یا چند جدول یا view | انتقال ستون از یک جدول به جدول دیگر، یا تقسیم ستون چندمنظوره به چند ستون جداگانه — هر کدام برای یک منظور |
| کیفیت داده (فصل ۷) | تغییری که کیفیت اطلاعات درون پایگاه داده را بهبود میدهد | غیرnullable کردن ستون تا همیشه مقدار داشته باشد، یا اعمال قالب مشترک روی ستون برای یکنواختی |
| یکپارچگی ارجاعی (فصل ۸) | تغییری که تضمین میکند ردیف ارجاعشده در جدول دیگر وجود دارد و/یا ردیفی که دیگر لازم نیست بهدرستی حذف شود | افزودن trigger برای حذف آبشاری (cascading delete) بین دو موجودیت — کدی که قبلاً خارج از پایگاه داده پیاده شده بود |
| معماری (فصل ۹) | تغییری که شیوهٔ کلی تعامل برنامههای بیرونی با پایگاه داده را بهبود میدهد | جایگزینی عملیات Java موجود در کتابخانهٔ مشترک با stored procedure در پایگاه داده — stored procedure آن را برای برنامههای غیرJava در دسترس میگذارد |
| متد (فصل ۱۰) | تغییر در متد (stored procedure، stored function، یا trigger) که کیفیت آن را بهبود میدهد. بسیاری از بازآراییهای کد برای متدهای پایگاه داده هم قابل اعمالاند | تغییر نام stored procedure برای فهم آسانتر |
| تبدیل غیربازآرایی (فصل ۱۱) | تغییر در طرحوارهٔ پایگاه داده که معناشناسی آن را تغییر میدهد | افزودن ستون جدید به جدول موجود |
۲.۴. بوی بد پایگاه داده
Fowler (1997) مفهوم «بوی بد کد» (code smell) را معرفی کرد — دستهای رایج از مشکل در کد که نیاز به بازآرایی را نشان میدهد. بوهای بد رایج کد شامل دستور switch، متدهای بلند، کد تکراری، و feature envy است. بهطور مشابه، بوهای بد پایگاه داده (Ambler 2003) وجود دارند که نیاز بالقوه به بازآرایی را نشان میدهند:
ستون چندمنظوره. اگر ستونی برای چند منظور استفاده میشود، احتمالاً کد اضافی برای اطمینان از استفادهٔ «درست» دادهٔ منبع وجود دارد — اغلب با بررسی مقادیر یک یا چند ستون دیگر. مثال: ستونی که تاریخ تولد را اگر فرد مشتری باشد ذخیره میکند، یا تاریخ شروع اگر کارمند باشد. بدتر آنکه احتمالاً در قابلیتی که میتوانید پشتیبانی کنید محدودید — مثلاً چگونه تاریخ تولد یک کارمند را ذخیره میکنید؟
جدول چندمنظوره. بهطور مشابه، وقتی جدول برای ذخیرهٔ چند نوع موجودیت استفاده میشود، احتمالاً نقص طراحی وجود دارد. مثال: جدول عمومی
Customerبرای اطلاعات هم افراد و هم شرکتها. مشکل این است که ساختار داده برای افراد و شرکتها متفاوت است — افراد نام، نام میانی، و نام خانوادگی دارند؛ شرکت فقط نام حقوقی. جدول عمومیCustomerستونهایی دارد که برای برخی مشتریان NULL و برای برخی نه.دادهٔ تکراری. دادهٔ تکراری در پایگاههای دادهٔ عملیاتی (operational) مشکل جدی است چون وقتی داده در چند جا ذخیره میشود، فرصت ناسازگاری پیش میآید. مثلاً رایج است اطلاعات مشتری در جاهای مختلف سازمان ذخیره شده باشد. در واقع بسیاری از شرکتها نمیتوانند فهرست دقیقی از مشتریان واقعی خود تهیه کنند. مشکل این است که در یک جدول John Smith در 123 Main Street زندگی میکند و در جدول دیگر در 456 Elm Street — در حالی که این یک نفر است که قبلاً در 123 Main Street بود و سال گذشته نقلمکان کرده؛ متأسفانه John دو فرم تغییر آدرس — یکی برای هر برنامهای که او را میشناسد — ارسال نکرده.
جداول با ستونهای زیاد. وقتی جدول ستونهای زیادی دارد، نشان میدهد انسجام (cohesion) ندارد — سعی میکند دادهٔ چند موجودیت را ذخیره کند. شاید جدول
Customerستونهایی برای سه آدرس مختلف (ارسال، صورتحساب، فصلی) یا چند شماره تلفن (منزل، محل کار، موبایل و غیره) دارد. احتمالاً باید با افزودن جداولAddressوPhoneNumberاین ساختار را نرمال کنید.جداول با ردیفهای زیاد. جداول بزرگ نشاندهندهٔ مشکلات عملکرد است. مثلاً جستجو در جدول با میلیونها ردیف زمانبر است. شاید بخواهید جدول را عمودی با انتقال برخی ستونها به جدول دیگر، یا افقی با انتقال برخی ردیفها به جدول دیگر تقسیم کنید. هر دو استراتژی اندازهٔ جدول را کاهش میدهند و احتمالاً عملکرد را بهبود میبخشند.
ستونهای «هوشمند». ستون هوشمند ستونی است که موقعیتهای مختلف در داده نمایانگر مفاهیم مختلفاند. مثلاً اگر چهار رقم اول شناسهٔ مشتری شعبهٔ محل سکونت را نشان دهد،
client IDستون هوشمند است چون میتوانید آن را parse کنید تا اطلاعات دانهریزتری — مثلاً شناسهٔ شعبه — به دست آورید. مثال دیگر: ستون متنی برای ذخیرهٔ ساختارهای XML؛ بهوضوح میتوانید ساختار XML را برای فیلدهای کوچکتر parse کنید. ستونهای هوشمند اغلب باید در نقطهای به فیلدهای دادهٔ constituent خود بازسازماندهی شوند تا پایگاه داده بتواند آنها را بهعنوان عناصر جداگانه راحتتر مدیریت کند.ترس از تغییر. اگر از تغییر طرحوارهٔ پایگاه داده میترسید چون میترسید چیزی بشکند — مثلاً ۵۰ برنامهای که به آن دسترسی دارند — این قویترین نشانه است که باید طرحواره را بازآرایی کنید. ترس از تغییر نشانهٔ خوبی است که ریسک فنی جدی دارید که فقط با گذشت زمان بدتر میشود.
مهم است بفهمید فقط بهخاطر بوی بد بودن، لزوماً بد نیست — پنیر Limburger حتی وقتی سالم است بوی بد میدهد. اما وقتی شیر بوی بد میدهد، میدانید مشکل دارید. اگر چیزی بوی بد میدهد، نگاه کنید، فکر کنید، و اگر منطقی است بازآرایی کنید.
۲.۵. جایگاه بازآرایی پایگاه داده
فرایندهای مدرن توسعهٔ نرمافزار — از جمله Rational Unified Process (RUP)، Extreme Programming (XP)، Agile Unified Process (AUP)، Scrum، و Dynamic System Development Method (DSDM) — همگی ماهیت تکاملی دارند. Craig Larman (2004) شواهد پژوهشی و همچنین حمایت گستردهٔ رهبران فکری جامعهٔ IT از رویکردهای تکاملی را جمعبندی میکند. متأسفانه، بیشتر تکنیکهای دادهمحور ماهیت سریالی دارند و به متخصصانی که وظایف نسبتاً باریک — مانند logical data modeling یا physical data modeling — انجام میدهند، متکیاند. اینجا مشکل است — دو گروه باید با هم کار کنند، اما هر دو میخواهند به شیوهٔ متفاوت.
موضع ما این است که متخصصان داده میتوانند از پذیرش تکنیکهای تکاملی مدرن مشابه توسعهدهندگان بهره ببرند و بازآرایی پایگاه داده یکی از چند مهارت مهم مورد نیاز آنهاست. متأسفانه، جامعهٔ داده انقلاب شیء دههٔ ۱۹۹۰ را از دست داد؛ یعنی فرصت یادگیری تکنیکهای تکاملی که برنامهنویسان امروز مسلم میدانند را از دست دادند. از بسیاری جهات، جامعهٔ داده انقلاب چابک را هم از دست میدهد که توسعهٔ تکاملی را یک گام جلوتر میبرد تا بسیار مشارکتی و همکارانه شود.
بازآرایی پایگاه داده یک تکنیک پیادهسازی پایگاه داده است، همانطور که بازآرایی کد تکنیک پیادهسازی برنامه است. طرحوارهٔ پایگاه داده را بازآرایی میکنید تا افزودن به آن آسانتر شود. اغلب مییابید باید قابلیت جدیدی — مانند ستون یا stored procedure جدید — به پایگاه داده اضافه کنید، اما طراحی موجود بهترین طراحی ممکن برای پشتیبانی آسان از آن قابلیت نیست. ابتدا طرحواره را بازآرایی میکنید تا افزودن قابلیت آسانتر شود، و پس از اعمال موفق بازآرایی، قابلیت را اضافه میکنید. مزیت این رویکرد این است که بهآرامی اما مداوم کیفیت طراحی پایگاه داده را بهبود میدهید. این فرایند نهتنها پایگاه داده را آسانتر برای فهم و استفاده میکند، بلکه تکامل آن در طول زمان را هم آسانتر میسازد؛ یعنی بهرهوری کلی توسعه را بهبود میبخشد.
شکل ۲.۶ نمای سطحبالایی از فعالیتهای حیاتی توسعه در پروژهٔ مدرن با فناوریهای شیء و پایگاه دادهٔ رابطهای ارائه میدهد. توجه کنید همهٔ پیکانها دوطرفهاند — بین فعالیتها در صورت نیاز رفتوبرگشت میکنید. همچنین نقطهٔ شروع یا پایان مشخصی وجود ندارد — این بهوضوح فرایند سنتی و سریالی نیست.
شکل ۲.۶. فعالیتهای بالقوهٔ توسعه در پروژهٔ تکاملی.
بازآرایی پایگاه داده فقط بخشی از تصویر توسعهٔ تکاملی پایگاه داده است. هنوز باید رویکرد تکاملی/چابک به مدلسازی داده داشته باشید. هنوز باید طرحوارهٔ پایگاه داده را تست کنید و تحت کنترل مدیریت پیکربندی قرار دهید. و هنوز باید آن را مناسب tune کنید. این موضوعات بهتر است در کتابهای دیگر بمانند.
۲.۶. آسانتر کردن بازآرایی طرحوارهٔ پایگاه داده
هرچه جفتشدگی بیشتر باشد، بازآرایی سختتر است. این در بازآرایی کد درست است و قطعاً در بازآرایی پایگاه داده هم درست است. تجربهٔ ما این است که جفتشدگی وقتی مسائل رفتاری (مثلاً کد) را در نظر میگیرید مسئلهٔ جدی میشود — چیزی که بسیاری از کتابهای پایگاه داده ترجیح میدهند به آن نپردازند. سادهترین سناریو بهوضوح پایگاه دادهٔ تکبرنامهای است چون طرحواره فقط به خودش و برنامهٔ شما جفت است. با معماری چندبرنامهای — که در شکل ۲.۷ نشان داده شده — طرحوارهٔ پایگاه داده بالقوه به کد منبع برنامه، چارچوبهای persistence و ابزارهای Object-Relational Mapping (ORM)، پایگاههای دادهٔ دیگر (از طریق replication، استخراج/بارگذاری داده و غیره)، طرحوارههای فایل داده، کد تست، و حتی خودش جفت است.
شکل ۲.۷. پایگاههای داده بهشدت به برنامههای بیرونی جفتاند.
راه مؤثر کاهش جفتشدگی پایگاه داده، کپسولهسازی دسترسی (encapsulating access) به آن است. این کار را با دسترسی برنامههای بیرونی از طریق لایههای persistence انجام میدهید — همانطور که در شکل ۲.۸ نشان داده شده. لایهٔ persistence را میتوان به چند روش پیاده کرد — از طریق Data Access Object (DAO) که SQL لازم را پیاده میکند؛ از طریق framework؛ از طریق stored procedure؛ یا حتی Web service. همانطور که در نمودار میبینید، هرگز نمیتوانید جفتشدگی را به صفر برسانید، اما قطعاً میتوانید آن را به سطح قابل مدیریت کاهش دهید.
شکل ۲.۸. کاهش جفتشدگی از طریق کپسولهسازی دسترسی.
۲.۷. آنچه آموختید
بازآرایی کد روشی منضبط برای بازساختاردهی کد در گامهای کوچک و تکاملی برای بهبود کیفیت طراحی است. بازآرایی کد معناشناسی رفتاری را حفظ میکند؛ نه قابلیت اضافه میکند و نه حذف. بهطور مشابه، بازآرایی پایگاه داده تغییری ساده در طرحوارهٔ پایگاه داده است که طراحی را بهبود میدهد و هم معناشناسی رفتاری و هم اطلاعاتی را حفظ میکند. بازآرایی پایگاه داده یکی از تکنیکهای اصلی است که به متخصصان داده امکان رویکرد تکاملی به توسعهٔ پایگاه داده میدهد. هرچه پایگاه داده جفتشدگی بیشتری داشته باشد، بازآرایی سختتر خواهد بود.