اصل Persistence Ignorance به طور خلاصه بیان میکند که در تحلیل و طراحی Business Logic به موضوع ذخیرهسازی (Persistence) فکر نکنید (تا جای ممکن) یا به عبارت دیگر، ذهن خود را درگیر پیچیدگیهای ذخیره سازی نکنید. چرا باید موقع طراحی دامینمدل، به موضوعاتی مثل تریگر، روالهای ذخیره شده، نرمالسازی دیتا، کلید اصلی، کلید فرعی و ... فکر کرد؟
اصل PI در واقع منشا شده از اصل Separation of Concerns است. مساله دامین از مساله ذخیره سازی سواست. ابتدا مسله دامین را حل کنید؛ چون اصلیترین مسله همینجاست. به مسله ذخیرهسازی هم در جای خود بپردازید.
دامینهای پیچیده، به خودی خود آنقدر پیچیدگی دارند که اگر بخواهید همزمان به مساله ذخیره سازی هم فکر کنید، عملا پیچیدگیها چند برابر شده و صلبیت (Rigidity) طراحی شما بالا میرود.
الگوی Repository Pattern هم در واقع امکانی برای تحقق این اصل است. این الگو به شما کمک میکند که دامین شما درگیر مکانیسم ذخیرهسازی نشود.
High-level modules should not depend on low-level modules. Both should depend on abstractions
این اصل یعنی چه؟ مفهوم «رانندگی اتومبیل» را به عنوان یک مفهوم انتزاعی سطح بالا در نظر بگیریم. شما به عنوان یک راننده پشت فرمان هر خودرویی که بنشینید بهتر است که درگیر پیچیدگیهای غیر ضروری مانند تعداد سیلندر و مشخصات فنی و ... نشوید و برای شما نباید فرق کند که مثلا سوخت ماشین بنزین است یا ماشین الکتریکی سوار شدهاید. مفهوم «رانندگی» نباید وابسته به مفاهیمی مانند موتور و کاربراتور و ... باشد. شما میخواهید ماشین را برانید و چیزی که برای شما اهمیت دارد چیزهایی مانند فرمان، تعداد دنده و مکان کلاج و پدال است. این مفاهیم مفاهیمی «هم سطح» با مفهوم «رانندگی» هستند. به این ترتیب میتوانید تجربه رانندگی را مستقلا حفظ کنید و این مفهوم سطح بالا (رانندگی) از یک ماشین به ماشین دیگر (low-level modules) دستخوش تغییر نشود. (فرض کنید که رانندگی هر ماشینی با ماشین دیگر کاملا متفاوت بود و برای یادگیری رانندگی هر ماشین باید آموزش جداگانهای میدیدید.) چیزی که اهمیت بیشتری دارد مفهوم سطح بالای رانندگی است و چیزهایی که تغییر میکند، مفاهیم سطح پایین تری مانند مدل ماشین و موتور و ... هستند.
برای اینکه اصل DI را به معماری هم تعمیم دهیم طراحی و وابستگی لایهها را به نحوی تعریف میکنیم که مفاهیم سطح بالا (High-level modules) وابستگی به مفاهیم سطح پایینتری مانند زیرساخت، سرویسهای بیرونی، واسط کاربر، ذخیرهسازها و ... نداشته باشد. چرا؟ مانند مثالی که زدم، اگر این سطوح انتزاع را رعایت نکنیم، مفهوم «رانندگی» با مفاهیم جزییتر وابستگی پیدا میکند و «پیچیدگی» غیر قابل کنترل میشود.
1- Decomposition
2- Hierarchy
3- Abstraction
اگر
به تعریف اصل DI که در ابتدای این نوشته به آن اشاره شد توجه کنید،
میبینیم که این اصل به طور غیر مستقیم هم به Hierarchy (High/low level)
اشاره کرده، هم به Abstraction و هم به Decomposition (Not Depend…). لذا معماریهایی
که اصل DI در طراحی آنها به درستی مورد توجه قرار گرفته باشد به همین دلیل
در غلبه بر پیچیدگی موفقتر هستند که به طور ضمنی، طراحان و توسعه دهندگان را
به اقدامات سه گانهی Decomposition, Hierarchy, Abstraction سوق میدهند.
ابتدا توجه شما را به این نقل قول جلب میکنم:
مشکلی در معماری موسوم به Layered Architecture وجود داشت این بود که Domain Logic به لایه Data Source وابسته بود. یعنی تجربه رانندگی، مثلا به تعداد سیلندرهای ماشین وابسته شده بود!
معماری های موسوم به Onion و Hexagonal یا همان (Ports & Adapters) جهت این وابستگی را اصلاح کردند. یعنی هر چه مربوط به Domain نبود را در بیرون از دایره (یا شش ضلعی یا ...) قرار دادند. دامین در مرکز قرار گرفت و لایههای دیگر (لایه های Mechanism و Utility) مجاز بودند که به دامین دسترسی داشته باشند (با واسطه) ولی خود دامین نمیتواند هیچ وابستگی به لایههای خارجی (بیرون از دایره وسطی) داشته باشد.
از جمله نتایج این طراحی این است که:
۱- قواعد کسب و کار و ... به طور کامل از جزییات دیگر منفک شود. بهبود از منظر Cohesion & Coupling
۲- مدل (Domain Model) خوانا و قابل فهم شود و توسعه آن آسانتر شود.
۳- طراحی Test Friendly شود.
۴- دامین مدل از دیتا سورسها مستقل شود. به این ترتیب امکان ایجاد تنوع در دیتا سورسها فراهم میشود. (یادمان بیاید که تغییر ظرفیت باک ماشین تجربه رانندگی را مختل نمیکند)
هر چند هر دو معماری Onion و Hexagonal در این وجوه با هم مشترکند اما جناب پالرمو (مطرح کننده معماری Onion) خلاقیت به خرج دادند و دو مفهوم، به آن اضافه کردند.
1- Domain Service
2- Application Service
به دلیل اینکه این مفاهیم نزدیک و هماهنگ با پترنهای مطرح در DDD هستند این سبک معماری را DDD Friendly به نظر میرسد. (مفهوم Application Service همان مفهوم Adapters است.)
ناگفته نماند که جناب پالرمو خودشان گفتهاند که معماری ابداعی ایشان، ایده تازهای نیست و آن را حاصل تفکرات پیشروانه کسانی مانند فاولر، کانینگهام، کنت بک و فدرز میداند:
I must stress again: I am not claiming any breakthroughs in technology or technique. I have learned from other industry thought leaders like Martin Fowler, Ward Cunningham, Kent Beck, Michael Feathers and others
برای مطالعه بیشتر درباره شباهتهای مفهومی معماریهای Hexagonal و Onion مطالعه لینک زیر پیشنهاد میشود.
http://blog.ploeh.dk/2013/12/03/layers-onions-ports-adapters-its-all-the-same/
در توسعه محصولات نرمافزاری، سه تصور یا پیش فرض غلط وجود داشته و بعضا هنوز هم وجود دارد:
۱- مشتریان از نیازمندیهای خود آگاهند.
۲- توسعه دهندگان روش ساخت محصول را میدانند.
۳- در مدت توسعه چیزی تغییر نمیکند.
تجربه نشان داده که اینطور نیست و چنین فرضیاتی در اغلب موارد و به خصوص در تولید محصولات پیچیده و یا نوآورانه غلط هستند و در واقع:
۱- مشتری/ذینفع به مرور به جزییات نیازمندیهای خود پی میبرد.
۲- توسعه دهنده ها بر اساس یافته های جدیدشان میفهمند که محصول را چگونه بهتر از قبل بسازند.
۳- در حین توسعه، به چیزهای جدیدی یاد میگیریم و این یادگیریها میتواند برنامههای قبلی را به طور کامل عوض کند.
متدهای چابک هم بر مبنای همین تجربیات پایه گذاشته شدند. رویکردی که از پیش بینی (Prediction) فاصله گرفت و پذیرای تغییر و تطبیق با شرایط جدید (Adaption) شد.
بر اساس همین رویکرد جدید (چابکی) میپذیریم، طراحی های ما به مرورد «بهتر» و «پدیدار» میشوند و به تدریج به شکل مطلوب در میآیند. به تجربه ثابت شده که ایدهی طراحی «کامل» (GOD Design) ایدهای است که در عمل شکست میخورد. لذا میپذیریم که پیش بینیهای بلند مدت نکنیم و به جای آن پذیرای تغییرات باشیم. البته این تغییرات مبتنی بر یادگیری معتبر (Validated Learning) هستند. شاید این حرف بدیهی به نظر برسد اما ایده یک طراحی جامع و زودهنگام (Big Up Front Design) که بشود بر اساس آن برنامه دقیقی ارایه داد، مدتها مطرح و در متدلوژیهای سنگین وزن (Plan-Driven) معتبر بوده است.
در بیانیه چابک، اصل یازدهم گفته شده که:
The best architectures, requirements, and designs emerge from self-organizing teams.
این اصل تاکید میکند رسیدن به بهترین طراحی و معماری، تدریجی است و از دل تجربیات تیم پدیدار میشود. همینطور اصل دوم بیانیه چابک میگوید:
Welcome changing requirements, even late in development.
با این مقدمه و پذیرش «تدریجی-تکاملی» بودن طراحی و معماری، این سوال مطرح میشود که چگونه میتوانیم طراحی و معماری را کاملتر و این امکان را ایجاد کنیم که به شکل مطلوب خود در بیاید؟ چگونه میشود حتی زمانی که فعالیت توسعه تا حد زیادی پیش رفته است، از تغییرات استقبال کنیم؟ مفهوم «طراحی پدیدآ» و روشهای اجرای آن، در واقع از اصل دوم بیانیه چابک حمایت میکنند و فرصتی برای تحقق آن پدید میآورند.
برای مطالعه بیشتر میتوانید این مطلب را بخوانید:
http://www.scaledagileframework.com/agile-architecture/
همینطور خواندن کتاب Lean Architecture for Agile Software Development نوشته جیمز کاپلین، مخصوصا فصل ۵ را پیشنهاد میکنم.
خواهرزادهام مهرانا، ۷ ساله است. پر جنب و جوش است و جسور و باهوش. از آنهایی که چشم و چال برای کسی نمیگذارند. یکبار دعوتم کرد به بازی. بازی شبیه مار و پله بود. صفحهای شبیه صفحه مار و پله با تاس و مهرههایی کمی متفاوت. اما در صفحهی بازی به جای مار و پله، فلشهای قرمز و آبی کشیده بودند و در خانههای مربعی، متنهایی نوشته بودند تا جنبه آموزشی-تربیتی برای کودکان داشته باشد. از نظر من این همان بازی مار و پله بود. اما مهرانا تاکید داشت که این بازی مار و پله نیست. میگفت: «این بازی نه مار داره و نه پله! پس مار و پله نیست.» به همین دلیل هم قواعد خاص خودش را برای بازی تعریف کرده بود و مسلماً من هم چارهای نداشتم جز تن دادن به قوانین بازیای که او تعریف کرده بود.
مهرانا بازی مار و پله را به خوبی بلد بود. چیزی که برای من جالب بود، تفاوت دیدگاه من و مهرانا بود. تاکید داشت که این یک بازی دیگریست، با قواعد دیگر؛ اما من تاکید داشتم که این همان مار و پله است و قواعدش هم باید همان باشد.
اینجا بود که به یاد مفهوم Shu-Ha-Ri افتادم. خواستگاه این مفهوم هنرهای رزمی ژاپنیست. بیان این مفهوم به این شکل است که برای استاد شدن باید سه مرحله را پشت سر گذاشت. مرحله اول یادگیری اصول، مبانی و تکنیکها از استاد به صورت دقیق و مو به مو است (Shu). مرحله بعد رها شدن از آموزشهای رسمی است. در این مرحله یادگیرنده به بررسی عمیقتر تئوریها میپردازد و از سایر اساتید، فنونی یاد میگیرد و ادغام میکند.(Ha). در مرحله ی آخر (Ri)، فرد صاحبِ سبک منحصر به خودش شده است و بر اساس تجربیات و آموختههای خودش تصمیم میگیرد و اقدام میکند.
مهرانا در بازی مار و پله، به همان مرحله سوم رسیده بود. قوانین خودش را داشت و بازی را جوری عوض کرده بود که احتمال برنده شدنش بیشتر شود. اما چرا خیلی از ما هنوز در قوانین ابتدایی بازی مار و پله ماندهایم؟!