تولید نرم افزار با الگو

وبلاگ شخصی ابراهیم خانی

۲ مطلب با موضوع «الگوهای معماری» ثبت شده است

microkernel

در کتاب [1] الگوی microkernel، الگویی برای ایجاد سیستم نرم افزاری که قادر به سازگاری [2] با تغییرات در نیازمندی هاست تعریف شده است. به صورتی که یک بخش حداقلی به عنوان هسته [3] از سیستم جدا می شود و سایر بخش ها به عنوان افزونه [4] به سیستم اضافه خواهند شد. در این کتاب یک پیاده سازی از این الگو پیشنهاد شده است که از مولفه های زیر تشکیل شده است.

  • Internal server
  • External server
  • Adaptor
  • Client
  • Microkernel

همانطور که در تعریف الگو در پست های قبلی اشاره شد، الگوها صورتی منتزع از یک شکل محسوس هستند و به نظر می رسد آنچه در این کتاب پیشنهاد شده یکی از پیاده سازی های ممکن برای این الگو باشد. آنچه در این الگو اهمیت دارد استقلال افزونه ها از یکدیگر و قابلیت اضافه شدن افزونه های جدید به هسته سیستم بدون نیاز به نوشتن کد است. این افزونه ها می توانند به عنوان مولفه هایی که به صورت مستقل و یا مولفه هایی که به صورت متمرکز و در فرآیند [5] مربوط به هسته استقرار [6] یافته اند، پیاده سازی شوند.

یک مثال استفاده از این الگو سیستم مربوط به بورس است که کاربر شرایطی را بر اساس قیمت، حجم و سایر اطلاعات مربوط به سهام تعریف می کند. برای پیاده سازی این سیستم نیاز است که در بازه های زمانی متوالی داده های مربوط به معاملات استخراج و برقرار شرط های مختلف بر اساس این داده ها مورد ارزیابی قرار گیرد. همانطور که گفته شد شرط ها بر اساس پارامترهای آنها (قیمت، حجم، ...) به انواع مختلفی تقسیم می شوند و در طور زمان انواع جدید شرط ها به سیستم اضافه خواهد شد. الگوی microkernel برای پیاده سازی چنین سیستمی کاملا مناسب است. برای استفاده از این الگو در مثال مذکور، می توان مسئولیت دریافت اطلاعات در بازه های زمانی متوالی را به هسته سیستم سپرد و برای هر نوع شرط یک افزونه تعریف کرد.

یک پیاده سازی نوعی از این الگو در این آدرس قابل دسترسی است. در این کد به خاطر حفظ سادگی، افزونه ها در فرآیند مربوط به هسته اجرا می شوند و وظیفه جستجو و ایجاد آنها بر عهده PluginFactory است (در پوشه bin جستجو انجام می شود، بنابراین می بایست dll مربوط به افزونه ها در این پوشه کپی شود). این کار نیز برای حفظ سادگی کد انجام شده است و روش های جایگزین دیگری برای آن وجود دارد (مثلا در مرورگرها [7] با جستجو در مخزن افزونه ها، افزونه مورد نظر دانلود می شود)


public class PluginFactory
{
    private readonly PluginConfigurationSection _pluginConfigurationSection;

    public PluginFactory()
    {
        _pluginConfigurationSection = ConfigurationManager.GetSection("pluginSection") as PluginConfigurationSection;
    }

    public IEnumerable<IPlugin> GetPlugins()
    {
        var plugins = new List<IPlugin>();

        foreach (PluginElement plugin in _pluginConfigurationSection.PluginElementCollection)
        {
            var type = Type.GetType(plugin.Type);
            if (type == null)
                continue;
            var pluginInstance = Activator.CreateInstance(type) as IPlugin;
            if (pluginInstance == null)
                continue;
            plugins.Add(pluginInstance);
        }
        return plugins;
    }
}



[1] - Pattern-Oriented Software Architecture Volume 1: A System of Patterns

[2] - Adaptability

[3] - Core 

