مطالب
ساخت گزارش Code coverage مربوط به تست‌ها
اگر برای پروژه‌های خود تست نویسی انجام می‌دهید، یکی از موارد مهم، Code coverage مربوط به تست‌ها می‌باشد که نشان می‌دهد چند درصد از کدهای شما تست شده، کدام قسمت از کد، تست نشده‌است و ... .
در این مطلب نحوه‌ی استفاده از ReportGenerator را برای ایجاد گزارش مربوط به Code coverage، ارائه می‌دهیم. ReportGenerator دیتاهای تولید شده‌ی توسط coverlet, OpenCover, dotCover, Visual Studio, NCover, Cobertura, JaCoCo, Clover و ... را به یک گزارش قابل درک در فرمت‌های Html, Coberura و CSV تبدیل می‌کند. در  این مطلب چند موردتست نویسی با xUnit در Asp.Net Core  را نوشته‌ام و اکنون می‌خواهیم برای تست‌های نوشته شده، Code coverage آنها را بدست آوریم.
در کد زیر، سه تست برای متد AverageUsersAge نوشته شده است:
[Fact]
public async Task AverageUsersAge_When_Repository_Return_Null_Then_Zero_Should_Be_Returned()
{
    _userRepository.Setup(a => a.GetAllUsers())
        .ReturnsAsync((List<User>)null);
    var result = await _userService.AverageUsersAge();
    result.Should().Be(0);
}
[Fact]
public async Task AverageUsersAge_When_Repository_Return_Empty_Then_Zero_Should_Be_Returned()
{
    _userRepository.Setup(a => a.GetAllUsers())
        .ReturnsAsync(new List<User>());
    var result = await _userService.AverageUsersAge();
    result.Should().Be(0);
}
[Fact]
public async Task AverageUsersAge_When_Repository_Return_List_Of_Users_Then_Average_Of_Age_Should_Be_Retunred()
{

    _userRepository.Setup(a => a.GetAllUsers())
        .ReturnsAsync(UserMockData.People);
    var result = await _userService.AverageUsersAge();
    var expected = (UserMockData.AdultUser.Age + UserMockData.ChildUser.Age + UserMockData.InfantUser.Age) / 3;
    result.Should().Be(expected);
}
اکنون اگر بخواهیم Code coverage مربوط به این تست‌ها را مشاهده کنیم، ابتدا باید پکیج coverlet.collector  را در پروژه‌ی تست نصب کنیم. سپس باید دستور زیر را برای نصب ReportGenerator اجرا کنید؛ درون powershell:
dotnet tool install -g dotnet-reportgenerator-globaltool
اکنون میتوانیم Code coverage تست‌ها را تولید کنیم و با استفاده از ReportGenerator، آن‌را به قالب HTML تبدیل کنیم. اگر به مسیر پروژه تست خود بروید و دستور زیر را وارد کنید:
dotnet test --collect:"XPlat Code Coverage"
در پروژه‌ی تست شما، یک پوشه به نام TestResults ایجاد می‌شود و همچنین یک فایل xml با عنوان coverage.cobertura ایجاد شده‌است که نتیجه‌ی Code coverage مربوط به تست‌های شما در آن قرار دارد. 
اکنون می‌توانید با استفاده از ReportGenerator گزارش تست‌های خود را از فایل ایجاد شده، تهیه کنید. برای این کار باید دستور زیر را در مسیر پروژه تست، در powershell  وارد کنید:
reportgenerator -reports:"C:\Users\Farhad\source\repos\xUnitExample\xUnitExample.Tests\TestResults\*\coverage.cobertura.xml" -targetdir:"coveragereport" -reporttypes:Html
در پارامتر reports باید مسیر فایل xml ایجاد شده مربوط به Code coverage را قرار دهید (با هر بار اجرای دستور "dotnet test --collect:"XPlat Code Coverage یک فایل xml جدید ایجاد می‌شود و ممکن است در سیستم شما مقدار GUID ایجاد شده، تفاوت داشته باشد). 
درون پوشه TestResults یک پوشه دیگر قرار دارد که نام آن پوشه، یک GUID می‎‌باشد و به همین دلیل به جای استفاده از GUID از * استفاده کرده‌ایم.
 اگر دستور بالا را اجرا کنید باید خروجی زیر را مشاهده کنید:
2021-11-18T14:05:02: Arguments
2021-11-18T14:05:02:  -reports:C:\Users\Farhad\source\repos\xUnitExample\xUnitExample.Tests\TestResults\*\coverage.cobertura.xml
2021-11-18T14:05:02:  -targetdir:coveragereport
2021-11-18T14:05:02:  -reporttypes:Html
2021-11-18T14:05:02: Writing report file 'coveragereport\index.html'
2021-11-18T14:05:02: Report generation took 0.3 seconds
اکنون اگر در مسیری که دستور بالا را اجرا کردید بروید، یک پوشه به نام coveragereport مشاهده می‌کنید که یک فایل index.html دارد و اگر آنرا در مرورگر مشاهده کنید، Code coverage مربوط به تست‌های نوشته شده را مشاهده میکنید:


در عکس ارسال شده، تست‌های نوشته شده برای تمامی لایه‌ها به صورت جدا ایجاد شده‌است.
تست مربوط به UserService:

در عکس بالا قسمت‌هایی که تست شده‌اند، با رنگ سبز مشخص می‌شود و اگر قسمتی از کد تست نشده باشد، با رنگ قرمز مشخص می‌شود. 

برای مثال در عکس زیر مشخص شده‌است که برای فایل ApplicationConfiguration هیچ تستی نوشته نشده‌است.


اگر از CICD استفاده میکنید، می‌توانید در قسمت CI پروژه، هربار دستورات بالا را اجرا کنید و Code coverage مربوط به هر Build را به صورت جداگانه در کنار فایل‌های آپلود شده داشته باشد.
نکته: برای اجرای دستورات بالا و ساخت گزارش باید ورژن SDK نصب شده بر روی سیستم شما برابر 2.2.401 یا بیشتر باشد و ورژن Microsoft.NET.Test.Sdk برابر 16.5.0 یا بیشتر باشد.

مطالب
تبدیل HTML فارسی به PDF با استفاده از افزونه‌ی XMLWorker کتابخانه‌ی iTextSharp
پیشتر مطلبی را در مورد «تبدیل HTML به PDF با استفاده از کتابخانه‌ی iTextSharp» در این سایت مطالعه کرده‌اید. این مطلب از افزونه HTMLWorker کتابخانه iTextSharp استفاده می‌کند که ... مدتی است توسط نویسندگان این مجموعه منسوخ شده اعلام گردیده و دیگر پشتیبانی نمی‌شود.
کتابخانه جایگزین آن‌را افزونه XMLWorker معرفی کرده‌اند که توانایی پردازش CSS و HTML بهتر و کاملتری را نسبت به HTMLWorker ارائه می‌دهد. این کتابخانه نیز همانند HTMLWorker پشتیبانی توکاری از متون راست به چپ و یونیکد فارسی، ندارد و نیاز است برای نمایش صحیح متون فارسی در آن، نکات خاصی را اعمال نمود که در ادامه بحث آن‌ها را مرور خواهیم کرد.

ابتدا برای دریافت آخرین نگارش‌های iTextSharp و افزونه XMLWorker آن به آدرس‌های ذیل مراجعه نمائید:

تهیه یک UnicodeFontProvider

Encoding پیش فرض قلم‌ها در XMLWorker مساوی BaseFont.CP1252 است؛ که از حروف یونیکد پشتیبانی نمی‌کند. برای رفع این نقیصه نیاز است یک منبع تامین قلم سفارشی را برای آن ایجاد نمود:
    public class UnicodeFontProvider : FontFactoryImp
    {
        static UnicodeFontProvider()
        {
            // روش صحیح تعریف فونت   
            var systemRoot = Environment.GetEnvironmentVariable("SystemRoot");
            FontFactory.Register(Path.Combine(systemRoot, "fonts\\tahoma.ttf"));
            // ثبت سایر فونت‌ها در اینجا
            //FontFactory.Register(Path.Combine(Environment.CurrentDirectory, "fonts\\irsans.ttf"));
        }

        public override Font GetFont(string fontname, string encoding, bool embedded, float size, int style, BaseColor color, bool cached)
        {
            if (string.IsNullOrWhiteSpace(fontname))
                return new Font(Font.FontFamily.UNDEFINED, size, style, color);
            return FontFactory.GetFont(fontname, BaseFont.IDENTITY_H, BaseFont.EMBEDDED, size, style, color);
        }
    }
قلم‌های مورد نیاز را در سازنده کلاس به نحوی که مشاهده می‌کنید، ثبت نمائید.
مابقی مسایل آن خودکار خواهد بود و هر زمانیکه نیاز به قلم خاصی از طرف XMLWorker وجود داشت، به متد GetFont فوق مراجعه کرده و اینبار قلمی با BaseFont.IDENTITY_H را دریافت می‌کند. IDENTITY_H در استاندارد PDF، جهت مشخص ساختن encoding قلم‌هایی با پشتیبانی از یونیکد بکار می‌رود.


تهیه منبع تصاویر

در XMLWorker اگر تصاویر با http شروع نشوند (دریافت تصاویر وب آن خودکار است)، آن تصاویر را از مسیری که توسط پیاده سازی کلاس AbstractImageProvider مشخص خواهد شد، دریافت می‌کند که نمونه‌ای از پیاده سازی آن‌را در ذیل مشاهده می‌کنید:
    public class ImageProvider : AbstractImageProvider
    {
        public override string GetImageRootPath()
        {
            var path = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
            return path + "\\"; // مهم است که این مسیر به بک اسلش ختم شود تا درست کار کند
        }
    }


نحوه تعریف یک فایل CSS خارجی

    public static class XMLWorkerUtils
    {
        /// <summary>
        /// نحوه تعریف یک فایل سی اس اس خارجی
        /// </summary>
        public static ICssFile GetCssFile(string filePath)
        {
            using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
            {
                return XMLWorkerHelper.GetCSS(stream);
            }
        }
    }
برای مسیردهی یک فایل CSS در کتابخانه XMLWorker می‌توان از کلاس فوق استفاده کرد.


تبدیل المان‌های HTML پردازش شده به یک لیست PDF ایی

تهیه مقدمات فارسی سازی و نمایش راست به چپ اطلاعات در کتابخانه XMLWorker از اینجا شروع می‌شود. در حالت پیش فرض کار آن، المان‌های HTML به صورت خودکار Parse شده و به صفحه اضافه می‌شوند. به همین دلیل دیگر فرصت اعمال خواص RTL به المان‌های پردازش شده دیگر وجود نخواهد داشت و به صورت توکار نیز این مسایل درنظر گرفته نمی‌شود. به همین دلیل نیاز است که در حین پردازش المان‌های HTML و تبدیل آن‌ها به معادل المان‌های PDF، بتوان آن‌ها را جمع آوری کرد که نحوه انجام آن‌را با پیاده سازی اینترفیس IElementHandler در ذیل مشاهده می‌کنید:
    /// <summary>
    /// معادل پی دی افی المان‌های اچ تی ام ال را جمع آوری می‌کند
    /// </summary>
    public class ElementsCollector : IElementHandler
    {
        private readonly Paragraph _paragraph;

        public ElementsCollector()
        {
            _paragraph = new Paragraph
            {
                Alignment = Element.ALIGN_LEFT  // سبب می‌شود تا در حالت راست به چپ از سمت راست صفحه شروع شود
            };
        }

        /// <summary>
        /// این پاراگراف حاوی کلیه المان‌های متن است
        /// </summary>
        public Paragraph Paragraph
        {
            get { return _paragraph; }
        }

        /// <summary>
        /// بجای اینکه خود کتابخانه اصلی کار افزودن المان‌ها را به صفحات انجام دهد
        /// قصد داریم آن‌ها را ابتدا جمع آوری کرده و سپس به صورت راست به چپ به صفحات نهایی اضافه کنیم
        /// </summary>
        /// <param name="htmlElement"></param>
        public void Add(IWritable htmlElement)
        {
            var writableElement = htmlElement as WritableElement;
            if (writableElement == null)
                return;

            foreach (var element in writableElement.Elements())
            {
                fixNestedTablesRunDirection(element);
                _paragraph.Add(element);
            }
        }

        /// <summary>
        /// نیاز است سلول‌های جداول تو در توی پی دی اف نیز راست به چپ شوند
        /// </summary>        
        private void fixNestedTablesRunDirection(IElement element)
        {
            var table = element as PdfPTable;
            if (table == null)
                return;

            table.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
            foreach (var row in table.Rows)
            {
                foreach (var cell in row.GetCells())
                {
                    cell.RunDirection = PdfWriter.RUN_DIRECTION_RTL;
                    foreach (var item in cell.CompositeElements)
                    {
                        fixNestedTablesRunDirection(item);
                    }
                }
            }
        }
    }
این کلاس کلیه المان‌های دریافتی را به یک پاراگراف اضافه می‌کند. همچنین اگر به جدولی در این بین برخورد، مباحث RTL آن‌را نیز اصلاح خواهد نمود.


یک مثال کامل از نحوه کنار هم قرار دادن پیشنیازهای تهیه شده

خوب؛ تا اینجا یک سری پیشنیاز را تهیه کردیم، اما XMLWorker از وجود آن‌ها بی‌خبر است. برای معرفی آن‌ها باید به نحو ذیل عمل کرد:
            using (var pdfDoc = new Document(PageSize.A4))
            {
                var pdfWriter = PdfWriter.GetInstance(pdfDoc, new FileStream("test.pdf", FileMode.Create));
                pdfWriter.RgbTransparencyBlending = true;
                pdfDoc.Open();


                var html = @"<span style='color:blue; font-family:tahoma;'><b>آزمایش</b></span>   
                                    کتابخانه <i>iTextSharp</i> <u>جهت بررسی فارسی نویسی</u>
                            <table style='color:blue; font-family:tahoma;' border='1'><tr><td>eeمتن</td></tr></table>
                            <code>This is a code!</code>
                            <br/>
                            <img src='av-13489.jpg' />
                            ";

                var cssResolver = new StyleAttrCSSResolver();
                // cssResolver.AddCss(XMLWorkerUtils.GetCssFile(@"c:\path\pdf.css"));
                cssResolver.AddCss(@"code 
                                     {
                                        padding: 2px 4px;
                                        color: #d14;
                                        white-space: nowrap;
                                        background-color: #f7f7f9;
                                        border: 1px solid #e1e1e8;
                                     }",
                                     "utf-8", true);

                // کار جمع آوری المان‌های ترجمه شده به المان‌های پی دی اف را انجام می‌دهد
                var elementsHandler = new ElementsCollector();

                var htmlContext = new HtmlPipelineContext(new CssAppliersImpl(new UnicodeFontProvider()));
                htmlContext.SetImageProvider(new ImageProvider());
                htmlContext.CharSet(Encoding.UTF8);
                htmlContext.SetAcceptUnknown(true).AutoBookmark(true).SetTagFactory(Tags.GetHtmlTagProcessorFactory());
                var pipeline = new CssResolverPipeline(cssResolver,
                                                       new HtmlPipeline(htmlContext, new ElementHandlerPipeline(elementsHandler, null)));
                var worker = new XMLWorker(pipeline, parseHtml: true);
                var parser = new XMLParser();
                parser.AddListener(worker);
                parser.Parse(new StringReader(html));

                // با هندلر سفارشی که تهیه کردیم تمام المان‌های اچ تی ام ال به المان‌های پی دی اف تبدیل شدند
                // الان تنها کافی کافی است تا این‌ها را در یک جدول راست به چپ محصور کنیم تا درست نمایش داده شوند
                var mainTable = new PdfPTable(1) { WidthPercentage = 100, RunDirection = PdfWriter.RUN_DIRECTION_RTL };
                var cell = new PdfPCell
                {
                    Border = 0,
                    RunDirection = PdfWriter.RUN_DIRECTION_RTL,
                    HorizontalAlignment = Element.ALIGN_LEFT
                };
                cell.AddElement(elementsHandler.Paragraph);
                mainTable.AddCell(cell);

                pdfDoc.Add(mainTable);
            }

            Process.Start("test.pdf");
نحوه تعریف inline css یا نحوه افزودن یک فایل css خارجی را نیز در ابتدای این مثال مشاهده می‌کنید.
UnicodeFontProvider باید به HtmlPipelineContext شناسانده شود.
ImageProvider توسط متد SetImageProvider به HtmlPipelineContext معرفی می‌شود.
ElementsCollector سفارشی ما در قسمت CssResolverPipeline باید به سیستم تزریق شود.
پس از آن XMLWorker را وادار می‌کنیم تا HTML را Parse کرده و معادل المان‌های PDF ایی آن‌را تهیه کند؛ اما آن‌ها را به صورت خودکار به صفحات فایل PDF نهایی اضافه نکند. در این بین ElementsCollector ما این المان‌ها را جمع آوری کرده و در نهایت، پاراگراف کلی حاصل از آن‌را به یک جدول با RUN_DIRECTION_RTL اضافه می‌کنیم. حاصل آن نمایش صحیح متون فارسی است.

کدهای مثال فوق را از آدرس ذیل نیز می‌توانید دریافت کنید:
XMLWorkerRTLsample.cs


به روز رسانی
کلیه نکات مطلب فوق را به همراه بهبودهای مطرح شده در نظرات آن، در پروژه‌ی ذیل می‌توانید به صورت یکجا دریافت و بررسی کنید:
XMLWorkerRTLsample.zip
مطالب
آموزش MDX Query - قسمت اول

در طول این سری آموزش‌های MDX (البته هنوز نمی‌دانم چند قسمت خواهد بود) تلاش خواهم کرد تمامی موارد موجود در MDX‌ها را به طور کامل با شرح و توضیح مناسب پوشش دهم.

امیدوارم شما دوستان عزیز پس از مطالعه‌ی این مجموعه مقالات به دانش کافی در خصوص MDX Query‌ها دست پیدا کنید.

در قسمت اول این آموزش‌ها در نظر دارم در ابتدا مفاهیم اولیه OLAP و همچنین مفاهیم مورد نیاز در Multi Dimentional Data Base  ها برای شما عزیزان توضیح دهم و در قسمت‌های بعدی این مجموعه در خصوص MDX Query‌ها صحبت خواهم کرد.

انباره داده (Data Warehouse)

عملا یک یا چند پایگاه داده می‌باشد که اطلاعات تجمیع شده از دیگر پایگاه‌های داده را درخود نگه داری می‌کند. برای ارایه گزارشاتی که از پایگاه داده‌های OLTP نمی‌توانیم به راحتی بگیریم.