[4] - Plugin

[5] - Process

[6] - Deployed

[7] - Browser 

۰ نظر موافقین ۱ مخالفین ۰
ابراهیم خانی

event sourcing

به بیان ساده Event sourcing راهکاری برای ذخیره سازی حالت یک شی بر اساس رخداد هایی [1] است که از زمان ایجاد برای آن اتفاق افتاده است. در این صورت قادر خواهیم بود حالت هر شی در هر لحظه از زمان را با بازسازی این رخدادها، ایجاد کنیم. هر چند فواید بسیاری بر این روش مترتب است، نباید از جان مایه آن که توجه به رفتار [2] به جای حالت [3] است غافل شد.  سایر مزایای استفاده از این روش عبارتند از :

  • تغییر در سازوکار ذخیره سازی، تغییری در برنامه ایجاد نمی کند.
  • به خاطر سادگی ذخیره سازی رخدادها، کارایی بهبود می یابد.
  • عدم نیاز به لایه orm [4] برای ذخیره سازی.
  • نگهداری تاریخچه رخدادهایی که در سیستم اتفاق افتاده است.
  • سادگی تجمیع [5] با سایر زیر سیستم ها.
  • سیر در گذشته و پیش بینی آینده.
  • خطایابی سیستم که در حال کار است با تکرار رخداد هایی که منجر به خطا شده اند.

سناریوی اصلی پیاده سازی این الگوی معماری در قطعه کد زیر نشان داده شده است. با هر درخواست در لایه application service، شناسه aggregate root ای که برای پاسخ گویی به این درخواست وظیفه ای برعهده دارد مشخص می شود. سپس رخدادهایی که تا این لحظه برای این شی اتفاق افتاده است از منبع ذخیره سازی رخداد ها [6] دریافت می شود. با دریافت این رخدادها و اعمال آنها به شی مورد نظر، این شی به حالتی قبل از ورود درخواست می رسد. سپس بر اساس درخواست ورودی، متدی روی شی مورد نظر فراخوانی می شود. در پاسخ به این متد فراخوانی شده، دنباله ای از رخداد ها اتفاق می افتد که شی مورد نظر این دنباله را در اختیار دارد. در ادامه رخدادهای اتفاق افتاده در منبع ذخیره سازی رخدادها ذخیره می شود و پاسخ درخواست ورودی، ارسال می شود.


public Customer EsRoutine(Guid id, Action<Customer> action)
{
    var events = _eventStore.Get(id);

    var customer = new Customer(events);

    action(customer);

    _eventStore.Save(customer.Id, customer.Changes);

    return customer;
}


کد منبع مربوط به این پست از این آدرس قابل دریافت است.

هر چند این الگو مزایای زیادی به دنبال دارد، استفاده از آن چالش هایی به همراه دارد. اول اینکه با توجه به اینکه با هر درخواست ورودی می بایست aggregate root درگیر در این درخواست را با اعمال رخدادهایی که تا کنون اتفاق افتاده است به حالت فعلی رساند، در صورتی که تعداد این رخدادها زیاد باشد باعث ایجاد سربار بالایی برای سیستم خواهد شد. استفاده از snapshot و cache دو راه معمول برای حل این مشکل است. از طرف دیگر هر چند ذخیره سازی به صورت blob [7] و clob [8] باعث سادگی درج [9] اطلاعات می شود اما جستار [10] اطلاعات ذخیره شده با این روش ها مقرون به صرفه نیست. استفاده از الگوی cqrs [11] راه حلی شناخته شده برای این مشکل است که انشاا... در پست های آتی مورد بررسی قرار خواهد گرفت. 



[1] - Event

[2] - Behavior

[3] - State

[4] - Object Relational Mapper

[5] - Integration

[6] - Event store

[7] - Binary Large OBject

[8] - Character Large OBject

[9] - Insert

[10] - Query

[11] - Command Query Responsibility Segregation 

۰ نظر موافقین ۱ مخالفین ۰
ابراهیم خانی