(OLTP (Online transaction processing

سیستم پردازش تراکنش بر‌خط می‌باشند . که عملا همان سیستم هایی می‌باشند که در طول روز دارای تغییرات بسیار زیادی می‌باشند (مانند سیستم‌های حسابداری، انبار داری و ... که در طول روز دایما دارای تغییرات در سطح داده می‌باشند.)

(OLAP (OnLine Analysis Processing 

این سیستم‌ها خدماتی در نقش تحلیل‌گر داده و تصمیم گیرنده ارائه می‌‌کند. چنین سیستمهایی می‌‌توانند، داده را در قالبهای مختلف برای هماهنگ کردن نیازهای مختلف کاربران مختلف، سازماندهی کنند.

تفاوت انبار داده (Data Warehouse) و پایگاه داده(Data Base)

وظیفه اصلی سیستم‌های پایگاه‌داده کاربردی OnLine ،پشتیبانی از تراکنش‌های بر‌خط و  پردازش کوئری است. این سیستم‌ها، سیستم پردازش تراکنش بر‌خط(OLTP)  نامیده می‌شوند و بیشتر عملیات روزمره یک سازمان را پوشش می‌‌دهند. از سوی دیگر انبار‌داده، خدماتی در نقش تحلیل‌گر داده و تصمیم گیرنده ارائه می‌‌کند. چنین سیستمهایی می‌‌توانند داده را در قالبهای مختلف برای هماهنگ کردن نیازهای مختلف کاربران مختلف، سازماندهی و ارائه می‌کند. این سیستم‌ها با نام سیستم‌های پردازش تحلیلی بر‌خط (OLAP) شناخته‌می‌شوند.

موارد تفاوت انبار داده (Data Warehouse) و پایگاه داده(Data Base)

• از لحاظ مدل‌های داده: پایگاه‌های داده برای مدل  OLTP بهینه سازی شده‌است. که بر اساس مدل داده رابطه‌ای امکان پردازش تعداد زیادی تراکنش همروند، که اغلب حاوی رکورد‌های اندکی هستند را دارد. اما در انبارهای داده که برای پردازش تحلیلی بر خط، طراحی شده‌اند امکان پردازش تعداد کمی کوئری پیچیده بر روی تعداد بسیار زیادی رکورد داده فراهم می‌شود. سرورهای OLAP می‌توانند از دو نوع رابطه‌ای  (ROLAP)  یا چند‌بعدی باشند (MOLAP).
• از لحاظ کاربران: کاربران پایگاه‌داده کارمندان دفتری و مسؤولان هستند در حالی‌که کاربران انبار‌داده مدیران و تصمیم‌گیرنده‌ها هستند.
• از لحاظ عملیات قابل اجرا بر روی آن‌ها: عملیات انجام شده برروی پایگاه‌های داده عمدتا عملیات (Select/Insert/Update/Delete) می‌باشد ، در حالی که عملیات روی انبار داده عمدتا Select  ها می‌باشند.
• از لحاظ مقدار داده‌ها: مقدار داده‌های یک پایگاه‌داده در حدود چند مگابایت تا چند گیگابایت است در حالی که این مقدار در انبار داده در حدود چند گیگابایت تا چند ترابایت است.
• از لحاظ زمان پرس و جو : به طور کلی سرعت پرس و جو  ها روی انباره‌ی داده بسیار بالاتر از کوئری مشابه آن روی پایگاه داده می‌باشد.
مراحل ساخت یک انباره‌ی داده (Data WareHouse) به شرح زیر می‌باشد 



• پاکسازی داده (Data Cleansing)

پاکسازی داده‌ها عبارت است از شناسایی و حذف خطاها و ناسازگاریهای داده ای به منظور دستیابی به داده‌ها‌یی با کیفیت بالاتر.

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

وجود خطاهای نویزی، ناسازگاری در داده‌های انبار داده و ناقص بودن داده‌ها  امری طبیعی است. فیلدهای یک جدول ممکن است خالی باشند و یا دارای داده‌های خطا دار و ناسازگار باشند. برای هر کدام از این حالت‌ها  روشهایی جهت پاکسازی و اصلاح داده‌ها  ارایه می‌شود. 

در این بخش عملیات مختلفی برای پاکسازی داده‌ها  قابل انجام است:

• نادیده گرفتن تاپل‌های نادرست
• پرکردن فیلدهای نادرست به صورت دستی
• پرکردن فیلدهای نادرست با یک مقدار مشخص
• پرکردن فیلدها با توجه به نوع فیلد و داده‌ها ی موجود
• پرکردن فیلدها با نزدیکترین مقدار ممکن (مثلا میانگین فیلد تاپل‌های دیگر می‌تواند به عنوان یک مقدار مناسب در نظر گرفته شود)
• یکپارچه‌سازی (Integration)
این فاز شامل ترکیب داده‌های دریافتی از منابع اطلاعاتی مختلف، استفاده از متاداده‌ها  برای شناسایی و حذف افزونگی داده ها، تشخیص و رفع برخوردهای داده ای می‌باشد. 

یکپارچه سازی داده‌ها از سه فاز کلی تشکیل شده است:
• شناسایی فیلدهای یکسان: فیلدهای یکسان که در جدول‌ها ی مختلف دارای نامهای مختلف میباشند. 

• شناسایی افزونگی‌ها ی موجود در داده‌ها ی ورودی:  داده‌های ورودی گاهی دارای افزونگی است. مثلا بخشی از رکورد در جداول مختلف وجود دارد.

• مشخص کردن برخورد‌های داده ای: مثالی از  برخوردهای داده ای یکسان نبودن واحدهای نمایش داده ای است. مثلا فیلد وزن در یک جدول بر حسب کیلوگرم و در جدولی دیگر بر حسب گرم ذخیره شده است.


• تبدیل داده‌ها(Data Transformation)
در این فاز، داده‌های ورودی طی مراحل زیر به شکلی که مناسب عمل داده کاوی باشند، در می‌آیند:
• از بین بردن نویز داده¬ها(Smoothing)
• تجمیع داده¬ها(Aggregation)
• کلی¬سازی(Generalization)
• نرمال¬سازی(Normalization)
• افزودن فیلدهای جدید
در ادامه به شرح  هر یک می‌پردازیم:
1. از بین بردن نویزهای داده ای(Smoothing): منظور از  داده‌های نویزی، داده هایی هستند که در خارج از بازه مورد نظر قرار می‌گیرند. مثلا اگر بازه حقوقی کارمندان بین یک صد هزار تومان و یک میلیون تومان باشد، داده‌های خارج از این بازه به عنوان داده‌های نویزی شناخته شده و در این مرحله اصلاح می‌گردند. برای اصلاح داده‌های نویزی از روشهای زیر استفاده می‌شود:
• استفاده از مقادیر مجاور برای تعیین یک مقدار مناسب برای فیلدهای دارای نویز
• دسته بندی داده‌های موجود و مقداردهی فیلد دارای داده نویزی با استفاده از دسته نزدیکتر
• ترکیب روشهای فوق با ملاحظات انسانی، در این روش، اصلاح مقادیر نویزی با استفاده از یکی از روشهای فوق انجام می‌گیرد اما افرادی برای بررسی و اصلاح نیز وجود دارند
2. تجمیع داده ها(Aggregation): تجمیع داده‌ها به معنی بدست آوردن اطلاعات جدید از ترکیب داده‌های موجود می‌باشد. به عنوان مثال بدست فروش ماهانه از حساب فروش‌های روزانه.
3. کلی سازی(Generalization): کلی سازی به معنی دسته بندی داده‌های موجود براساس ماهیت و نوع آنها است. به عنوان مثال می‌توان اطلاع رده‌های سنی خاص (جوان، بزرگسال، سالخورده) را از فیلد سن استخراج کرد. 
4. نرمال سازی(Normalization): منظور از نرمال سازی، تغییر مقیاس داده‌ها است. به عنوان مثالی از نرمال سازی، می‌توان به تغییر بازه یک فیلد از مقادیر موجود به بازه 0 تا 1 اشاره کرد.

5. افزودن فیلدهای جدید: گاهی اوقات برای سهولت عمل داده کاوی می‌توان فیلدهایی به مجموعه فیلدهای موجود اضافه کرد. مثلا می‌توان فیلد میانگین حقوق کارمندان یک شعبه را به مجموعه فیلدهای موجود اضافه نمود.

• کاهش داده‌ها(Reduction)

در این مرحله، عملیات کاهش داده‌ها انجام می‌گیرد که شامل تکنیکهایی برای نمایش کمینه اطلاعات موجود است

. این فاز از سه بخش  تشکیل می‌شود:

• کاهش دامنه و بعد: فیلدهای نامربوط، نامناسب و تکراری حذف می‌شوند. برای تشخیص فیلدهای اضافی، روشهای آماری و تجربی وجود دارند ؛ یعنی  با اعمال الگوریتمهای آماری و یا تجربی بر روی داده‌های موجود در یک بازه زمانی مشخص، به این نتیجه می‌رسیم که فیلد یا فیلدهای خاصی کاربردی در انباره داده ای و داده کاوی نداشته و آنها را حذف می‌کنیم. 

• فشرده سازی داده ها: از تکنیکهای فشرده سازی برای کاهش اندازه داده‌ها استفاده می‌شود.
• کدکردن داده ها: داده‌ها در صورت امکان با پارامترها و اطلاعات کوچکتر جایگزین می‌شوند.

مدل داده‌ای رابطه‌ای (Relational) وچند بعدی (Multidimensional)  :

1. مدل داده رابطه‌ای (Relational data modeling)  بر اساس دو مفهوم اساسی موجودیت (entity)  و رابطه (relation) بنا نهاده شده است. از این رو آن را با نام مدل ER نیز می‌شناسند.

• موجودیت (entity) : نمایانگر همه چیزهایی که در پایگاه داده وجود خارجی دارند یا به تصور در می‌آیند. پدیده‌ها دارای مشخصاتی هستندکه به آن‌ها صفت (attribute) گفته می‌شود.

• رابطه (relation) : پدیده‌ها را به هم می‌پیوندد و چگونگی در ارتباط قرار گرفتن آن‌ها با یکدیگر را مشخص می‌کند.

2. مدل داده چند‌بعدی ( Multidimensional modeling ) یا MD بر پایه دو ساختار جدولی اصلی بنا نهاده شده است: 



• جدول حقایق (Fact Table)

• جداول ابعاد (Dimension Table)


این ساختار امکان داشتن یک نگرش مدیریتی و تصمیم‌گیری به داده‌های موجود در پایگاه داده را تسهیل می‌کند. 

جدول حقایق : قلب حجم داده‌ای ما را تشکیل می‌دهد و شامل دو سری فیلد است : کلیدهای خارجی به ابعاد و شاخص‌ها (Measure). 

شاخص‌ها (Measure) : معیارهایی هستند که بر روی آن‌ها تحلیل انجام می‌گیرد و درون جدول حقایق قرار دارند. شاخص‌ها قبل از شکل‌گیری انبار داده توسط مدیران و تحلیل‌گران به دقت مشخص می‌‌شوند. چون در مرحله کار با انبار اطلاعات اساسی هر تحلیل بر اساس همین شاخص‌ها شکل می‌گیرد. شاخص‌‌ها تقریباً همیشه مقادیر عددی را شامل می‌شوند. مثلا برای یک فروشگاه زنجیره‌ای این شاخص‌ها می‌توانند واحدهای فروخته‌شده کالاها و مبلغ فروش به تومان باشند.

بعد (Dimension) : هر موجودیت در این مدل می‌تواند با یک بعد تعریف شود. ولی بعدها با موجودیت‌های مدل ER متفاوتند زیرا آن‌ها سازمان شاخص‌ها را تعیین می‌کنند. علاوه بر این دارای یک ساختار سلسله مراتبی هستند و به طور کلی برای حمایت از سیستم‌های تصمیم گیری سازمان‌دهی شده‌اند.

اجزای بعدها member نام دارند و تقریباٌ همه بعدها، memberهای خود را در یک یا چند سطح سلسله مراتبی (hierarchies) سازمان‌دهی می‌نمایند، که این سلسله مراتب نمایانگر مسیر تجمیع (integration) و ارتباط بین سطوح پایین‌تر (مثل روز) و سطوح بالاتر (مثل ماه و سال) است. وقتی یک دسته از memberهای خاص با هم مفهوم جدیدی را ایجاد می‌‌کنند، به آنها یک سطح (Level) می‌گوییم. ( مثلاٌ هر سی روز را ماه می‌‌گوییم. در این حالت ماه یک سطح است. ) 

حجم‌های داده‌ای (Data Cube)

حجم‌های داده‌ای یا Cube از ارتباط تعدادی بعد با تعدادی شاخص تعریف می‌‌شود. ترکیب memberهای هر بعد از حجم داده‌ای فضای منطقی را تعریف می‌کند که در آن مقادیر شاخص‌ها  ظاهر می‌‌شوند. هر بخش مجزا که شامل یکی از memberهای بعد در حجم داده‌ای است ، سلول (cell) نامیده‌می‌شود. سلول‌ها شاخص‌های مربوط به تجمیع‌های مختلف را در خود نگهداری می‌نمایند. در واقع مقادیر مربوط به حقایق (Fact) که در جدول حقایق (Fact) تعریف می‌شوند در حجم داده‌ای (Data Cube) در سلول‌ها (Cell) نمایان می‌گردند.

     

شماهای داده‌ای (Data Schema)  : سه نوع Schema در طراحی Data Warehouse وجود دارد 

1. Stare
2. Snowflake
3. Galaxy
1. شمای ستاره‌ای (Star Schema) : متداولترین شما، همین شمای‌ستاره‌ای است. که در آن انبار‌داده با استفاده از اجزای زیر تعریف می‌شود:
• یک جدول مرکزی بزرگ به نام جدول حقایق که شامل حجم زیادی از داده‌های بدون تکرار است.

• مجموعه‌ای از جدول‌های کمکی کوچک‌تر به نام‏ جدول بعد ، که به ازای هر بعد یکی از این جداول موجود خواهد بود.

• شکل این شما به صورت یک ستاره است که جدول حقایق در مرکز آن قرار گرفته و هر یک از ‏ جداول بعد‏ به وسیله شعاع‌هایی به آن مربوط هستند.

مشکل این مدل احتمال پیشامد افزونگی در آن است.

2. شمای دانه‌برفی ( Snowflake Schema ) : در واقع شمای دانه‌برفی، نوعی از شمای ستاره‌ای است که در آن بعضی از ‏ جداول بعد نرمال شده‌اند. و به همین خاطر دارای تقسیمات بیشتری به شکل جداول اضافی می‌باشد که از ‏ جداول بعد‏ جدا شده‌اند. 

تفاوت این دو شما در این است که جداول شمای دانه برف نرمال هستند و افزونگی در آن‌ها  کاهش یافته است. که این برای کار کردن با داده‌ها و از لحاظ فضای ذخیره‌سازی مفید است. ولی در عوض کارایی را پایین می‌آورد، زیرا در محاسبه کوئری‌ها به joinهای بیشتری نیاز داریم. 

3. شمای کهکشانی (galaxy schema) : در کاربرد‌های پیچیده برای به اشتراک گذاشتن ابعاد نیاز به جداول حقایق چندگانه احساس می‌شود که یک یا چند ‏ جدول بعد‏ را در بین خود به اشتراک می‌گذارند. این نوع شما به صورت مجموعه‌ای از شماهای ستاره‌ای است و به همین دلیل شمای کهکشان یا شمای منظومه‌ای نامیده‌می‌شود. این شما به ما این امکان را می‌دهد که جداول بعد بین جداول حقایق مختلف به اشتراک گذاشته شوند.

عملیات بر روی حجم‌های داده‌ای :

• Roll Up  (یا Drill-up) : با بالا رفتن در ساختار سلسله مراتبی مفهومی یک حجم داده‌ای، یا با کاهش دادن بعد، یک مجموعه با جزئیات کمتر (خلاصه شده) ایجاد می‌نماید. بالا رفتن در ساختار سلسله مراتبی به معنای حذف قسمتی از جزئیات است. برای مثال اگر قبلاٌ بعد مکان بر حسب شهر بوده آن را با بالا رفتن در ساختار سلسله مراتبی بر حسب کشور درمی‌آوریم. ولی وقتی با کاهش دادن بعد سروکار داریم منظور حذف یکی از ابعاد و جایگزین کردن مقادیر کل است. در واقع همان عمل تجمیع (aggregation) است. 
• Drill Down : بر عکس عملRoll-up است و از موقعیتی با جزئیات داده‌ای کم به جزئیات زیاد می‌رود. این کار با پایین آمدن در ساختار سلسله مراتبی( به سمت جزئیات بیشتر) یا با ایجاد ابعاد اضافی انجام می‌گیرد.

نمونه‌ای از عملیات Drill Down و Roll Up

• Slice : با انتخاب و اعمال شرط بر روی یکی از ابعاد یک subcube به شکل یک برش دو بعدی ایجاد می‌کند. در واقع همان عمل انتخاب (select) است.

• Dice : با انتخاب قسمتی از ساختار سلسله مراتبی بر روی دو یا چند بعد یک subcube ایجاد می‌نماید.

نمونه‌ای از عملیات Dice و Slice

• Pivot (یا Rotate) : این عملیات بردارهای بعد را در ظاهر می‌چرخاند.

نمونه‌ای از عملیات pivot

• Drill-across : نتیجه اجرای کوئری‌هایی که نتیجه اجرای آنها حجم‌های داده‌ایهای مرکب با بیش از یک fact-table است.

• Ranking : سلول‌هایی را باز می‌گرداند که در بالا یا پایین شرط خاصی واقع هستند. مثلاٌ ده محصولی که بهترین فروش را داشته‌اند.

سرورهای OLAP :

در تکنولوژیOALP داده‌ها به دو صورت چند‌بعدی (Multidimensional OLAP) (MOLAP) و رابطه‌ای (Relational OLAP) (ROLAP) ذخیره می‌شوند. OLAP پیوندی(HOLAP) تکنولوژیی است که دو نوع قبل را با هم ترکیب می‌کند.

MOLAP : روشی است که معمولاٌ برای تحلیل‌های OLAP در تجارت مورد استفاده قرار می‌گیرد. در MOLAP، داده‌ها با ساختار یک حجم داده‌ای ( Data Cube ) چند بعدی ذخیره می‌شوند. ذخیره‌سازی در پایگاه‌داده‌های رابطه‌ای انجام نمی‌گیرد، بلکه با یک فرمت خاص انجام می‌شود. اغلب محصولات موفق MOLAP از یک روش چند‌بعدی استفاده می‌نمایند که در آن یک سری حجم‌های داده‌ای کوچک، انبوه و از پیش محاسبه‌شده، یک حجم داده‌ای بزرگ (hypercube  ) را می‌سازند. 

علاوه بر‌این MOLAP به شما امکان می‌دهد داده‌های دیدهای (View) تحلیل‌گران را دسته بندی کنید، که این در حذف اشتباهات و برخورد با ترجمه‌های پرغلط کمک بزرگی است.

گذشته از همه این‌ها از آن‌جا که داده‌ها به طور فیزیکی در حجم‌های داده‌ای بزرگ چند‌بعدی ذخیره می‌شوند، سرعت انجام فعالیت‌ها بسیار زیاد خواهد بود.

از آنجا که یک کپی از داده‌های منبع در کامپیوتر Analysis server ذخیره‌می‌شود، کوئری‌‌ها می‌توانند بدون مراجعه به منابع مجدداً محاسبه شوند. کامپیوتر Analysis server ممکن است کامپیوترسرور که تقسیم بندی‌ها در آن انجام شده یا کامپیوتر دیگری باشد. این امر بستگی به این دارد که تقسیم‌بندی‌ها در کجا تعریف شده‌اند. حتی اگر پاسخ کوئری‌ها از روی تقسیمات تجمیع (integration) شده قابل دستیابی نباشند، MOLAP سریع‌ترین پاسخ را فراهم می‌کند. سرعت انجام این کار به طراحی و درصد تجمیع تقسیم‌بندی‌ها بستگی دارد. 

مزایا : کارایی عالی-  حجم‌های داده‌ای MOLAP برای بازیابی سریع داده‌ها ساخته شده‌اند و در فعالیت‌های slice و dice به صورت بهینه پاسخ می‌دهند. ترکیب سادگی و سرعت مزیت اصلی MOLAP است.

در ضمنMOLAP  قابلیت محاسبه محاسبات پیچیده را فراهم می‌کند. همه محاسبات از پیش وقتی که حجم‌های داده‌ای ساخته می‌‌شود، ایجاد می‌شوند. بنابراین نه تنها محاسبات پیچیده انجام شدنی هستند بلکه بسیار سریع هم پاسخ می‌دهند.

معایب : عیب این روش این است که تنها برای داده‌هایی با مقدار محدود کارکرد خوبی دارد. از آنجا که همه محاسبات زمانی که حجم‌های داده‌ای ساخته می‌شود، محاسبه می‌گردند، امکان این که حجم‌های داده‌ای مقدار زیادی از داده‌ها را در خود جای دهد، وجود ندارد. ولی این به این معنا نیست که داده‌‌های حجم‌های داده‌ای نمی‌توانند از مقدار زیادی داده مشتق شده باشند. داده‌ها می‌توانند از مقدار زیادی داده مشتق شده‌باشند. اما در این صورت، فقط اطلاعات level خلاصه (level ای که دارای کمترین جزئیات است یعنی سطوح بالاتر) می‌‌توانند در حجم‌های داده‌ای  موجود باشند. 

ROLAP : محدودیت MOLAP در حجم داده‌های قابل پرس‌و‌جو و نیاز به روشی که از داده‌های ذخیره‌شده به روش رابطه‌ای حمایت کند، موجب پیشرفت ROLAP شد.

مبنای این روش کارکردن با داده‌هایی که در پایگاه‌داده‌های رابطه‌ای ذخیره‌شده‌اند، برای انجام اعمال slicing و dicing معمولی است. با استفاده از این مدل ذخیره‌سازی می‌توان داده‌ها را بدون ایجاد واقعی تجمیع در پایگاه‌داده‌های رابطه‌ای به هم مربوط کرد.

مزایا : با این روش می‌توان به حجم زیادی از داده‌ها را رسیدگی کرد. محدودیت حجم داده در تکنولوژی ROLAP مربوط به محدودیت حجم داده‌های قابل ذخیره‌سازی در پایگاه‌داده‌های رابطه‌ای است. به بیان دیگر، خود ROLAP هیچ محدودیتی بر روی حجم داده‌ها اعمال نمی‌کند.

معایب : ممکن است کارایی پایین بیاید. زیرا هر گزارش ROLAP در واقع یک کواِری SQL (یا چند کواِری SQL )در پایگاه داده‌های رابطه‌ای است و اگر حجم داده‌ها زیاد باشد ممکن است زمان پاسخ کواِری طولانی شود. در مجموع ROLAP سنگین است، نگهداری آن سخت است و کند هم هست. بخصوص زمانی که نیاز به آدرس دهی جدول‌های ذخیره شده در سیستم چند بعدی داریم.

این محدودیت ناشی از عملکرد SQL است. زیرا تکنولوژی ROLAP بر پایه عبارات مولد SQL برای پرسش و پاسخ بر روی پایگاه داده رابطه‌ای است و عبارات SQL به همه نیازها پاسخ نمی‌دهند (مثلاٌ محاسبه حساب‌های پیچیده در SQL مشکل است)، بنابراین فعالیت‌های ROLAP به آن چه SQL قادر به انجام آن است محدود می‌گردد. 

تفاوت ROALP و MOLAP : تفاوت اصلی این دو در معماری آن‌ها است. محصولات MOLAP داده‌های مورد نیاز را در یک حافظه نهان (cache) مخصوص می‌گذارد. ولی ROLAP تحلیل‌های خود را بدون استفاده از یک حافظه میانی انجام می‌دهد، بدون آن که از یک مرحله میانی برای گذاشتن داده‌ها در یک سرور خاص استفاده کند. 

با توجه به کند بودن ROLAP در مقایسه باMOLAP ، باید توجه داشت که کاربرد این روش بیشتر در پایگاه داده‌های بسیار بزرگی است که  گاه‌گاهی پرس و جویی بر روی آن‌ها شکل می‌گیرد، مثل داده‌های تاریخی و کمتر جدید سال‌‌های گذشته.

نکته: اگر از Analysis Services که به وسیله Microsoft OLE DB Provider مهیا شده استفاده می‌کنید، تجمیع‌ها نمی‌توانند برای تقسیم‌بندی از روش ROLAP استفاده نمایند.

HOLAP : با توجه به نیاز رو به رشدی که برای کارکردن با داده‌های بلادرنگ (real time) در بخش‌های مختلف در صنعت و تجارت احساس می‌شود، مدیران تجاری انتظار دارند بتوانند با دامنه وسیعی از اطلاعات که فوراً و بدون حتی لحظه‌ای تأخیر در دسترس باشند، کار کنند. در حال حاضر شبکه اینترنت و سایر کاربرد‌ها یی که به داده‌هایی از منابع مختلف مراجعه دارند و نیاز به فعالیت با یک سیستم بلادرنگ هم دارند، همگی از سیستم HOLAP بهره می‌گیرند.

named set :

Named Set مجموعه‌ای از memberهای بعد یا مجموعه‌ای از عبارات است که برای استفاده مجدد ایجاد می‌شود.

Calculated member 

Calculated Memberها memberهایی هستند که بر اساس داده‌ها نیستند بلکه بر اساس عبارات ارزیابی MDX هستند. آنها دقیقاَ به سبک سایر memberهای معمولی هستند. MDX یک مجموعه قوی از عملیاتی را تامین میکند که میتوانند برای ساختCalculated Memberها مورد استفاده قرار گیرند به طوری که به شما امکان داشتن انعطاف زیاد در کار کردن با داده‌های چند بعدی را بدهد. 

امیدوارم در این قسمت با مفاهیم نخستین OLAP آشنا شده باشید.

تلاش خواهم کرد در قسمت بعدی در خصوص نصب SQL Server Analysis Services و نصب پایگاه داده‌ی Adventure Work DW 2008 شرح کاملی را ارایه کنم.

 

نظرات مطالب
طراحی گردش کاری با استفاده از State machines - قسمت دوم
پروژه‌ی دیگری هست از همین گروه به نام mass transit. این پروژه، یک زیر شاخه‌ی ساخت گردش کاری به نام « Automatonymous » هم دارد؛ با این مستندات. به تست‌های سورس آن نگاه کنید، مثال NHibernate هم در آن لحاظ شده‌است.
مطالب
استفاده از Fluent Validation در برنامه‌های ASP.NET Core - قسمت دوم - اجرای قواعد اعتبارسنجی تعریف شده
در قسمت قبل، روش تعریف قواعد اعتبارسنجی را با استفاده از کتابخانه‌ی Fluent Validation بررسی کردیم. در این قسمت می‌خواهیم این قواعد را به صورت خودکار به یک برنامه‌ی ASP.NET Core معرفی کرده و سپس از آن‌ها استفاده کنیم.


روش اول: استفاده‌ی دستی از اعتبارسنج کتابخانه‌ی Fluent Validation

روش‌های زیادی برای استفاده‌ی از قواعد تعریف شده‌ی توسط کتابخانه‌ی Fluent Validation وجود دارند. اولین روش، فراخوانی دستی اعتبارسنج، در مکان‌های مورد نیاز است. برای اینکار در ابتدا نیاز است با اجرای دستور «dotnet add package FluentValidation.AspNetCore»، این کتابخانه را در پروژه‌ی وب خود نیز نصب کنیم تا بتوانیم از کلاس‌ها و متدهای آن استفاده نمائیم. پس از آن، روش دستی کار با کلاس RegisterModelValidator که در قسمت قبل آن‌را تعریف کردیم، به صورت زیر است:
using FluentValidationSample.Models;
using Microsoft.AspNetCore.Mvc;

namespace FluentValidationSample.Web.Controllers
{
    public class HomeController : Controller
    {
        public IActionResult Index()
        {
            return View();
        }

        [HttpPost]
        public IActionResult RegisterValidateManually(RegisterModel model)
        {
            var validator = new RegisterModelValidator();
            var validationResult = validator.Validate(model);
            if (!validationResult.IsValid)
            {
                return BadRequest(validationResult.Errors[0].ErrorMessage);
            }

            // TODO: Save the model

            return Ok();
        }
    }
}
ساده‌ترین روش کار با RegisterModelValidator تعریف شده، ایجاد یک وهله‌ی جدید از آن و سپس فراخوانی متد Validate آن شیء است. در این حالت می‌توان کنترل کاملی را بر روی قالب پیام نهایی بازگشت داده شده داشت. برای مثال در اینجا اولین خطای بازگشت داده شده، به اطلاع کاربر رسیده‌است. حتی می‌توان کل شیء Errors را نیز بازگشت داد.

یک نکته: متد الحاقی AddToModelState که در فضای نام FluentValidation.AspNetCore قرار دارد، امکان تبدیل نتیجه‌ی اعتبارسنجی حاصل را به ModelState استاندارد ASP.NET Core نیز میسر می‌کند:
public IActionResult RegisterValidateManually(RegisterModel model)
{
    var validator = new RegisterModelValidator();
    var validationResult = validator.Validate(model);
    if (!validationResult.IsValid)
    {
       validationResult.AddToModelState(ModelState, null);
       return BadRequest(ModelState);
    }

    // TODO: Save the model

    return Ok();
}


روش دوم: تزریق اعتبارسنج تعریف شده در سازنده‌ی کنترلر

بجای وهله سازی دستی RegisterModelValidator و ایجاد وابستگی مستقیمی به آن، می‌توان از روش تزریق وابستگی‌های آن نیز استفاده کرد. در این حالت اعتبارسنج RegisterModelValidator با طول عمر Transient به سیستم تزریق وابستگی‌ها معرفی شده:
namespace FluentValidationSample.Web
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IValidator<RegisterModel>, RegisterModelValidator>();
            services.AddControllersWithViews();
        }
 و پس از آن با تزریق <IValidator<RegisterModel به سازنده‌ی کنترلر مدنظر، می‌توان به امکانات آن همانند روش اول، دسترسی یافت:
namespace FluentValidationSample.Web.Controllers
{
    public class HomeController : Controller
    {
        private readonly IValidator<RegisterModel> _registerModelValidator;

        public HomeController(IValidator<RegisterModel> registerModelValidator)
        {
            _registerModelValidator = registerModelValidator;
        }

        [HttpPost]
        public IActionResult RegisterValidatorInjection(RegisterModel model)
        {
            var validationResult = _registerModelValidator.Validate(model);
            if (!validationResult.IsValid)
            {
                return BadRequest(validationResult.Errors[0].ErrorMessage);
            }

            // TODO: Save the model

            return Ok();
        }
    }
}
به این ترتیب new RegisterModelValidator را با وهله‌ای از <IValidator<RegisterModel، تعویض کردیم. کار با این روش بسیار انعطاف پذیر بوده و همچنین قابلیت آزمون پذیری بالایی را نیز دارد.


روش سوم: خودکار سازی اجرای یک تک اعتبارسنج تعریف شده

اگر متد الحاقی AddFluentValidation را به صورت زیر به سیستم معرفی کنیم:
namespace FluentValidationSample.Web
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddTransient<IValidator<RegisterModel>, RegisterModelValidator>();
            services.AddControllersWithViews().AddFluentValidation();
        }
سبب اجرای خودکار تمام IValidatorهای اضافه شده‌ی به سیستم، پیش از اجرای اکشن متد مرتبط با آن‌ها می‌شود. برای مثال اگر اکشن متدی دارای پارامتری از نوع RegisterModel بود، چون IValidator مخصوص به آن به سیستم تزریق وابستگی‌ها معرفی شده‌است، متد الحاقی AddFluentValidation، کار وهله سازی خودکار این IValidator و سپس فراخوانی متد Validate آن‌را به صورت خودکار انجام می‌دهد. به این ترتیب، قطعه کدهایی را که تاکنون نوشتیم، به صورت زیر خلاصه خواهند شد که در آن‌ها اثری از بکارگیری کتابخانه‌ی FluentValidation مشاهده نمی‌شود:
namespace FluentValidationSample.Web.Controllers
{
    public class HomeController : Controller
    {
        [HttpPost]
        public IActionResult RegisterValidatorAutomatically(RegisterModel model)
        {
            if (!ModelState.IsValid)
            {
                // re-render the view when validation failed.
                return View(model);
            }

            // TODO: Save the model

            return Ok();
        }
    }
}
زمانیکه model به سمت اکشن متد فوق ارسال می‌شود، زیرساخت model-binding موجود در ASP.NET Core، اینبار کار اعتبارسنجی آن‌را توسط RegisterModelValidator به صورت خودکار انجام داده و نتیجه‌ی آن‌را به ModelState اضافه می‌کند که برای مثال در اینجا سبب رندر مجدد فرم شده که تمام مباحث tag-helper‌های استانداردی مانند asp-validation-summary و asp-validation-for پس از آن به صورت متداولی و همانند قبل، قابل استفاده خواهند بود.

نکته 1: تنظیمات فوق برایASP.NET Web Pages و PageModels نیز یکی است. فقط با این تفاوت که اعتبارسنج‌ها را فقط می‌توان به مدل‌هایی که به صورت خواص یک page model تعریف شده‌اند، اعمال کرد و نه به کل page model.

نکته 2: اگر کنترلر شما به ویژگی [ApiController] مزین شده باشد:
namespace FluentValidationSample.Web.Controllers
{
    [Route("[controller]")]
    [ApiController]
    public class HomeController : Controller
    {
        [HttpPost]
        public IActionResult RegisterValidatorAutomatically(RegisterModel model)
        {
            // TODO: Save the model

            return Ok();
        }
    }
}
در این حالت دیگر نیازی به ذکر if (!ModelState.IsValid) نیست و خطای حاصل از شکست اعتبارسنجی، به صورت خودکار توسط FluentValidation تشکیل شده و بازگشت داده می‌شود (پیش از رسیدن به بدنه‌ی اکشن متد فوق) و برای نمونه یک چنین شکل و خروجی خودکاری را پیدا می‌کند:
{
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "|84df05e2-41e0d4841bb61293.",
    "errors": {
        "FirstName": [
            "'First Name' must not be empty."
        ]
    }
}
اگر علاقمند به سفارشی سازی این خروجی خودکار هستید، باید به این صورت با تنظیم ApiBehaviorOptions و مقدار دهی نحوه‌ی تشکیل ModelState نهایی، عمل کرد:
        public void ConfigureServices(IServiceCollection services)
        {
            // ...

            // override modelstate
            services.Configure<ApiBehaviorOptions>(options =>
            {
                options.InvalidModelStateResponseFactory = context =>
                {
                    var errors = context.ModelState.Values.SelectMany(x => x.Errors.Select(p => p.ErrorMessage)).ToList();
                    return new BadRequestObjectResult(new
                    {
                        Code = "00009",
                        Message = "Validation errors",
                        Errors = errors
                    });
                };
            });
        }


روش چهارم: خودکار سازی ثبت و اجرای تمام اعتبارسنج‌های تعریف شده

و در آخر بجای معرفی دستی تک تک اعتبارسنج‌های تعریف شده به سیستم تزریق وابستگی‌ها، می‌توان تمام آن‌ها را با فراخوانی متد RegisterValidatorsFromAssemblyContaining، به صورت خودکار از یک اسمبلی خاص استخراج نمود و با طول عمر Transient، به سیستم معرفی کرد. در این حالت متد ConfigureServices به صورت زیر خلاصه می‌شود:
namespace FluentValidationSample.Web
{
    public class Startup
    {
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddControllersWithViews().AddFluentValidation(
                fv => fv.RegisterValidatorsFromAssemblyContaining<RegisterModelValidator>()
            );
        }
در اینجا امکان استفاده‌ی از متد fv.RegisterValidatorsFromAssembly نیز برای معرفی اسمبلی خاصی مانند ()Assembly.GetExecutingAssembly نیز وجود دارد.


سازگاری اجرای خودکار FluentValidation با اعتبارسنج‌های استاندارد ASP.NET Core

به صورت پیش‌فرض، زمانیکه FluentValidation اجرا می‌شود، اگر اعتبارسنج دیگری نیز در سیستم تعریف شده باشد، اجرا خواهد شد. به این معنا که برای مثال می‌توان FluentValidation و DataAnnotations attributes و IValidatableObject‌ها را با هم ترکیب کرد.
اگر می‌خواهید این قابلیت را غیرفعال کنید و فقط سبب اجرای خودکار FluentValidationها شوید، نیاز است تنظیم زیر را انجام دهید:
public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews().AddFluentValidation(
       fv =>
       {
           fv.RegisterValidatorsFromAssemblyContaining<RegisterModelValidator>();
           fv.RunDefaultMvcValidationAfterFluentValidationExecutes = false;
       }
    );
}
مطالب
چرا توسعه چابک (Agile Development)؟

خیلی از ما با کابوس پروژه ای که هیچ تجربه ای در انجام آن نداریم روبرو شده ایم. نبودن تجربه موثر منجر به خطاهای تکراری و غیر قابل پیش بینی شده و تلاش و وقت ما را به هدر می­دهد. مشتریان از کیفیت پایین، هزینه بالا و تحویل دیر هنگام محصول ناراضی هستند و توسعه دهندگان از اضافه کارهای بیشتر که منجر به نرم افزار ضعیت­تر می­گردد، ناخشنود.

همین که با شکستی مواجه می­شویم از تکرار چنین پروژه هایی اجتناب می­کنیم. ترس ما باعث می­شود تا فرآیندی بسازیم که فعالیت­های ما را محدود نموده و ایجاد آرتیفکت­ها[۱] را الزامی کند. در پروژه­ جدید از  چیزهایی که در پروژه‌های قبلی به خوبی کار کرده­اند، استفاده می­کنیم. انتظار ما این است که آنها برای پروژه جدید نیز به همان خوبی کار کند.

اما پروژه‌­ها آنقدر ساده نیستند که تعدادی محدودیت و آرتیفکت­ ما را از خطاها ایمن سازند. با بروز خطاهای جدید ما آنها را شناسایی و رفع می­کنیم. برای اینکه در آینده با این خطاها روبرو نشویم آنها را در محدودیت­ها و آرتیفکت­های جدیدی قرار می­دهیم. بعد از انجام پروژه‌های زیاد با فرآیندهای حجیم و پر زحمتی روبرو هستیم که توانایی تیم را کم کرده و باعث کاهش کیفیت تولید می­شوند.

فرآیندهای بزرگ و حجیم می­تواند مشکلات زیادی را ایجاد کند. متاسفانه این مشکلات باعث می­شود که خیلی از افراد فکر کنند که علت مشکلات، نبود فرآیندهای کافی است. بنابراین فرآیندها را حجیم­تر و پیچیده­تر می­کنند. این مسئله منجر به تورم فرآیندها می­گردد که در محدوده سال ۲۰۰۰ گریبان بسیاری از شرکت­های نرم افزاری را گرفت.

اتحاد چابک

در وضعیتی که تیم­های نرم افزاری در بسیاری از شرکت­ها خود را در مردابی از فرآیندهای زیاد شونده می­دیدند، تعدادی از خبره‌­های این صنعت که خود را اتحاد چابک[۲] نامیدند در اویل سال ۲۰۰۱ یکدیگر را ملاقات کرده و ارزش هایی را معرفی کردند تا تیم­های نرم افزاری سریعتر نرم افزار را توسعه داده و زودتر به تغییرات پاسخ دهند. چند ماه بعد، این گروه ارزش­هایی تعریف شده را تحت مانیفست اتحاد چابک در سایت http://agilemanifesto.org منتشر کردند.

مانیفست اتحاد چابک

ما با توسعه نرم افزار و کمک به دیگران در انجام آن، در حال کشف راه‌های بهتری برای توسعه نرم افزار هستیم. از این کار به ارزش‌های زیر می­رسیم :

۱- افراد و تعاملات بالاتر از فرآیندها و ابزارها

۲- نرم افزار کار کننده بالاتر از  مستندات جامع

۳- مشارکت مشتری بالاتر از قرارداد کاری

۴- پاسخگویی به تغییرات بالاتر از پیروی از یک برنامه

با آنکه موارد سمت چپ ارزشمند هستند ولی ما برای موارد سمت راست ارزش بیشتری قائل هستیم.

افراد و تعاملات بالاتر از فرآیندها و ابزارها

افراد مهمترین نقش را در پیروزی یک پروژه دارند. یک فرآیند عالی بدون نیروی مناسب منجر به شکست می­گردد و بر عکس افراد قوی تحت فرآیند ضعیت ناکارآمد خواهند بود.

یک نیروی قوی لازم نیست که برنامه نویسی عالی باشد، بلکه کافیست که یک برنامه نویسی معمولی با قابلیت همکاری مناسب با سایر اعضای تیم باشد. کار کردن با دیگران، تعامل درست و سازنده با سایر اعضای تیم خیلی مهمتر از این که یک برنامه نویس با هوش باشد. برنامه نویسان معمولی که تعامل درستی با یکدیگر دارند به مراتب موفقتر هستند از تعداد برنامه نویسی عالی که قدرت تعامل مناسب با یکدیگر را ندارند.

در انتخاب ابزارها آنقدر وقت نگذارید که کار اصلی و تیم را فراموش کنید. به عنوان مثال می­توانید در شروع به جای بانک اطلاعاتی از فایل استفاده کنید، به جای ابزار کنترل کد گرانقیمت از برنامه رایگان کد باز استفاده کنید. باید به هیچ ابزاری عادت نکنید و صرفا به آنها به عنوان امکانی جهت تسهیل فرآیندها نگاه کنید.

نرم افزار کار کننده بالاتر از  مستندات جامع

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

با این حال، مستندات زیاد از مستندات کم بدتر است. ساخت مستندات زیاد نیاز به وقت زیادی دارد و وقت بیشتری را می‌گیرد تا آن را با کد برنامه به روز نمایید. اگر آنها با یکدیگر به روز نباشند باعث درک اشتباه از سیستم می‌شوند.

بهتر است که همیشه مستندات کم حجمی از منطق و ساختار برنامه داشته باشید و آن را به روز نماید. البته آنها باید کوتاه و برجسته باشند. کوتاه به این معنی که ۱۰ تا ۲۰ صفحه بیشتر نباشد و برجسته به این معنی که طراحی کلی و ساختار سطح بالای سیستم را بیان نماید.

اگر فقط مستندات کوتاه از ساختار و منطق سیستم داشته باشیم چگونه می‌توانیم اعضای جدید تیم را آموزش دهیم؟ پاسخ کار نزدیک شدن به آنها است. ما دانش خود را با نشستن در کنار آنها و کمک کردن به آنها انتقال می­دهیم. ما آنها را بخشی از تیم می­کنیم و با تعامل نزدیک و رو در رو به آنها آموزش می­دهیم.

مشارکت مشتری بالاتر از قرارداد کاری

نرم افزار نمی­تواند مثل یک جنس سفارش داده شود. شما نمی‌توانید یک توصیف از نرم افزاری که می‌خواهید را بنویسید و آنگاه فردی آن را بسازد و در یک زمان معین با قیمت مشخص به شما تحویل دهد. بارها و بارها این شیوه با شکست مواجه شده است.

این قابل تصور است که مدیران شرکت به اعضای تیم توسعه بگویند که نیازهای آنها چیست، سپس اعضای تیم بروند و بعد از مدتی برگردند و یک سیستمی که نیازهای آنها را برآورده می‌کند، بسازند. اما این تعامل به کیفیت پایین نرم افزار و در نهایت شکست آن می‌انجامد. پروژه‌های موفق بر اساس دریافت بازخورد مشتری در بازه‌های زمانی کوتاه و مداوم است. به جای وابستگی به قرارداد یا دستور کار، مشتری به طور تنگاتنگ با تیم توسعه کار کرده و مرتبا اعمال نظر می­کند.

قراردادی که مشخص کننده نیازمندیها، زمانبندی و قیمت پروژه است، اساسا نقص دارد. بهترین قرارداد این است که تیم توسعه و مشتری با یکدیگر کار کنند.

پاسخگویی به تغییرات بالاتر از پیروی از یک برنامه

توانایی پاسخ به تغییرات اغلب تعیین کننده موفقیت یا شکست یک پروژه نرم افزاری است. وقتی که طرحی را می­ریزیم باید مطمئن شویم که به اندازه کافی انعطاف پذیر است و آمادگی پذیرش تغییرات در سطح بیزنس و تکنولوژی را دارد.

مسیر یک پروژه نرم افزاری نمی­تواند برای بازه زمانی طولانی برنامه ریزی شود. اولا احتمالا محیط تغییر می­کند و باعث تغییر در نیازمندی‌ها می­شود. ثانیا همین که سیستم شروع به کار کند مشتریان نیازمندی­های خود را تغییر می‌دهند. بنابراین اگر بدانیم که نیازها چیست و مطمئن شویم که تغییر نمی­کنند، قادر به برآورد مناسب خواهیم بود، که این شرایط بعید است.

یک استراتژی خوب برای برنامه ریزی این است که یک برنامه ریزی دقیق برای یک هفته بعد داشته باشیم و یک برنامه ریزی کلی برای سه ماه بعد.

اصول چابک

۱- بالاترین اولویت ما عبارت است از راضی کردن مشتری با تحویل سریع و مداوم نرم افزار با ارزش. تحویل نرم افزار با کارکردهای کم در زود هنگام بسیار مهم است چون هم مشتری چشم اندازی از محصول نهایی خواهد داشت و هم مسیر کمتر به بیراهه می‌رود.

۲- خوش آمدگویی به تغییرات حتی در انتهای توسعه. اعضای تیم چابک، تغییرات را چیز خوبی می‌بینند زیرا تغییرات به این معنی است که تیم بیشتر یاد گرفته است که چه چیزی مشتری را راضی می‌کند.

۳- تحویل نرم افزار قابل استفاده از چند هفته تا چند ماه با تقدم بر تحویل در دوره زمانی کوتاهتر. ما مجموعه از مستندات و طرحها را به مشتری نمی‌دهیم.

۴- افراد مسلط به بیزنس و توسعه دهندگان باید روزانه با یکدیگر روی پروژه کار کنند. یک پروژه نرم افزاری نیاز به هدایت مداوم دارد.

۵- ساخت پروژه را بر توان افراد با انگیزه بگذارید و به آنها محیط و ابزار را داده و اعتماد کنید.  مهمترین فاکتور موفقیت افراد هستند، هر چیز دیگر مانند فرآیند، محیط و مدیریت  فاکتورهای بعدی محسوب می­شوند که اگر تاثیر بدی روی افراد می­گذارند، باید تغییر کنند.

۶- بهترین و موثر‌ترین روش کسب اطلاعات در تیم توسعه، ارتباط چهره به چهره است. در تیم چابک افراد با یکدیگر صحبت می‌کنند. نامه نگاری و مستند سازی فقط زمانی که نیاز است باید صورت گیرد.

۷- نرم افزار کار کننده معیار اصلی پیشرفت است. پروژه‌های چابک با نرم افزاری که در حال حاضر نیازهای مشتری را پاسخ می‌دهد، سنجیده می‌شوند. میزان مستندات، حجم کدهای زیر ساخت و هر چیز دیگری غیره از نرم افزار کار کننده معیار پیشرفت نرم افزار نیستند.

۸- فرآیندهای چابک توسعه با آهنگ ثابت را ترویج می‌دهد. حامیان، توسعه دهندگان و کاربران باید یک آهنگ توسعه ثابت را حفظ کنند که بیشتر شبیه به دو  ماراتون است یا دوی ۱۰۰ متر. آنها با سرعتی کار می‌کنند که بالاترین کیفیت را ارائه دهند.

۹- توجه مداوم به برتری تکنیکی و طراحی خوب منجر به چابکی می­گردد. کیفیت بالاتر کلیدی برای سرعت بالا است. راه سریعتر رفتن این است که نرم افزار تا جایی که ممکن است پاک و قوی نگهداریم. بنابراین همه اعضای تیم چابک تلاش می­کنند که با کیفیت­ترین کار ممکن را انجام دهند. آنها هر آشفتگی را به محض ایجاد برطرف می‌کنند.

۱۰-  سادگی هنر بیشینه کردن مقدار کاری که لازم نیست انجام شود، است. تیم چابک همیشه ساده‌ترین مسیر که با هدف آنها سازگار است را در پیش می­گیرند. آنها وقت زیادی روی مشکلاتی که ممکن است فردا رخ دهد، نمی­گذارند.  آنها کار امروز را با کیفیت انجام داده و مطمئن می­شوند که تغییر آن در صورت بروز مشکلات در فردا، آسان خواهد بود.

۱۱-  بهترین معماری و طراحی از تیم‌های خود سازمان ده بیرون می‌آید. مدیران، مسئولیت‌ها را به یک فردی  خاصی در تیم نمی‌دهند بلکه بر عکس با تیم به صورت یک نیروی واحد برخورد می­کنند. خود تیم تصمیم می­گیرد که هر مسئولیت را چه کسی انجام دهد. تیم چابک با هم روی کل جنبه‌های پروژه کار می­کنند. یعنی یک فرد خاص مسئول معماری، برنامه نویسی، تست و غیره نیستند. تیم، مسئولیتها را به اشتراک گذاشته و هر فرد بر کل کار تاثیر دارد.

۱۲-  در بازهای زمانی مناسب تیم در می­یابد که چگونه می­تواند کاراتر باشد و رفتار خود را متناسب با آن تغییر دهد. تیم می­داند که محیط دائما در حال تغییر است، بنابراین خود را با محیط تغییر می­دهد تا چابک بماند.

ضرورت توسعه چابک

امروزه صنعت نرم افزار دارای سابقه بدی در تحویل به موقع و با کیفیت نرم افزار است. گزارشات بسیاری تایید می­کنند که بیش از ۸۰ درصد از پروژه‌های نرم افزاری با شکست مواجه می­شوند؛ در سال ۲۰۰۵ موسسه IEEE  برآورد زده است که بیش از ۶۰ بیلیون دلار صرف پروژه‌های نرم افزاری شکست خورده شده است. عجب فاجعه­ای؟

شش دلیل اصلی شکست پروژه‌های نرم افزاری

وقتی که از مدیران و کارکنان سوال می­شود که چرا پروژه‌های نرم افزاری با شکست مواجه می­شوند، آنها به موضوعات گسترده ای اشاره می­کنند. اما شش دلیل زیر بارها و بارها تکرار شده است که به عنوان دلایل اصلی شکست نرم افزار معرفی می­شوند:

۱- درگیر نشدن  مشتری

۲- عدم درک درست نیازمندها

۳- زمان بندی غیر واقعی

۴- عدم پذیریش و مدیریت تغییرات

۵- کمبود تست نرم افزار

۶- فرآیندهای غیر منعطف و باد دار

چگونه چابکی این مشکلات را رفع می­کند؟

با آنکه Agile برای هر مشکلی راه حل ندارد ولی برای مسائل فوق بدین صورت کمک می­کند:

مشتری پادشاه است!

برای رفع مشکل عدم همکاری کاربر نهایی یا مشتری، Agile مشتری را عضوی از تیم توسعه می­کند. به عنوان عضوی از تیم، مشتری با تیم توسعه کار می­کند تا مطمئن شود که نیازمندها به درستی برآورده می­شوند. مشتری همکاری می­کند در شناسایی نیازمندی­ها، تایید می­کند نتیجه نهایی را و حرف آخر را در اینکه کدام ویژگی به نرم افزار اضافه شود، حذف شود و یا تغییر کند، را می­زند.

نیازمندی‌ها به صورت تست­های پذیرش[۳] نوشته می­شوند

برای مقابله با مشکل عدم درک درست نیازمندی­ها، Agile تاکید دارد که نیازمندیهای کسب شده باید به صورت ویژگی­هایی تعریف شوند که بر اساس معیارهای مشخصی قابل پذیرش باشند. این معیارهای پذیرش برای نوشتن تست­های پذیرش به کار می­روند. به این ترتیب قبل از اینکه کدی نوشته شود، ابتدا تست پذیرش نوشته می­شود. این بدین معنی است که هر کسی باید اول فکر کند که چه می­خواهد، قبل از اینکه از کسی بخواهد آن را انجام دهد. این راهکار فرایند کسب نیازمندی­ها را از بنیاد تغییر می­دهد و به صورت چشم گیری کیفیت برآورد و زمان بندی را بهبود می­دهد.

زمانبندی با مذاکره بین تیم توسعه و سفارش دهنده تنظیم می­شود

برای حل مشکل زمان بندی غیر واقعی، Agile زمان بندی را به صورت یک فرآیند مشترک بین تیم توسعه و سفارش دهنده تعریف می­کند. در شروع هر نسخه از  نرم افزار، سفارش دهنده ویژگی‌های مورد انتظار را به تیم توسعه می­گوید. تیم توسعه تاریخ تحویل را بر اساس ویژگی­ها برآورد می­زد و در اختیار سفارش دهنده قرار می­دهد. این تعامل تا رسیدن به یک دیدگاه مشترک ادامه می­یابد.

هیچ چیزی روی سنگ حک نشده است، مگر تاریخ تحویل

برای رفع مشکل ضعف در مدیریت تغییرات، Agile اصرار دارد که هر کسی باید تغییرات را بپذیرد و نسبت به آنها واقع بین باشد. یک اصل مهم Agile  می­گوید که هر چیزی می­تواند تغییر کند مگر تاریخ تحویل! به عبارت دیگر همین که محصول به سمت تولید شدن حرکت می­کند، مشتری (در تیم محصول) می­تواند بر اساس اولویت­ها و ارزش­های خود ویژگی­های محصول را کم یا زیاد کرده و یا تغییر دهد. به هر حال او باید واقع بین باشد. اگر او یک ویژگی جدید اضافه کنید، باید تاریخ تحویل را تغییر دهد. به این ترتیب همیشه تاریخ تحویل رعایت می­گردد.

تست­ها قبل از کد نوشته می­شوند و کاملا خودکار هستند

برای رفع مشکل کمبود تست، Agile تاکید می­کند که ابتدا باید تست­ها نوشته شوند و همواره ارزیابی گردند. هر برنامه نویس باید اول تست­ را بنویسد، سپس کد لازم برای پاس شدن آن را. همین که کد تغییر می­کند باید تست­ها دوباره اجرا شوند. در این راهکار، هر برنامه نویس مسئول تست­های خود است تا درستی برنامه از ابتدا تضمین گردد.

مدیریت پروژه یک فعالیت جداگانه نیست

برای رفع مشکل فرآیندهای غیر منعطف و باددار، Agile مدیریت پروژه را درون فرآیند توسعه می­گنجاند. وظایف مدیریت پروژه بین اعضای تیم توسعه تقسیم می­شود. برای مثال هر ۷ نفر در تیم توسعه نرم افزار (متدلوژی اسکرام) زمان تحویل را با مذاکره تعیین می­کنند. همچنین کد برنامه به صورت خودکار اطلاعات وضعیت پروژه را تولید می­کند. به عنوان مثال  نمودار burndown ، تست­های انجام نشده، پاس شده و رد شده به صورت خودکار تولید می­شوند.

به کار گیری توسعه چابک

یکی از مشکلات توسعه چابک این است که شما اول باید به خوبی آن را درک کنید تا قادر به پیاده سازی درست آن باشید. این درک هم باید کلی باشد (مانند Scrum و XP) و هم جزئی (مانند TDD و جلسات روازنه). اما چگونه باید به این درک برسیم؟ کتاب­ها و مقالات انگلیسی زیادی برای یادگیری توسعه چابک و پیاده سازی آن در سازمان وجود دارند، ولی متاسفانه منابع فارسی کمی در این زمینه است. هدف این کتاب رفع این کمبود و آموزش عملی توسعه چابک و ابزارهای پیاده سازی آن است.

برای این یک توسعه دهنده چابک شوید، باید به مهارت­های فردی و تیمی چابک برسید. در ادامه این مهارت­ها معرفی می­شوند.

مهارت­های فردی

قبل از هر چیز شما باید یک برنامه نویس باشید و مقدمات برنامه نویسی مانند الگوریتم و فلوچارت، دستورات برنامه نویسی، کار با متغیرها، توابع و آرایه­‌ها را بلد باشید. پس از تسلط به مقدمات برنامه نویسی می­توانید مهارت­های برنامه نویسی چابک را فرا بگیرید که عبارتند از:

- برنامه نویسی شیءگرا

- توسعه تست محور

- الگوهای طراحی

در ادامه نحوه کسب این مهارت­ها بیان می­شوند.

برنامه نویسی شیءگرا

اساس طراحی چابک بر تفکر شیءگرا استوار است. بنابراین تسلط به مفاهیم و طراحی شیءگرا ضروری است. 

توسعه تست محور

مهمترین و انقلابی‌ترین سبک برنامه نویسی از دهه گذشته تا به امروز، توسعه یا برنامه نویسی تست محور است. این سبک بسیاری از ارزش‌های توسعه چابک را فراهم می­کند و یادگیری آن برای هر توسعه دهنده چابک ضروری است.

الگوهای طراحی

الگوهای طراحی راه حل­های انتزاعی سطح بالا هستند. این الگوها بهترین تکنیک­های[۴] طراحی نرم افزار هستند و بسیاری از مشکلاتی که در طراحی نرم افزار رخ می­دهند با استفاده از این الگوها قابل حل هستند.

مهارت­های تیمی

انجام پروژه نرم افزاری یک کار تیمی است. شما پس از یادگیری مهارت­های فردی باید خود را آماده حضور در تیم توسعه چابک کنید. برای این منظور باید با مهارت تیمی مانند آشنایی با گردشکار تولید نرم افزار، حضور موثر در جلسات، قبول مسئولیت­ها و غیره آشنا شوید.

اسکرام

تمامی مهارت­های تیمی توسعه چابک توسط اسکرام آموزش داده می­شوند. اسکرام فریم ورکی برای توسعه چابک است که با تعریف فرآیندها، نقش­ها و آرتیفکت­های مشخص به تیم­های نرم افزاری کمک می­کند تا چابک شوند.


[۱] Artifact : خروجی یک فرآیند  است. مثلا خروجی طراحی شیءگرا، نمودارهای UML است.

[۲] Agile Alliance

[3] Acceptance Tests

[4] Best Practice

--------------------------------

اطلاعات بیشتر در http://AgileDevelopment.ir

نظرات مطالب
کار با اسکنر در برنامه های تحت وب (قسمت دوم و آخر)
با سلام
در صورتی که از وب سرویس asmx یا web API یا wcf service در پروژه وبی جهت انجام عملیات اسکن استفاده کنم با خطای زیر مواجه می‌شوم :

Creating an instance of the COM component with CLSID {850D1D11-70F3-4BE5-9A11-77AA6B2BB201} from the IClassFactory failed due to the following error: 80070005 Access is denied. (Exception from HRESULT: 0x80070005 (E_ACCESSDENIED)).

سطح دسترسی application pool وب سایت را نیز تغییر داده ام, اما مشکل حل نشده است .
ظاهرا اگر عملیات دسترسی به کتابخانه WIA از طریق وب سایت انجام شود این مشکل به وجود می‌آید .
یعنی حتما باید این کار در یک پروژه مجزای WCF انجام شود و هاست شود و سپس در وب اپلیکیشن فراخوانی شود؟ 
مطالب
ارسال ترافیک وب یک برنامه‌ی خاص به یک پروکسی سرور به کمک FiddlerCore
خیلی از برنامه‌ها به صورت پیش‌فرض تنظیمات پروکسی خاصی را درنظر نگرفته‌اند. در شبکه‌های داخلی شرکت‌ها هم معمولا اینترنت از طریق پروکسی سرورهایی مانند ISA Server ویندوزی و یا Squid لینوکسی، بین کاربران توزیع می‌شود.

سؤال: چطور می‌شود برنامه‌ای را که تنظیمات پروکسی ندارد، پروکسی خور کرد؟!

روشی که با سطح دسترسی معمولی و بدون نیاز به درایورهای خاص بررسی پکت‌های TCP و UDP سیستم و همچنین توسط دات نت فریم ورک قابل استفاده باشد، استفاده از کتابخانه‌ی معظم FiddlerCore است. برنامه‌ی Fiddler توسط یکی از کارکنان سابق مایکروسافت و عضو پیشین تیم IE تهیه شده‌است. کار اصلی این برنامه، دیباگ درخواست‌های HTTP/HTTPS، FTP و امثال آن است. هسته‌ی اصلی آن نیز به صورت یک کتابخانه‌ی مجزا به نام FiddlerCore در اختیار برنامه نویس‌های دات نت است. این برنامه اخیرا توسط شرکت تلریک پشتیبانی و تملک شده‌است.
کتابخانه‌ی FiddlerCore و برنامه‌ی Fiddler را از اینجا می‌توانید دریافت کنید. (اگر سایت آن باز نمی‌شود به این علت است که هاستینگ شرکت تلریک IP‌های ایرانی را بسته است)


اسکلت اصلی یک برنامه‌ی مبتنی بر FiddlerCore

using System;
using System.Net;
using System.Threading;
using Fiddler;
using System.Net.Security;

namespace FiddlerTest
{
    class Program
    {
        static void beforeRequest(Session oSession)
        {
        }

        static void Main(string[] args)
        {
            try
            {
                startFiddlerApplication();

                Console.WriteLine("FiddlerCore started on port " + FiddlerApplication.oProxy.ListenPort);
                Console.WriteLine("Press any key to exit");
                Console.ReadKey();
            }
            finally
            {
                shutdownFiddlerApplication();
            }
        }

        static void onLogString(object sender, LogEventArgs e)
        {
            Console.WriteLine("** LogString: " + e.LogString);
        }

        static void onNotification(object sender, NotificationEventArgs e)
        {
            Console.WriteLine("** NotifyUser: " + e.NotifyString);
        }

        static void onValidateServerCertificate(object sender, ValidateServerCertificateEventArgs e)
        {
            if (SslPolicyErrors.None == e.CertificatePolicyErrors)
                return;

            Console.WriteLine("invalid certificate: {0}", e.ServerCertificate.Subject);

            e.ValidityState = CertificateValidity.ForceValid;
        }

        static void shutdownFiddlerApplication()
        {
            FiddlerApplication.OnNotification -= onNotification;
            FiddlerApplication.Log.OnLogString -= onLogString;
            FiddlerApplication.BeforeRequest -= beforeRequest;
            FiddlerApplication.OnValidateServerCertificate -= onValidateServerCertificate;

            FiddlerApplication.oProxy.Detach();
            FiddlerApplication.Shutdown();

            Thread.Sleep(500);
        }

        private static void startFiddlerApplication()
        {
            FiddlerApplication.OnNotification += onNotification;
            FiddlerApplication.Log.OnLogString += onLogString;
            FiddlerApplication.BeforeRequest += beforeRequest;
            FiddlerApplication.OnValidateServerCertificate += onValidateServerCertificate;

            FiddlerApplication.Startup(5656,
                FiddlerCoreStartupFlags.RegisterAsSystemProxy |
                FiddlerCoreStartupFlags.MonitorAllConnections |
                FiddlerCoreStartupFlags.CaptureFTP); // proxy server on 5656
        }
    }
}
اسکلت کلی یک برنامه‌ی مبتنی بر FiddlerCore را در اینجامشاهده می‌کنید. در متد startFiddlerApplication کار برپایی پروکسی آن صورت می‌گیرد. همچنین یک سری Callback نیز در اینجا قابل تنظیم هستند. برای مثال پیام‌ها و اخطارهای داخلی FiddlerCore را می‌توان دریافت کرد و یا توسط روال رخدادگردان BeforeRequest می‌توان کار تحت کنترل قرار دادن یک درخواست را انجام داد. به همین جهت است که به این برنامه و کتابخانه، Web debugger نیز گفته می‌شود. متد BeforeRequest دقیقا جایی است که می‌توانید روی یک درخواست صادر شده توسط مرورگر، break point قرار دهید.
در متد FiddlerApplication.Startup روی پورتی مشخص، کار تنظیم پروکسی فیدلر انجام می‌شود. سپس مشخص می‌کنیم که چه مواردی را باید تحت نظر قرار دهد. با تنظیمات RegisterAsSystemProxy و MonitorAllConnections فیدلر قادر خواهد بود ترافیک وب اکثر برنامه‌های ویندوزی را مونیتور و دیباگ کند.
در متد shutdownFiddlerApplication نیز روال‌های رخدادگردان، آزاد شده و پروکسی آن خاموش می‌شود.


هدایت درخواست‌های وب کلیه‌ی برنامه‌ها به یک پروکسی مشخص

static void beforeRequest(Session oSession)
{
  //send each request to the next proxy
  oSession["X-OverrideGateway"] = "socks=" + IPAddress.Loopback + ":" + 2002; //socks on 2002
}
در اینجا شیء oSession، حاوی اطلاعات کامل درخواست در حال بررسی است. توسط آن می‌توان با استفاده از تنظیم خاصی به نام X-OverrideGateway، به فیدلر اعلام کرد که درخواست رسیده را به پروکسی سرور دیگری منتقل کن. تنها کاری که باید صورت گیرد ذکر IP و پورت این پروکسی سرور است. اگر نوع آن سرور، ساکس باشد به ابتدای رشته یاد شده باید یک =socks، نیز اضافه شود.


هدایت درخواست‌های تنها یک برنامه‌ی خاص به یک پروکسی مشخص

در متد beforeRequest، متغیر oSession.LocalProcessID مشخص کننده‌ی مقدار PID پروسه‌ای است که درخواست وب آن در حال بررسی است. برای بدست آوردن این PIDها در دات نت می‌توان از متد Process.GetProcesses استفاده کرد. Id هر پروسه، همان LocalProcessID فیدلر است. بر این اساس می‌توان تنها یک پروسه‌ی مشخص را تحت نظر قرار داد و نه کل سیستم را.

کاربردها
- فرض کنید برنامه‌ای تنظیمات پروکسی ندارد. با استفاده از روش فوق می‌توان برای آن پروکسی تعریف کرد.
- فرض کنید برنامه‌ای تنظیمات HTTP پروکسی دارد، اما پروکسی سرور شما از نوع ساکس است و نمی‌توان از این پروکسی سرور در برنامه‌ی مورد نظر استفاده کرد. X-OverrideGateway ذکر شده با هر دو نوع پروکسی‌های HTTP و Socks کار می‌کند.


اگر علاقمند به مطالعه‌ی اطلاعات بیشتری در مورد این کتابخانه هستید، کتاب 316 صفحه‌ای Debugging with Fiddler نویسنده‌ی اصلی آن، Eric Lawrence توصیه می‌شود.


معرفی برنامه‌ی Process Proxifier

اگر اطلاعات فوق را کنار هم قرار دهیم و یک GUI نیز برای آن طراحی کنیم، به برنامه‌ی Process Proxifier خواهیم رسید:


کار کردن با آن نیز بسیار ساده‌است. در قسمت تنظیمات پیش فرض برنامه، آدرس IP و پورت پروکسی سرور خود را وارد کنید. نوع آن‌را نیز مشخص نمائید که Socks است یا از نوع HTTP Proxy.
سپس در لیست پروسه‌ها، مواردی را که لازم است از این پروکسی عبور کنند تیک بزنید. در اینجا می‌شود یا از تنظیمات پیش فرض استفاده کرد، یا می‌توان به ازای هر پروسه، از یک پروکسی مجزا با تنظیماتی که ذکر می‌کنید، کمک گرفت. اگر صرفا یک پروسه را انتخاب کنید و اطلاعاتی را وارد ننمائید، از اطلاعات پروکسی پیش فرض استفاده خواهد شد.

دریافت سورس + باینری
ProcessProxifier_V1.0.rar
نظرات مطالب
نمونه‌ای از تزریق اس کیوال جهت درج تبلیغات مخفی شده‌ی در رکوردهای سایت
با دیدن سایت، کار خاصی نمی‌شه انجام داد. شاید حداکثر بشه با ابزارهای تزریق کور اس کیوال مثل ACUNETIX یک حدس‌هایی زد؛ ولی کافی نیست. کد شما باید سطر به سطر بررسی و آنالیز بشه.
خود مایکروسافت یک زمانی برای وب فرم‌ها، ابزاری رو به نام CAT.NET، درست کرده بود که کارش آنالیز استاتیک امنیتی کدهای برنامه است. نسخه‌ی 32 بیتی + نسخه‌ی 64 بیتی + ویدیوی آموزشی آن
اشتراک‌ها
پیاده سازی websockets در NetCore

تعریف وب سوکت : یه پروتکلی هست بر مبنای TCP که یک ارتباط دو طرفه  بین کلاینت و سرور ایجاد میکنه 
کاربرد وب سوکت : بیشتر در چت و وب کنفرانس‌ها و در برنامه هایی که نیاز به ارتباط تنگاتنگ بین سرور و کلاینت هست یا مثلا تو یه قسمتی از برنامه برای چک کردن پست ، اطلاعیه و پیغام جدید و یا در بازی‌های تحت وب 

تفاوت عمده ای که وب سوکت با HTTP داره در اینه که در HTTP سرور بعد از ارسال response کانکشن موجود رو قطع میکنه ,ولی در وب سوکت بعد از پاسخ سرور کانکشن موجود همچنان برقرار هست و این کمک میکنه که هر وقت دیتای جدیدی بود باز به کلاینت ارسال کنه 



پیاده سازی websockets در NetCore