نظرات مطالب
ASP.NET MVC #4
به این منو مراجعه کنید: Tools/Import and Export Settings 
مطالب
شروع به کار با EF Core 1.0 - قسمت 1 - برپایی تنظیمات اولیه
در ادامه‌ی سری «ارتقاء به ASP.NET Core 1.0» اگر بخواهیم مباحث اعتبارسنجی کاربران و ASP.NET Identity مخصوص آن‌را بررسی کنیم، نیاز است ابتدا مباحث Entity framework Core 1.0 را بررسی کنیم. به همین جهت در طی چند قسمت مباحث پایه‌ای کار با EF Core 1.0 را در ASP.NET Core 1.0، بررسی خواهیم کرد. بنابراین پیشنیاز ضروری این مباحث، مطالعه‌ی سری «ارتقاء به ASP.NET Core 1.0» است و در آن از مباحثی مانند چگونگی کار با فایل‌های کانفیگ جدید، تزریق وابستگی‌ها و سرویس‌ها، فعال سازی سرویس Logging، فعال سازی صفحات مخصوص توسعه دهنده‌ها و ... در ASP.NET Core 1.0 استفاده خواهد شد.


EF Core چیست؟

EF Core یک ORM یا object-relational mapper چندسکویی است که امکان کار با بانک‌های اطلاعاتی مختلف را از طریق اشیاء دات نتی میسر می‌کند. توسط آن قسمت عمده‌ی کدهای مستقیم کار با بانک‌های اطلاعاتی حذف شده و تبدیل به کدهای دات نتی می‌شوند. مزیت این لایه‌ی Abstraction اضافی (لایه‌ای بر روی کدهای مستقیم لایه ADO.NET زیرین)، امکان تعویض بانک اطلاعاتی مورد استفاده، تنها با تغییر کدهای آغازین برنامه‌است؛ بدون نیاز به تغییری در سایر قسمت‌های برنامه. همچنین کار با اشیاء دات نتی و LINQ، مزایایی مانند تحت نظر قرار گرفتن کدها توسط کامپایلر و برخورداری از ابزارهای Refactoring پیشرفته را میسر می‌کنند. به علاوه SQL خودکار تولیدی توسط آن نیز همواره پارامتری بوده و مشکلات حملات تزریق SQL در این حالت تقریبا به صفر می‌رسند (اگر مستقیما SQL نویسی نکنید و صرفا از LINQ استفاده کنید). مزیت دیگر همواره پارامتری بودن کوئری‌ها، رفتار بسیاری از بانک‌های اطلاعاتی با آن‌ها همانند رویه‌های ذخیره شده است که به عدم تولید Query plan‌های مجزایی به ازای هر کوئری رسیده منجر می‌شود که در نهایت سبب بالا رفتن سرعت اجرای کوئری‌ها و مصرف حافظه‌ی کمتری در سمت سرور بانک اطلاعاتی می‌گردد.


تفاوت EF Core با نگارش‌های دیگر Entity framework در چیست؟

سورس باز بودن
EF از نگارش‌های آخر آن بود که سورس باز شد؛ اما EF Core از زمان نگارش‌های پیش نمایش آن به صورت سورس باز در GitHub قابل دسترسی است.

چند سکویی بودن
EF Core برخلاف EF 6.x (آخرین نگارش مبتنی بر Full Framework آن)، نه تنها چندسکویی است و قابلیت اجرای بر روی Mac و لینوکس را نیز دارا است، به علاوه امکان استفاده‌ی از آن در انواع و اقسام برنامه‌های دات نتی مانند UWP یا Universal Windows Platform و Windows phone که پیشتر با EF 6.x میسر نبود، وجود دارد. لیست این نوع سکوها و برنامه‌های مختلف به شرح زیر است:
 • All .NET application (Console, ASP.NET 4, WinForms, WPF)
 • Mac and Linux applications (Mono)
 • UWP (Universal Windows Platform)
 • ASP.NET Core applications
 • Can use EF Core in Windows phone and Windows store app

افزایش تعداد بانک‌های اطلاعاتی پشتیبانی شده
در EF Full یا EF 6.x، هدف اصلی، تنها کار با بانک‌های اطلاعاتی رابطه‌‌ای بود و همچنین مایکروسافت صرفا نگارش‌های مختلف SQL Server را به صورت رسمی پشتیبانی می‌کرد و برای سایر بانک‌های اطلاعاتی دیگر باید از پروایدرهای ثالث استفاده کرد.
در EF Core علاوه بر افزایش تعداد پروایدرهای رسمی بانک‌های اطلاعاتی رابطه‌ای، پشتیبانی از بانک‌های اطلاعاتی NoSQL هم اضافه شده‌است؛ به همراه پروایدر ویژه‌‌ای به نام In Memory جهت انجام ساده‌تر Unit testing. کاری که با نگارش‌های پیشین EF به سادگی و از روز اول پشتیبانی نمی‌شد.

حذف و یا عدم پیاده سازی تعدادی از قابلیت‌های EF 6.x
اگر موارد فوق جزو مهم‌ترین مزایای کار با EF Core باشند، باید درنظر داشت که به علت حذف و یا تقلیل یافتن یک سری از ویژگی‌ها در NET Core.، مانند Reflection (جهت پشتیبانی از دات نت در سکوهای مختلف کاری و خصوصا پشتیبانی از حالتی که کامپایلر مخصوص برنامه‌های UWP نیاز دارد تمام نوع‌ها را همانند زبان‌های C و ++C، در زمان کامپایل بداند)، یک سری از قابلیت‌های EF 6.x مانند Lazy loading هنوز در EF Core پشتیبانی نمی‌شوند. لیست کامل و به روز شده‌ی این موارد را در اینجا می‌توانید مطالعه کنید.
بنابراین امکان انتقال برنامه‌های EF 6.x به EF Core 1.0 عموما وجود نداشته و نیاز به بازنویسی کامل دارند. هرچند بسیاری از مفاهیم آن با EF Code First یکی است.


برپایی تنظیمات اولیه‌ی EF Core 1.0 در یک برنامه‌ی ASP.NET Core 1.0

برای نصب تنظیمات اولیه‌ی EF Core 1.0 در یک برنامه‌ی ASP.NET Core 1.0، جهت کار با مشتقات SQL Server (و SQL LocalDB) نیاز است سه بسته‌ی ذیل را نصب کرد (از طریق منوی Tools -> NuGet Package Manager -> Package Manager Console):
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer
PM> Install-Package Microsoft.EntityFrameworkCore.Tools -Pre
PM> Install-Package Microsoft.EntityFrameworkCore.SqlServer.Design
البته در این قسمت صرفا از بسته‌ی اول که جهت اتصال به SQL Server است استفاده می‌کنیم. بسته‌های دیگر را در قسمت‌های بعد، برای به روز رسانی اسکیمای بانک اطلاعاتی (مباحث Migrations) و مباحث scaffolding استفاده خواهیم کرد.
پس از اجرای سه دستور فوق، تغییرات مداخل فایل project.json برنامه به صورت ذیل خواهند بود:
{
    "dependencies": {
       // same as before
        "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
        "Microsoft.EntityFrameworkCore.Tools": "1.0.0-preview2-final",
        "Microsoft.EntityFrameworkCore.SqlServer.Design": "1.0.0"
    }
}
این مداخلی که توسط نیوگت اضافه شده‌اند، نیاز به اصلاح دارند؛ به این صورت:
{
    "dependencies": {
       // same as before
        "Microsoft.EntityFrameworkCore.SqlServer": "1.0.0",
        "Microsoft.EntityFrameworkCore.Tools": {
            "version": "1.0.0-preview2-final",
            "type": "build"
        },
        "Microsoft.EntityFrameworkCore.SqlServer.Design": {
            "version": "1.0.0",
            "type": "build"
        }
    },

    "tools": {
       // same as before
        "Microsoft.EntityFrameworkCore.Tools": {
            "version": "1.0.0-preview2-final",
            "imports": [
                "portable-net45+win8"
            ]
        }   
   }
}
نیاز است در قسمت dependencies مشخص کنیم که ابزارهای اضافه شده مخصوص build هستند و نه اجرای برنامه. همچنین قسمت tools را باید با Microsoft.EntityFrameworkCore.Tools مقدار دهی کرد تا بتوان از این ابزار در خط فرمان، جهت اجرای فرامین migrations استفاده کرد.
بنابراین از همین ابتدای کار، بدون مراجعه‌ی به Package Manager Console، چهار تغییر فوق را به فایل project.json اعمال کرده و آن‌را ذخیره کنید؛ تا کار به روز رسانی و نصب بسته‌ها، به صورت خودکار و همچنین صحیحی انجام شود.


فعال سازی صفحات مخصوص توسعه دهنده‌های EF Core 1.0

در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 5 - فعال سازی صفحات مخصوص توسعه دهنده‌ها» با تعدادی از اینگونه صفحات آشنا شدیم. برای EF Core نیز بسته‌ی مخصوصی به نام Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore وجود دارد که امکان فعال سازی صفحه‌ی نمایش خطاهای بانک اطلاعاتی را میسر می‌کند. بنابراین ابتدا به فایل project.json مراجعه کرده و این بسته را اضافه کنید:
{
    "dependencies": {
       // same as before
        "Microsoft.AspNetCore.Diagnostics.EntityFrameworkCore": "1.0.0"
    }
}
سپس می‌توان متد جدید UseDatabaseErrorPage را در متد Configure کلاس آغازین برنامه، فراخوانی کرد:
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
   if (env.IsDevelopment())
   {
      app.UseDatabaseErrorPage();
   }
با فعال سازی این صفحه، اگر در حین توسعه‌ی برنامه و اتصال به بانک اطلاعاتی، خطایی رخ دهد، بجای مشاهده‌ی یک صفحه‌ی خطای عمومی (اگر UseDeveloperExceptionPage را فعال کرده باشید)، اینبار ریز جزئیات بیشتری را به همراه توصیه‌هایی از طرف تیم EF مشاهده خواهید کرد.


تعریف اولین Context برنامه و مشخص سازی رشته‌ی اتصالی آن


در این تصویر، زیر ساخت نگاشت‌های EF Core را مشاهده می‌کنید. در سمت چپ، ظرفی را داریم به نام DB Context که در برگیرنده‌ی Db Setها است. در سمت راست که بیانگر ساختار کلی یک بانک اطلاعاتی است، معادل این‌ها را مشاهده می‌کنیم. هر Db Set به یک جدول بانک اطلاعاتی نگاشت خواهد شد و متشکل است از کلاسی به همراه یک سری خواص که این‌ها نیز به فیلدها و ستون‌های آن جدول در سمت بانک اطلاعاتی نگاشت می‌شوند.
بنابراین برای شروع کار، پوشه‌ای را به نام Entities به پروژه اضافه کرده و سپس کلاس ذیل را به آن اضافه می‌کنیم:
namespace Core1RtmEmptyTest.Entities
{
    public class Person
    {
        public int PersonId { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
    }
}
کلاس Person بیانگر ساختار جدول اشخاص بانک اطلاعاتی است. برای اینکه این کلاس را تبدیل و نگاشت به یک جدول کنیم، نیاز است آن‌را به صورت یک DbSet در معرض دید EF Core قرار دهیم و اینکار در کلاسی که از DbContex مشتق می‌شود، صورت خواهد گرفت:
using Microsoft.EntityFrameworkCore;

namespace Core1RtmEmptyTest.Entities
{
    public class ApplicationDbContext : DbContext
    {
        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        {
        }

        public DbSet<Person> Persons { get; set; }
    }
}
بنابراین در ادامه کلاس جدید ApplicationDbContext را که از کلاس پایه DbContext مشتق می‌شود تعریف کرده و سپس کلاس Person را به صورت یک DbSet در معرض دید EF Core قرار می‌دهیم.
سازنده‌ی این کلاس نیز به نحو خاصی تعریف شده‌است. اگر به سورس‌های EF Core مراجعه کنیم، کلاس پایه‌ی DbContext دارای دو سازنده‌ی با و بدون پارامتر است:
protected DbContext()
   : this((DbContextOptions) new DbContextOptions<DbContext>())
{
}

public DbContext([NotNull] DbContextOptions options)
{
  // …
}
اگر از سازنده‌ی بدون پارامتر استفاده کنیم و برای مثال در کلاس ApplicationDbContext فوق، به طور کامل سازنده‌ی تعریف شده را حذف کنیم، باید به نحو ذیل تنظیمات بانک اطلاعاتی را مشخص کنیم:
using Microsoft.EntityFrameworkCore;

namespace Core1RtmEmptyTest.Entities
{
    public class ApplicationDbContext : DbContext
    {
        public DbSet<Person> Persons { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"... connection string ...");
        }
    }
}
در این حالت باید متد OnConfiguring را override و یا بازنویسی کنیم، تا بتوان از اول مشخص کرد که قرار است از پروایدر SQL Server استفاده کنیم و ثانیا رشته‌ی اتصالی به آن چیست.
اما چون در یک برنامه‌ی ASP.NET Core، کار ثبت سرویس مربوط به EF Core، در کلاس آغازین برنامه انجام می‌شود و در آنجا به سادگی می‌توان به خاصیت Configuration برنامه دسترسی یافت و توسط آن رشته‌ی اتصالی را دریافت کرد، مرسوم است از سازنده‌ی با پارامتر DbContext به نحوی که در ابتدا عنوان شد، استفاده شود.
بنابراین در ادامه، پس از مطالعه‌ی مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 7 - کار با فایل‌های config» به فایل appsettings.json مراجعه کرده و تنظیمات رشته‌ی اتصالی برنامه را به صورت ذیل در آن مشخص می‌کنیم:
{
    "ConnectionStrings": {
        "ApplicationDbContextConnection": "Data Source=(local);Initial Catalog=TestDbCore2016;Integrated Security = true"
    }
}
باید دقت داشت که نام این مداخل کاملا اختیاری هستند و در نهایت باید در کلاس آغازین برنامه به صورت صریحی مشخص شوند.
در اینجا به وهله‌ی پیش فرض SQL Server اشاره شده‌است؛ از حالت اعتبارسنجی ویندوزی SQL Server استفاده می‌شود و بانک اطلاعاتی جدیدی به نام TestDbCore2016 در آن مشخص گردیده‌است.

پس از تعریف رشته‌ی اتصالی، متد OnConfiguring را از کلاس ApplicationDbContext حذف کرده و از همان نگارش دارای سازنده‌ی با پارامتر آن استفاده می‌کنیم. برای اینکار به کلاس آغازین برنامه مراجعه کرده و توسط متد AddDbContext این Context را به سرویس‌های ASP.NET Core معرفی می‌کنیم:
    public class Startup
    {
        public IConfigurationRoot Configuration { set; get; }

        public Startup(IHostingEnvironment env)
        {
            var builder = new ConfigurationBuilder()
                                .SetBasePath(env.ContentRootPath)
                                .AddJsonFile("appsettings.json", reloadOnChange: true, optional: false)
                                .AddJsonFile($"appsettings.{env}.json", optional: true);
            Configuration = builder.Build();
        }

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddSingleton<IConfigurationRoot>(provider => { return Configuration; });
            services.AddDbContext<ApplicationDbContext>(options =>
            {
                options.UseSqlServer(Configuration["ConnectionStrings:ApplicationDbContextConnection"]);
            });
در اینجا جهت یادآوری مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 7 - کار با فایل‌های config» نحوه‌ی وهله سازی خاصیت Configuration که در متد UseSqlServer مورد استفاده قرار گرفته‌است، نیز ذکر شده‌است.
بنابراین قسمت options.UseSqlServer را یا در اینجا مقدار دهی می‌کنید و یا از طریق بازنویسی متد OnConfiguring کلاس Context برنامه.


یک نکته: امکان تزریق IConfigurationRoot به کلاس Context برنامه وجود دارد

با توجه به اینکه Context برنامه را به صورت یک سرویس به ASP.NET Core معرفی کردیم، امکان تزریق وابستگی‌ها نیز در آن وجود دارد. یعنی بجای روش فوق، می‌توان IConfigurationRoot را به سازنده‌ی کلاس Context برنامه نیز تزریق کرد:
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;

namespace Core1RtmEmptyTest.Entities
{
    public class ApplicationDbContext : DbContext
    {
        private readonly IConfigurationRoot _configuration;

        public ApplicationDbContext(IConfigurationRoot configuration)
        {
            _configuration = configuration;
        }

        //public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) : base(options)
        //{
        //}

        public DbSet<Person> Persons { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(_configuration["ConnectionStrings:ApplicationDbContextConnection"]);
        }
    }
}
با توجه به اینکه IConfigurationRoot در کلاس ConfigureServices به صورت Singleton، به مجموعه‌ی سرویس‌های برنامه معرفی شده‌است، از آن در تمام کلاس‌های برنامه که تحت نظر سیستم تزریق وابستگی‌های توکار ASP.NET Core هستند، می‌توان استفاده کرد.
در این حالت متد ConfigureServices کلاس آغازین برنامه، چنین شکلی را پیدا می‌کند و ساده می‌شود:
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>();


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

همینقدر که ApplicationDbContext را به عنوان سرویسی در ConfigureServices تعریف کردیم، امکان تزریق آن در اجزای مختلف یک برنامه‌ی ASP.NET Core نیز وجود دارد:
using System.Linq;
using Core1RtmEmptyTest.Entities;
using Microsoft.AspNetCore.Mvc;

namespace Core1RtmEmptyTest.Controllers
{
    public class TestDBController : Controller
    {
        private readonly ApplicationDbContext _ctx;

        public TestDBController(ApplicationDbContext ctx)
        {
            _ctx = ctx;
        }

        public IActionResult Index()
        {
            var name = _ctx.Persons.First().FirstName;
            return Json(new { firstName = name });
        }
    }
}
در اینجا نحوه‌ی تزریق DB Context برنامه را به یک کنترلر مشاهده می‌کنید. البته هرچند تزریق یک کلاس مشخص به این شکل، تزریق وابستگی‌ها نام ندارد و هنوز این کنترلر دقیقا وابسته‌است به پیاده سازی خاص کلاس ApplicationDbContext، اما ... در کل امکان آن هست.

در این حالت پس از اجرای برنامه، خطای ذیل را مشاهده خواهیم کرد:


علت اینجا است که هنوز این بانک اطلاعاتی ایجاد نشده‌است و همچنین ساختار جداول را به آن منتقل نکرده‌ایم که این موارد را در قسمت‌های بعدی مرور خواهیم کرد.
فایل‌های پروژه‌ها
PdfRpt-2.5.7z
- Updated the project to use iTextSharp 5.5.x
- Fixed 'PDFTemplate FormFlattening removes filled data'.
- Fixed disappearing of the DIV's, during XMLWorker processing.
- Added default font support for XHtmlFooterProvider & XHtmlHeaderProvider.
- Improved UnicodeFontProvider to support default font for HTML documents.
- Improved RtlElementsCollector.
مطالب
اتصال Node.js به SQL Server با استفاده از Edge.js
اگر خواسته باشید که با استفاده از Node.js به SQL Server متصل شوید، احتمالا متوجه شده‌اید ماژولی که مایکروسافت منتشر کرده است، ناقص بوده و به صورت پیش نمایش است که بسیاری از ویژگی‌ها و مسائل مهم، در آن در نظر گرفته نشده است.

یکی دیگر از ماژول‌هایی که امکان اتصال Node.js را به SQL Server ممکن می‌کند، Edge.js است. Edge.js یک ماژول Node.js است که امکان اجرای کدهای دات نت را در همان پروسه توسط Node.js فراهم می‌کند. این مسئله، توسعه دهندگان Node.js را قادر می‌سازد تا از فناوری‌هایی که به صورت سنتی استفاده‌ی از آنها سخت یا غیر ممکن بوده است را به راحتی استفاده کنند. برای نمونه:
  • SQL Server
  • Active Directory
  • Nuget packages
  • استفاده از سخت افزار کامپیوتر (مانند وب کم، میکروفن و چاپگر)


نصب Node.js

اگر Node.js را بر روی سیستم خود نصب ندارید، می‌توانید از اینجا آن را دانلود کنید. بعد از نصب برای اطمینان از کارکرد آن، command prompt را باز کرده و دستور زیر را تایپ کنید:

node -v
شما باید نسخه‌ی نصب شده‌ی Node.js را مشاهده کنید.

ایجاد پوشه پروژه

سپس پوشه‌ای را برای پروژه Node.js خود ایجاد کنید. مثلا با استفاده از command prompt و دستور زیر:

md \projects\node-edge-test1
cd \projects\node-edge-test1

نصب Edge.js

Node با استفاده از package manager خود دانلود و نصب ماژول‌ها را خیلی آسان کرده است. برای نصب، در command prompt عبارت زیر را تایپ کنید:

npm install edge
npm install edge-sql
فرمان اول باعث نصب Edge.js و دومین فرمان سبب نصب پشتیبانی از SQL Server می‌شود.

Hello World

ایجاد یک فایل متنی با نام server.js و نوشتن کد زیر در آن:
var edge = require('edge');

// The text in edge.func() is C# code
var helloWorld = edge.func('async (input) => { return input.ToString(); }');

helloWorld('Hello World!', function (error, result) {
    if (error) throw error;
    console.log(result);
});
حالا برای اجرای این Node.js application از طریق command prompt کافی است به صورت زیر عمل کنید:
node server.js
همانطور که مشاهده می‌کنید "!Hello World" در خروجی چاپ شد.

ایجاد پایگاه داده تست

در مثال‌های بعدی، نیاز به یک پایگاه داده داریم تا query‌ها را اجرا کنیم. در صورتی که SQL Server بر روی سیستم شما نصب نیست، می‌توانید نسخه‌ی رایگان آن را از اینجا دانلود و نصب کنید. همچنین SQL Management Studio Express را نیز نصب کنید.

  1. در SQL Management Studio، یک پایگاه داده را با نام node-test با تنظیمات پیش فرض ایجاد کنید.
  2. بر روی پایگاه داده node-test راست کلیک کرده و New Query را انتخاب کنید.
  3. اسکریپت زیر را copy کرده و در آنجا paste کنید، سپس بر روی Execute کلیک کنید.
IF EXISTS(SELECT 1 FROM sys.tables WHERE object_id = OBJECT_ID('SampleUsers')) BEGIN; DROP TABLE SampleUsers; END; GO

CREATE TABLE SampleUsers ( Id INTEGER NOT NULL IDENTITY(1, 1), FirstName VARCHAR(255) NOT NULL, LastName VARCHAR(255) NOT NULL, Email VARCHAR(255) NOT NULL, CreateDate DATETIME NOT NULL DEFAULT(getdate()), PRIMARY KEY (Id) ); GO

INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Orla','Sweeney','nunc@convallisincursus.ca','Apr 13, 2014');
INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Zia','Pickett','porttitor.tellus.non@Duis.com','Aug 31, 2014');
INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Justina','Ayala','neque.tellus.imperdiet@temporestac.com','Jul 28, 2014');
INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Levi','Parrish','adipiscing.elit@velarcueu.com','Jun 21, 2014');
INSERT INTO SampleUsers(FirstName,LastName,Email,CreateDate) VALUES('Pearl','Warren','In@dignissimpharetra.org','Mar 3, 2014');
نتیجه‌ی اجرای کد بالا، ایجاد جدولی با نام SampleUsers و درج 5 رکورد در آن می‌شود.

تنظیمات ConnectionString

قبل از استفاده از Edge.js با SQL Server، باید متغیر محیطی (environment variable) با نام EDGE_SQL_CONNECTION_STRING را تعریف کنید.

set EDGE_SQL_CONNECTION_STRING=Data Source=localhost;Initial Catalog=node-test;Integrated Security=True
این متغیر تنها برای command prompt جاری تعریف شده است و با بستن آن از دست می‌رود. در صورتیکه از Node.js Tools for Visual Studio استفاده می‌کنید، نیاز به ایجاد یک متغیر محیطی دائمی و راه اندازی مجدد VS دارید. همچنین در صورتیکه بخواهید متغیر محیطی دائمی ایجاد کنید، فرمان زیر را اجرا کنید:
SETX EDGE_SQL_CONNECTION_STRING "Data Source=localhost;Initial Catalog=node-test;Integrated Security=True"


روش اول: اجرای مستقیم SQL Server Query در Edge.js

فایلی با نام server-sql-query.js را ایجاد کرده و کد زیر را در آن وارد کنید:

var http = require('http');
var edge = require('edge');
var port = process.env.PORT || 8080;

var getTopUsers = edge.func('sql', function () {/*
    SELECT TOP 3 * FROM SampleUsers ORDER BY CreateDate DESC
*/});

function logError(err, res) {
    res.writeHead(200, { 'Content-Type': 'text/plain' });
    res.write("Error: " + err);
    res.end("");
}    

http.createServer(function (req, res) {
    res.writeHead(200, { 'Content-Type': 'text/html' });

    getTopUsers(null, function (error, result) {
        if (error) { logError(error, res); return; }
        if (result) {
            res.write("<ul>");
            result.forEach(function(user) {
                res.write("<li>" + user.FirstName + " " + user.LastName + ": " + user.Email + "</li>");
            });
            res.end("</ul>");
        }
        else {
        }
    });
}).listen(port);
console.log("Node server listening on port " + port);
سپس با استفاده از command prompt، فرمان زیر را اجرا کنید:
node server-sql-query.js
حال مرورگر خود را باز و سپس آدرس http://localhost:8080 را باز کنید. در صورتی که همه چیز به درستی انجام گرفته باشد لیستی از 3 کاربر را خواهید دید.

روش دوم: اجرای کد دات نت برای SQL Server Query

Edge.js تنها از دستورات Update، Insert، Select و Delete پشتیبانی می‌کند. در حال حاضر از store procedures و مجموعه‌ای از کد SQL پشتیبانی نمی‌کند. بنابراین، اگر چیزی بیشتر از عملیات CRUD می‌خواهید انجام دهید، باید از دات نت برای این کار استفاده کنید.

یادتان باشد، همیشه async

مدل اجرایی Node.js به صورت یک حلقه‌ی رویداد تک نخی است. بنابراین این بسیار مهم است که کد دات نت شما به صورت async باشد. در غیر اینصورت یک فراخوانی به دات نت سبب مسدود شدن و ایجاد خرابی در Node.js می‌شود.

ایجاد یک Class Library

اولین قدم، ایجاد یک پروژه Class Library در Visual Studio که خروجی آن یک فایل DLL است و استفاده از آن در Edge.js است. پروژه Class Library با عنوان EdgeSampleLibrary ایجاد کرده و فایل کلاسی با نام Sample1 را به آن اضافه کنید و سپس کد زیر را در آن وارد کنید:

using System;
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using System.Threading.Tasks;

namespace EdgeSampleLibrary
{
     public class Sample1
    {
        public async Task<object> Invoke(object input)
        {
            // Edge marshalls data to .NET using an IDictionary<string, object>
            var payload = (IDictionary<string, object>) input;
            var pageNumber = (int) payload["pageNumber"];
            var pageSize = (int) payload["pageSize"];
            return await QueryUsers(pageNumber, pageSize);
        }

        public async Task<List<SampleUser>> QueryUsers(int pageNumber, int pageSize)
        {
            // Use the same connection string env variable
            var connectionString = Environment.GetEnvironmentVariable("EDGE_SQL_CONNECTION_STRING");
            if (connectionString == null)
                throw new ArgumentException("You must set the EDGE_SQL_CONNECTION_STRING environment variable.");

            // Paging the result set using a common table expression (CTE).
            // You may rather do this in a stored procedure or use an 
            // ORM that supports async.
            var sql = @"
DECLARE @RowStart int, @RowEnd int;
SET @RowStart = (@PageNumber - 1) * @PageSize + 1;
SET @RowEnd = @PageNumber * @PageSize;

WITH Paging AS
(
    SELECT  ROW_NUMBER() OVER (ORDER BY CreateDate DESC) AS RowNum,
            Id, FirstName, LastName, Email, CreateDate
    FROM    SampleUsers
)
SELECT  Id, FirstName, LastName, Email, CreateDate
FROM    Paging
WHERE   RowNum BETWEEN @RowStart AND @RowEnd
ORDER BY RowNum;
";
            var users = new List<SampleUser>();

            using (var cnx = new SqlConnection(connectionString))
            {
                using (var cmd = new SqlCommand(sql, cnx))
                {
                    await cnx.OpenAsync();

                    cmd.Parameters.Add(new SqlParameter("@PageNumber", SqlDbType.Int) { Value = pageNumber });
                    cmd.Parameters.Add(new SqlParameter("@PageSize", SqlDbType.Int) { Value = pageSize });

                    using (var reader = await cmd.ExecuteReaderAsync(CommandBehavior.CloseConnection))
                    {
                        while (await reader.ReadAsync())
                        {
                            var user = new SampleUser
                            {
                                Id = reader.GetInt32(0), 
                                FirstName = reader.GetString(1), 
                                LastName = reader.GetString(2), 
                                Email = reader.GetString(3), 
                                CreateDate = reader.GetDateTime(4)
                            };
                           users.Add(user);
                        }
                    }
                }
            }
            return users;
        } 
    }

    public class SampleUser
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Email { get; set; }
        public DateTime CreateDate { get; set; }
    }
}
سپس ذخیره و کامپایل کنید. فایل DLL خروجی که در مسیر
[project]/bin/Debug/EdgeSampleLibrary.dll
قرار دارد را در پوشه‌ی پروژه Node کپی کنید. فایل جدیدی را با نام server-dotnet-query.js در پروژه Node ایجاد کنید و کد زیر را در آن وارد کنید:
var http = require('http');
var edge = require('edge');
var port = process.env.PORT || 8080;

// Set up the assembly to call from Node.js 
var querySample = edge.func({ assemblyFile: 'EdgeSampleLibrary.dll', typeName: 'EdgeSampleLibrary.Sample1', methodName: 'Invoke' });

function logError(err, res) { res.writeHead(200, { 'Content-Type': 'text/plain' }); res.write("Got error: " + err); res.end(""); }

http.createServer(function (req, res) { res.writeHead(200, { 'Content-Type': 'text/html' });

    // This is the data we will pass to .NET
    var data = { pageNumber: 1, pageSize: 3 };

    // Invoke the .NET function
    querySample(data, function (error, result) {
        if (error) { logError(error, res); return; }
        if (result) {
            res.write("<ul>");
            result.forEach(function(user) {
                res.write("<li>" + user.FirstName + " " + user.LastName + ": " + user.Email + "</li>");
            });
            res.end("</ul>");
        }
        else {
            res.end("No results");
        }
    });

}).listen(port);

console.log("Node server listening on port " + port);
سپس از طریق command prompt آن را اجرا کنید:
node server-dotnet-query.js
حال مرورگر خود را باز کرده و به آدرس http://localhost:8080 بروید. در صورتیکه همه چیز به درستی انجام گرفته باشد، لیستی از 3 کاربر را خواهید دید. مقادیر pageNumber و pageSize را در فایل جاوااسکریپت تغییر دهید و تاثیر آن را بر روی خروجی مشاهده کنید.
 
نکته: برای ایجاد pageNumber و pageSize داینامیک با استفاده از ارسال مقادیر توسط QueryString، می‌توانید از ماژول connect استفاده کنید.
مطالب
Pro Agile .NET Development With Scrum - قسمت اول
 با همکاری آقایان سید مجتبی حسینی و محمد شریفی طی یک سری مقالات سریالی قصد داریم ترجمه آزادی از کتاب  Pro Agile .NET Development With Scrum نوشته Jerrel Blankenship  و Matthew Bussa ، داشته باشیم. 
با توجه به اینکه در سایت جاری مطالب قسمت اول کتاب پوشش داده شده است، ما هم دوباره کاری نکرده و میتوانید از این مقاله استفاده کنید.

مدیریت پروژه‌های چابک با اسکرام
در این فصل با روشها و ماهیت تکرارپذیر اسکرام آشنا می‌شوید که استخوان‌بندی فرآیندی را تعریف می‌کند که دربردارندۀ  مجموعه‌ای از نقشها و فعالیتهایی است که همگی بر پشتیبانی از تیم مسؤول تولید محصول، تمرکز می‌کنند. 
مطالعۀ موردی بخش دوم این کتاب از شیوۀ اسکرام به نحوی پیروی می‌کند که قادر به دیدن اجرایی عملی از تمام ویژگیهای کلیدی‌ای که در این فصل از آنها بحث می‌شود، خواهید بود و به شما کمک می‌کند تا مزیت‌های این شیوه را به خوبی درک کنید.
اسکرام چیست؟
اسکرام رویکردی تکرارپذیر جهت توسعۀ نرم‌افزار است که بصورت تنگاتنگی با اصول و بیانیۀ چابک هم‌سو شده است. اسکرام از دنباله‌ای از بلاکهای زمانی به نام اسپرینت ساخته شده است که بر ارائۀ محصولات کارآمد تمرکز می‌کند. یک اسپرینت نوعاً از دو تا چهار هفته به طول می‌انجامد و با هدف یا موضوعی که واضح کنندۀ اسپرینت است، تعریف شده است.
اسپرینتها نسبت به تغییرات ایزوله شده‌اند و بدون هیچ اختلالی، تیم توسعه را بر ارائۀ محصولی کارآمد، متمرکز می‌سازند. کارها در Product   Backlog ( لیستی از کارهای کلی یک پروژه است که باید آن را بر اساس درجه اهمیت، دسته بندی نمود) اولویت‌بندی شده که توسط صاحب محصول مدیریت می‌شود. قبل از وقوع هر اسپرینت، یک ویژگی از Product Backlog  انتخاب شده و تیم توافق می‌کند که در انتهای آن اسپرینت، آن ویژگی را ارائه کند.
برای آنکه همه چیز بخوبی پیش برود، یک نفر به عنوان ScrumMaster (که وظیفه نگهداری و حفظ فرآیند را برعهده دارد) تعیین می‌شود تا اطمینان حاصل شود که هیچ مانعی باعث جلوگیری از ارائۀ ویژگیهایی که تیم توسعه مد نظر قرار داده، نشود. جلسات سرپایی روزانه به تیم کمک می‌کند تا دربارۀ هر مشکلی که مانع کار است، گفتگو کنند. مرور هر اسپرینت در انتهای آن به ارتقای فرآیند کمک می‌کند.
شکل 1-2 نمایش گرافیکی روش اسکرام است که حاوی همۀ نقشها و فعالیتها و خروجیهای اسکرام بوده که در ادامه، بیشتر دربارۀ آنها خواهید خواند. 
 




  شیوه‌های برنامه محور در مقابل شیوه‌های ارزش محور
هنگام ملاحظۀ تفاوت میان شیوۀ آبشاری و شیوۀ چابک، نیاز است تا به هستۀ مرکزی هر روش نگریست. یکی از شیوه‌ها از نقشه‌ای برگرفته شده که در ابتدای پروژه ایجاد شده است و شیوۀ دیگر از ارزشی برگرفته شده که شما به مشتری می‌دهید.

شیوۀ آبشاری (برنامه محور)
به شیوۀ آبشاری می‌توان به منزلۀ شیوه‌ای برنامه محور در توسعۀ نرم‌افزار نگریست. در گذشته، این شیوۀ توسعه بسیار مورد استفاده بود، نه به این دلیل که بهترین شیوۀ توسعۀ نرم‌افزار بود، بلکه به این دلیل که تنها شیوۀ شناخته شده بود.
پروژه‌ای که شیوۀ آبشاری را به کار می‌برد با ریسک بسیار بالایی مواجه بود؛ به این دلیل که همه چیز در ابتدای پروژه طرح‌ریزی می‌شد. تمام نیازمندیها و جستجوها و تعیین بازۀ کاری قبل از آنکه حتی یک خط کد نوشته شود، جمع‌آوری می‌شد. مشتریان باید همۀ آنچه را که از سیستم انتظار داشتند، در ابتدای امر می‌دانستند. در زمانی که مشتریان دقیقاً نمی‌دانستند که چه می‌خواهند اما باید تمام جزئیات نیازهای خود را تعریف می‌کردند و در یک وهله باید جزئیات کار را تعیین می‌کردند و تا آخر نیز نمی‌توانستند آن را تغییر دهند؛ حتی اگر بعداً متوجه می‌شدند که نیازشان تغییر کرده است.
این رویکرد سرانجام پروژه را، حتی قبل از آنکه شروع شود، با شکست مواجه می‌کرد. کل فرآیند به سمت مشکلاتی هدایت می‌شد که تا پایان پروژه نیز پنهان می‌ماندند. زیرا مشتری همۀ نکات جزئی کار را مدنظر قرار نداده بود و راهی برای تغییرات مورد نیاز وجود نداشت. گاهی انجام تغییر مستلزم هزینۀ بسیار بالایی بود. در این گونه پروژه‌ها دامنۀ پروژه دچار تغییرات می‌شد؛  توسعه‌دهنده از مسائلی که مشتری درصدد حل آنها بود سردرنمی‌آورد و به همین ترتیب مشتری.
توسعۀ برنامه محور به مانند روند پرش حلقه‌ای است: شما ابتدا جستجو می‌کنید و یک مرتبه از میان آن حلقه پریده و وارد حلقۀ جمع‌آوری نیازمندیها می‌شوید و از آنجا وارد حلقۀ طراحی می‌شوید. از یک حلقه نمی‌توانید عبور کنید مگر اینکه از حلقۀ پیشین آن پریده باشید و با یک مرتبه، عبور از یک حلقه برگشتن به آن حلقه ممکن نیست. حتی اگر نیاز باشد چنین کاری انجام شود. ممکن نیست که اندکی از هر کاری را انجام داده و برای اطمینان از مسیر درست، قدری متوقف بمانید. فرآیند آبشاری فراهم کنندۀ بستری نیست که در آن توسعه دهند بتواند به مشتری خود بگوید: «مایل هستم که کاری را که تاکنون انجام داده‌ام، به شما نشان دهم تا ببینید که آیا با آنچه شما می‌خواهید منطبق است یا خیر».
معمولاً در انتهای پروژه است که مشکلات بزرگی بروز پیدا می‌کنند که نسبتاً خیلی دیر است. این مورد منجر به آن می‌شود که چند تیم به کار وارد شده و افراد بیشتری در پروژه استفاده شوند؛ به این امید که پروژه سریعتر به اتمام برسد و البته چنین نتیجه‌ای به ندرت اتفاق می‌افتد. در نتیجه بخشهایی از پروژه باید کنار گذاشته شوند؛ یعنی یا حدود پروژه محدودتر شود، یا آزمودن آن حذف شود یا هردو.

شیوۀ اسکرام (ارزش محور)
اسکرام به عنوان شیوه‌ای ارزش محور در توسعۀ نرم‌افزار مورد توجه قرار می‌گیرد. اسکرام به چند دلیل تغییر چشم‌گیری نسبت به شیوۀ آبشاری داشته‌است.  اسکرام به جای آنکه در ابتدا به جمع‌آوری نیازمندیهای مورد نیاز برای هر ویژگی مد نظر پروژه بپردازد و به جای آنکه همۀ طراحی‌های خود را مبتنی بر این نیازمندیها کامل کرده و سپس به کدنویسی برنامه مبتنی بر این طرحهای از اول مشخص شده بپردازد؛ به توسعۀ تکرارپذیر و افزایشی می‌نگرد.
اسکرام تماماً معطوف به مسیرهایی جزئی در حل مسأله و ارزیابی مجدد آن مسأله پس از طی هر مسیر است.
  • بلاکهای جزئی با عنوان اسپرینت
  • ویژگیهای جزئی
  • تیم‌های کوچک
بلاکهای زمانی کوچک بیانگر چگونگی کار بر روی حل مسأله توسط تیم توسعه است. به هر اسپرینت می‌توان به صورت یک پروژۀ آبشاری کوچک نگریست. زیرا در هر اسپرینت شما همۀ کارهایی را که به طور عادی در یک پروژۀ آبشاری انجام می‌دهید، اجرا می‌کنید با این تفاوت که فقط در مقیاسی کوچک‌تر آن را انجام می‌دهید. در هر اسپرینت، شما یک ویژگی را انتخاب کرده و نیازمندیهای آن ویژگی را جمع‌آوری کرده و به طراحی آن ویژگی مبتنی بر نیازمندیهای به دست‌آمده پرداخته و سپس کدنویسی کرده و آن خصیصه را با توجه به طراحی صورت گرفته، تست می‌کنید. شما در اسکرام برخلاف روش آبشاری، تلاش نمی‌کنید که همه چیز را پیشاپیش طراحی کنید. بلکه شما چیزی را انجام می‌دهید که نیاز است انجام شود. هدف هر اسپرینت انجام ارتقایی (افزایشی) برای رسیدن به پروژۀ نهایی است؛ اما افزایشی که به طور بالقوه قابل ارائه است.
حال چگونه می‌توان در هر اسپرینت تعداد زیادی پروژه‌های آبشاری را انجام داد، در حالی که قبلاً به سختی یک پروژۀ آبشاری قابل انجام بود؟ جواب، انجام اسپرینتهایی با ویژگیهای کوچک است. ویژگیهای جزئی‌، قطعاتی از پروژه هستند که تلاش می‌کنند مسألۀ خاصی را برای مشتری حل کنند. آنها درصدد این نیستند که کل برنامه را ایجاد کنند. ویژگیهای مدنظر یک پروژه به تکه‌های کوچکتری شکسته می‌شوند که هنوز قادر به تامین ارزش برای مشتری بوده و می‌توان آنها را به سرعت انجام داد. با هرچه بیشتر شدن این ویژگیهای کامل شده در پروژه، مشتری کم کم با نمای کامل برنامه مورد نظر مواجه شده و آن را ملاحظه می‌کند.
همه‌ی این موارد توسط یک تیم کوچکی از توسعه‌دهندگان، تست‌کننده‌ها و طراحانی که صرفاً به انجام پروژه مشغول هستند، انجام می‌شود. این تیم، یک تیم با قابلیت‌هایی چندگانه است که هر عضو آن با انجام تمام کارهای تیم آشناست. هر عضوی از آن ممکن است که در همه چیز بهترین نباشد؛ اما هرکس می‌داند که چگونه یک کار ضروری را برای تکمیل پروژه انجام دهد. نگریستن به آنها به عنوان یک تیم SEAL  که هر عضو آن می‌داند که چگونه هرچیز مورد نیاز را انجام دهد، اما برای هرکاری کارشناسان مخصوص آن کار وجود دارد.
با انجام این کار در سطوح جزئی، مسائل این سطوح جزئی تا حدی شبیه مسائلی هستند که در انتهای پروژه در شیوۀ آبشاری رخ می‌دهند. در واقع اسکرام به گونه‌ای کار می‌کند که بتواند تا آنجا که ممکن است سریعاً مشکلات و مسائل را نشان دهد. مشکلات قابل پنهان شدن نیستند؛ چراکه پروژه به سطوحی کوچک و قابل مدیریت، تجزیه شده است. هنگامیکه مشکلی بروز پیدا می‌کند، تا وقت پیدا شدن راه حل و حل شدن آن، موجبات دردسر تیم را فراهم می‌کند و آنها نمی‌توانند از مسأله چشم‌پوشی کنند، چون برای همه قابل رؤیت است.
نکتۀ بسیارمهمی را باید دربارۀ اسکرام فهمید و آن اینکه اسکرام مشکلات را هرچه زودتر، به تیم نشان می‌دهد؛ اما آنها را حل نمی‌کند. 
اسکرام نه تنها ویژگیهایی را برای نمایش به مشتری توسط تیمهای فروش و بازاریابی تولید می‌کند، بلکه راه‌حلهایی را نیز به مشتری ارائه می‌دهد. چنین امری با اولویت‌بندی خصوصیت‌ها مطابق نیاز و خواسته‌های مشتری، صورت می‌گیرد. اگر مشتری‌ای تصور کند که ویژگی A باید از ویژگی B بسیار مهم‌تر باشد و توسعه دهنده، وقت زیادی را بر سر ویژگی B قبل از ویژگی A صرف کند، نمی‌تواند به نیاز مشتری به نحو مطلوبی، پاسخ‌گو باشد.

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



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

محصولات اسکرام
اسکرام سه خروجی دارد:
  1.  product backlog : مجموعه‌ای اولویت بندی شده از نیازمندی‌های سطح بالای سیستمی که در نهایت بایستی تحویل داده شود.
  2. sprint backlog : مواردی از  product backlog که قرار است در یک sprint انجام شوند.
  3. نمودار burn-down :هدف نمودار burn-down، نمایش روند پیشرفت پروژه به صورت نموداری به اعضای تیم توسعه است که حاوی اطلاعاتی دربارۀ کل زمان انجام کار، زمان تخمین‌زده شده، مقدار کارانجام شده و عقب‌ماندگی‌های پروژه است.
این خروجی‌ها، محصولات فعالیت‌های اسکرام هستند و به تیم در جهت‌یابی و شفافیت کار کمک می‌کنند. افزون بر این خروجی‌های اصلی خروجی‌های فرعی‌ای نیز از قبیل معیار پذیرش (الزاماتی که باید در حل یک مسأله برآورده شود تا بتوان آن را کامل شده تلقی کرد) وجود دارد.

Product Backlog
product backlog لیستی از همه کارهای باقی‌مانده در یک پروژه است که باید انجام شوند. این لیست نمایانگر نیازمندیها و خواسته‌های مشتری است. در قلب این لیست «داستان کاربر (user story)» یعنی مؤلفۀ کلیدی اسکرام قرار دارد. این مؤلفه تعیین‌کنندۀ ملاک افزایش ارزش در نزد مشتری بوده و آن چیزی است که توسعه دهنده تلاش می‌کند، ارائه نماید و توسط صاحب محصول (product owner) (یعنی کسی که نسبت به افزودن یا حذف داستان کاربر (user story)‌ها به لیست، پاسخ‌گو است) مدیریت می‌شود. product backlog به طور دائم توسط صاحب محصول و مشتری اولویت‌بندی می‌شود. این اولویت‌بندی دائمی امری کلیدی برای اسکرام است. این امر تضمین می‌کند که داستان کاربر (user story) که تعیین‌کنندۀ بیشترین ارزش برای مشتریست، در صدر product backlog قرار گرفته باشد. با افزوده شدن یک داستان کاربر (user story) این مورد با سایر داستان‌های کاربر (user storyهای) پیشین مقایسه شده تا مشخص شود که در چه سطح ارزشی‌ای از نظر مشتری قراردارد. در طول یک اسپرینت، داستان کاربر (user storyها) را می‌توان به اسپرینت اضافه کرد. اما تا کامل شدن اسپرینت جاری، به تیم توسعه نشان داده نمی‌شود.

User Stories
همانطور که خاطرنشان شد، product backlog چیزی بیش از یک لیست اولویت‌بندی شده از داستان‌های کاربر (user storyها) نیست. یک داستان کاربر (user story)، یک کارت است که ارزش اضافه‌ای را برای مشتری توصیف می‌کند. داستان کاربر (user story) برای توسعه‌دهنده به منظور بیان ارزشی اضافه نوشته می‌شود. نکتۀ کلیدی یک داستان کاربر (user story) خوب، این است که داستان کاربر (user story) بخشی عمودی از لیست است و بخش افقی ویژگی‌ای است که فقط به یک سطح، مانند سطح بانک اطلاعات یا سطح رابط کاربری اثر می‌گذارد. به عبارت دیگر قطعۀ عمودی تمام سطوح را آن گونه که در شکل 3-2 نشان داده شده، متاثر می‌سازد. این کوچکترین مقدار کاری است که تمام سطوح یک محصول را تحت تاثیر قرارداده و برای مشتری ارزش ایجاد می‌کند. با نوشتن داستان‌های کاربر (user storyها) به گونه‌ای که در بخشهای عمودی جایز است، می‌توان قابلیت پایه‌ای را در اولین داستان کاربر (user story) ایجاد کرده و سپس به سادگی قابلیتی به این ویژگی به عنوان نیازهای مشتری اضافه کرد.


یک شیوۀ اطمینان از اینکه داستان کاربر (user story) فایدۀ قطعۀ عمودی بودن در یک سیستم را داراست این است که مطمئن شویم با «INVEST» منطبق است. «INVEST» عبارت است از مخفف: 
  • مستقل (Independent): باید خودبسنده باشد و به سایر داستانها وابسته نباشد.
  • قابل مذاکره (Negotiable): داستانهای کاربری که بخشی از یک اسپرینت هستند همیشه قابل تغییر و بازنویسی هستند.
  • با ارزش (Valuable): یک داستان کاربر باید به کاربر نهایی، ارزشی را ارائه دهد.
  • قابل برآورد (Estimable): همیشه باید بتوان اندازۀ داستان کاربر را تخمین زد.
  • اندازۀ مناسب (Sized appropriately): داستانهای کاربر نباید آن قدر بزرگ باشند که تبدیلشان به یک طرح یا وظیفه یا امر اولویت‌بندی شده با درجۀ مشخصی ممکن نباشد.
  • قابل آزمون (Testable): داستان کاربر یا توصیفات مربوط به آن باید اطلاعات ضروری برای آزمودن آن را فراهم کنند.

تعیین اندازۀ backlog
تعیین اندازۀ product backlog  عبارت است از اندازه‌گیری سرعتی که تیم اسکرام می‌تواند مؤلفه‌های آن را ارائه کند. افراد در تخمین کار خوب عمل نمی‌کنند. همگی می‌دانیم که در تخمین دقیق اینکه چقدر طول می‌کشد تا یک کار را به طور کامل انجام دهیم، تا چه اندازه بد عمل می‌کنیم. تا کنون چند مرتبه این اتفاق افتاده است که از کسی بشنویم یا به خودمان بگوییم که 80 درصد کار را انجام داده‌ام و 20 درصد باقی‌ماندۀ آن در یک ساعت انجام خواهد شد. اما هنوز بعد از دو روز انجام نشده است. افراد به طور طبیعی بد تخمین می‌زنند.
ما ممکن است در تخمین زدن خوب نباشیم؛ اما در مقایسه کردن اشیاء با یکدیگر عالی هستیم. به عنوان مثال قادریم که با نگاه انداختن به دو دستور پخت غذا تشخیص دهیم که کدام‌یک پیچیده‌تر از دیگری است؛ بدون آنکه تخصصی در آشپزی داشته باشیم. به دو چیز نگاه می‌کنیم و تشخیص می‌دهیم که کدام‌یک بزرگتر از دیگری است. تخمین اندازۀ backlog تماماً یعنی تصمیم‌گیری دربارۀ پیچیدگی و مقدار کار لازم، نه اینکه چقدر طول می‌کشد تا این کار انجام شود. تخمین اندازه با تخمین برابر نیست.
ممکن است بپرسید که چگونه می‌توان زمان انجام برخی چیزها را اندازه گرفت؟ مدیری را در نظر بگیرید که می‌خواهد بداند چقدر طول می‌کشد تیم شما یک widget را تولید کند. شما می‌توانید تخمین زمان کامل شدن widget  را از پیچیدگی widget تخمین بزنید. شما می‌توانید وقتی که تیم از یک اسپرینت فارغ شد، به آن اسپرینت نگاه کرده و محاسبه کنید که چقدر طول می‌کشد تا کار کامل شود. فقط پیچیدگی یک وظیفه‌ی مورد توجه تیم است.
اجازه دهید برای توضیح بهتر چگونگی تخمین مقدار کار مورد نیاز برای کامل شدن کار، این مسأله را با رنگ‌آمیزی خانه‌تان مقایسه کنیم. شما به فروشگاه رنگ فروشی رفته و چند سطل رنگ را برای رنگ‌آمیزی خانه می‌خرید. سپس از سه پیمانکار می‌خواهید که انجام این کار را برای شما تخمین بزنند. اولین پیمانکار به خانه‌ی شما آمده و دور خانه قدم زده و به سطلهای رنگی که خریده‌اید نگاه کرده  و می‌گوید که وی با یک نردبان زنگ زده و برس‌های دستی و پسرکی لاغراندام به عنوان دستیارش، این کار را در ظرف دو روز انجام می‌دهد.
دومین پیمانکار دور خانه قدم زده و به سطلها نگریسته و می‌گوید که به تازگی نردبان و برس‌هایی خریداری کرده است و تیم محلی فوتبال در آخر هفته به وی کمک خواهند کرد. با این دستیاران و تجهیزات جدید، انجام این کار فقط یک روز به طول می‌انجامد.
سومین پیمانکار دور خانه قدم زده و به رنگها نگریسته و می‌گوید که وی صاحب یک دستگاه مکانیکی رنگ‌آمیزی است که باعث می‌شود انجام این کار حدود یک ساعت وقت بگیرد.
شما دربارۀ این ماجرا و سه نوع تخمین از رنگ‌آمیزی خانه، چگونه فکر می‌کنید در صورتی که در هیچ کدام از این سه وضعیت، نه ابعاد خانه تغییری کرده است و نه مقدار رنگی که شما خریداری کرده‌اید.  نکتۀ این داستان در این است که بهترین چیزی که شما می‌توانید انجام دهید تخمین مدت زمان انجام کار نیست؛ بلکه به جای آن باید مقدار تلاشی را که منجر به اتمام کار خواهد شد، تخمین زد. با تخمین مقدار کار می‌توان مدت زمان انجام کار را به دست آورد.

Sprint Backlog
sprint backlog لیستی از همۀ کارهای باقی‌مانده در یک اسپرینت است و باید توسط تیم انجام شود. sprint backlog زیرمجموعه‌ای از product backlog است. product backlog همۀ داستانهای کاربران را که برای product مانده لیست می‌کند؛ اما sprint backlog حاوی همه‌ی داستان‌ها و وظایف باقی‌مانده برای اسپرینت است. نوعاً هنگامی که یک داستان کاربر برای یک اسپرینت انتخاب می‌شود، تیم، آن داستان کاربر را به تعدادی وظیفه تقسیم می‌کند.
یک وظیفه، تکۀ کوچکی از داستان کاربر است که توسط هر عضو تیم قابل انجام است. مثلاً وظایفی از قبیل اجرای تغییرات بر روی بانک اطلاعاتی مورد نیاز یک داستان کاربر یا وظیفۀ اجرای UI برای داستان کاربر. وظایفی که بر روی تابلوی وظایف – که با عنوان Kanban (معادل ژاپنی بیلبورد) نیز شناخته می‌شود- برای همۀ تیم قابل رؤیت است. سایر مؤلفه‌های روی این تخته به همان ترتیب، حاوی اطلاعاتی دربارۀ قرار ملاقاتهای جمع‌آوری نیازمندیها، کنترلهای بازبینی، تحقیقات، آزمون، طراحی و مراحل کد نویسی هستند. شکل 4-2 یک مثال را نشان می‌دهد.
اعضای تیم یک کارت از تخته برداشته و در طول اسپرینت اقدام به انجام وظیفه‌ای که روی کارت توصیف شده، می‌نمایند. در خلال مدتی که تیم بر روی وظایف کار می‌کند، سایر وظایف بروز پیدا کرده و تخمینهای اصلی مجدداً تنظیم می‌شوند. همۀ اعضای تیم، در قبال به روز رسانی تابلو بر طبق اطلاعات جدید مقید خواهند بود.

شکل 4-2 نمونه‌ای از تابلوی Kaban با یک sprint backlog


sprint backlog اطلاعات مورد نیاز نمودار burn-down را فراهم می‌کند. در پایان هر اسپرینت، sprint backlog خالی می‌شود. هر آیتم باقی مانده‌ای در backlog به product backlog برگردانده شده و مجدداً در کنار سایر داستانهای کاربری موجود در product backlog بعلاوۀ داستانهای کاربری تازه وارد شده، اولویت‌بندی می‌شود. 

Burn-down chart
نمودار burn-down شیوه‌ای بصری برای دنبال کردن چگونگی پیش‌روی یک اسپرینت است. این نمودار کار باقیماندۀ اسپرینت را در هر روز، به صورت گرافیکی همانند شکل 5-2 نشان می‌دهد. معمولاً این نمودار در یک محیط عمومی نمایش داده می‌شود تا هرکسی بتواند آن را ببیند. این کار به ارتباطات میان اعضای تیم و هرکس دیگری در سازمان کمک می‌کند. این نمودار همچنین می‌تواند به عنوان نشانگر وجود یک مسأله در اسپرینت عمل کند که تیم ممکن است بخاطر آن نتوانند به تعهد خود عمل کنند.


معیار پذیرش

اگرچه product backlog ، sprint backlog و نمودار burn-down بخشهای اصلی اسکرام هستند، معیار پذیرش خروجی جانبی بسیار مهمی از فرآیند اسکرام است. بدون معیار پذیرش خوب، یک پروژه محکوم به شکست است.

معیار پذیرش ضرورتاً شفاف کنندۀ داستان است. چنین معیاری مجموعه‌ای از گامهای مختلف را در اختیار توسعه دهنده می‌گذارد که پیش از آنکه کار تمام شده تلقی شود، باید انجام دهد. معیار پذیرش، توسط صاحب محصول ( product owner ) به کمک مشتری ایجاد می‌شود. این معیار انتظار از داستان کاربر را تنظیم می‌کند. استفاده از این معیار درجای خود نقطۀ شروع خوبی برای نوشتن تستهای خودکار یا حتی توسعۀ آزمون محور توسط توسعه‌دهنده است. بدین طریق، توسعه‌دهنده چیزی را تولید می‌کند که مشتری بدان نیاز داشته و آن را می‌خواهد.

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


نقش‌های اسکرام
اسکرام بین افرادی که نسبت به پروژه متعهد هستند و افرادی که فقط ذینفع  محسوب میشوند، تمایز قابل توجه‌ای قائل است. مشهورترین روش برای توضیح این مفهوم تعریف حکایت "Pig & Chicken" میباشد؛ یک خوک و یک جوجه در حال قدم زدن بودند که، یک دفعه جوجه به خوک گفت که: "چرا یک رستوران افتتاح نکنیم؟" خوک هم نگاهی به جوجه کرد و گفت:"ایده  خوبی است ، اسم آن را چه بنامیم؟"  جوجه کمی در مورد این مسئله فکر کرد و گفت:"چرا اسمش را 'گوشت ران خوک و تخم مرغ ها' نگذاریم؟" 
 خوک جواب داد:"فکر نمیکنم جالب باشد چون من متعهد خواهم بود به کار، ولی تو فقط درگیر کار خواهی بود".
بنابراین Pigs همان افراد متعهد به پروژه هستند که وظیفه ساخت، تست، گسترش و توزیع را ایفا میکنند. Chickens در طرف دیگر همان افرادی هستند که کمتر به پروژه تعهد دارند. این افراد همان stackeholder‌ها و یا ذینفعانی هستند که از پروژه منفعت می‌برند، اما در مقابل تحویل پروژه مسئول و پسخگو نیستند.

Pig Roles
نقش‌های عنوان شده در زیر جز نقش‌های Pig هستند که تیم اسکرام را نیز تشکیل میدهند:
  • Scrum Master
  • Product Owner
  • Delivery Team
  • Scrum Master
اگر تیم را موتور پروژه‌ی اسکرام در نظر بگیریم، اسکرام مستر روغنی است که موتور را در حال اجرا نگه می‌دارد. او مسئول این است که مطمئن شود فرآیند اسکرام تفهیم شده و دنبال میشود. اسکرام مستر تسهیل کننده‌ی جلسات تیم و حذف موانعی است که امکان دارد تیم در دوره‌ای از انجام کار خود با آن مواجه شد. او مطمئن خواهد بود که هیچ مانعی به عنوان بازدارنده از رسیدن به اهداف تیم در مقابل آنها وجود ندارد و تیم را از حواس پرتی‌های خارجی ایزوله نگه می‌دارد تا مطمئن شود اعضای تیم دقیقا کاری را به آنها سپرده شده است انجام میدهند. اسکرام مستر با بخش‌های مختلف تیم، از صاحبان محصول گرفته تا تست کنندگان وذینفعان کسب و کار در تعامل است، تا مطمئن شود که تمام اعضای تیم برای پروژه مفید هستند و تمام دست آورد‌های مشترک در اسپرینت را به اشتراک میگذارند. اسکرام مستر را یک مدیر پروژه معمول فرض نکنید؛ چون نقشی که او ایفا میکند بیشتر از نقش یک مدیر پروژه است. مشخصه کلیدی اسکرام مستر "رهبر خدمتگزار است". او رئیس تیم نیست ولی به تیم کمک میکند تا به چیزی که نیاز دارند در این اسپرینت دست یابند. اسکرام مستر به تیم کمک میکند تا کار را به سمتی که خروجی با ارزشی برای مشتری دارد، متمایل کنند. زمانی که مسئله‌ای در داخل تیم بوجود آید، به اسکرام مستر انتقال داده میشود تا این تضاد را مدیریت کند. مواقعی هم وجود دارند که اسکرام مستر در نقش فرمانروا، ایفای نقش میکند. وقتی که یکی از مسئولیت‌های اسکرام مستر مطمئن شدن از این است که تمام روشهای اسکرام توسط اعضای تیم دنبال میشوند، هرمسئله و حمله‌ای در برابر چارچوب اسکرام باید توسط اسکرام مستر رفع شود. این شانس خوش و اینچنین اتفاقی به ندرت خواهد افتاد.

Product Owner
صاحب پروژه یا محصول، مسئول مشخص کردن مشتری و افزایش مقدار کاری است که تیم انجام میدهد. او با مشتریان برای مشخص کردن اینکه خواسته آنها چیست، جلسه تشکیل داده و این نیاز‌ها را اولویت بندی میکنند و تیم هم بر روی آیتم هایی با بیشترین  ارزش برای مشتری، کار خواهد کرد. صاحب محصول همچنین product backlog را مدیریت کرده و تنها شخصی است که میتواند user story‌ها را برای انتقال به اسپرینت، اولویت بندی کند. مسئولیت‌های صاحب محصول در طول اسپرینت از سری مسئولیت‌های نقش Pig به سری مسئولیت‌های نقش Chicken تغییر میکند. یکی دیگر از نقش‌های حیاتی او این است که به عنوان نماینده‌ی مشتری، برای تیم است. صاحب محصول خیلی شبیه به اسکرام مستر میباشد ولی در این بین یک تفاوت اصلی در طبیعت نقش‌های آنها وجود دارد: اسکرام مستر به دنبال بهترین جذابیتهای مورد علاقه تیم در یک اسپرینت بوده؛ در حالی که صاحب محصول به دنبال بهترین جذابیتهای مطلوب مشتری در یک اسپرینت است. در یک تیم اسکرام، صاحب محصول، نقشی است که نمیتوان آن را دست کم گرفت. اگر صاحب محصول کسی باشد که نتواند به طور دقیق نیاز‌های مشتری را به تصویر بکشد، در نتیجه پروژه شکست خواهد خورد.
صاحب محصول کلید اجرایی یک محصول است که ارزشی را برای مشتری و موفقیتی را برای تیم به ارمغان می‌آورد.

Delivery Team
تیم تحویل، گروهی است از افراد که مسئول ارائه واقعی محصول هستند. این تیم معمولا شامل دو تا ده نفر از افراد و همچنین ترکیبی از برنامه نویسان، تست کننده‌ها، طراحان محصول نهایی و اعضایی از سایر نظام‌های ضروری، میباشد. تیم برای انتقال user story و وظایف مرتبط با آن به مرحله بعد بر روی تخته Kanban، تا مرحله‌ی اتمام، بر روی اسپرینت‌ها کار میکند. مشخصه‌ی کلیدی تیم تحویل این است که آنها به صورت یک واحد خود سازمانده می‌باشند. هیج رهبری در جمع آنها وجود ندارد و همه به صورت گروهی تصمیم میگیرند که در هر اسپرینت به انجام چه چیزی میتوانند متعهد شوند. اعضای تیم بار دیگر تصمیم خواهند گرفت که چه ابزاری برای موفقیت پروژه نیاز دارند. چنین سطحی از استقلال در متدولوژی آبشاری بی‌سابقه است! تیم تحویل برای بهینه سازی انعطاف پذیری و بهره وری در نظر گرفته شده‌اند. 
تیم اسکرام ترکیبی از افرادی است با توانمندیهای گوناگون که هرکدام باید با تمام چشم اندازهای محصول در مراتب مختلف آشنا باشند. هریک از اعضای تیم به تنهایی در همه‌ی مباحث نرم افزار ماهر نیستند، اما هر یک از آنها دانش عمومی در همه مباحث را دارند و در قسمت کلی از مفاهیم محصول هم متخصص هستند. تیم تحویل به همراه اسکرام مستر و صاحب محصول، برای تکمیل user story‌ها و به سرانجام رساندن هر اسپرینت، باهم کار میکنند. اسکرام مستر با آمادگی به دنبال بهترین جذابیتهای مورد علاقه تیم در یک اسپرینت است؛ در حالیکه صاحب محصول با آمادگی به دنبال بهترین جذابیتهای مطلوب مشتری در یک اسپرینت است. با وجود این دو نقش، تیم میتواند محصولی که مشتری میخواهد را بسارد.

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

Sprint Planning
قبل از شروع هر sprint، جلسه طرح ریزی برای مشخص کردن اینکه کدام امکان و ویژگی در این sprint قرار بگیرد، برگزار میشود. ویژگی‌ها و امکانات از لیست pb ای (product backlog) که توسط صاحبان (یا صاحب) محصول اولویت بندی شده است، انتخاب خواهند شد. برای بار اول که این نشست و جلسه برای یک پروژه برگزار شود، pb ساخته می‌شود. شما می‌توانید این قسمت را sprint 0 در نظر بگیرید. user stories (گزارشات کاربر) انتخاب شده توسط صاحب محصول، برای قرار گرفتن در print ، به تیم داده میشود و  آنها از طریق یک ابزار کاری بنام Planning Poker، گزارشات مذکور را برای نشان دادن پیچیدگی یک گزارش وابسته به گزارشات دیگر در گروه گزارشات، تغییر اندازه و تغییر حجم میدهند. بار دیگر user story هایی که به اندازه هستند، توسط تیم به وظیفه‌هایی قابل نسبت دادن به یک فرد تبدیل میشوند و یک زمان تخمینی که نشان دهنده‌ی زمان اتمام  برای هر وظیفه است، برای هر وظیفه در نظر گرفته میشود. بار دیگر که تمام این کار‌ها انجام شد ، اعضای  تیم به لیست کامل کارهایی که برای  sprint در نظر گرفته شده‌اند، نگاه خواهند کرد و اگر بتوانند تا اتمام sprint کار را تمام  کنند، تصمیم خواهند گرفت که آن را انجام دهند. این تصمیم گیری به صورت زیر است:
به وسیله 5 انگشت قرار است نظرات خود را ارائه دهند؛ به طوری که اگر عضوی دست خود را با یک انگشت بالا ببرد، بدین معنی است که او درطرح پیشنهادی خیلی تردید دارد و اگر دستی با 5 انگشت بالا رود، به این معنی است که این عضو، به شدت به طرح پیشنهادی مطمئن است. اگر هیج دستی با تعداد انگشت 1 یا 2 از بین دست‌های بالا رفته دیده نشود، لذا تیم به انجام آن کار در sprint جاری متعهد خواهد شد. ولی اگر دستی با تعداد انگشت 1 یا 2 از بین دست‌های بالا رفته دیده شود، در آن صورت  اعضای تیم در مورد دلیل رای عضوی که رایی با ارزش 1 یا 2 داده است، بحث خواهند کرد و با دیگر اعضای تیم برای تحویل گزارشات و وظایف موجود در اسپرینت، متعهد میشوند.
sprint backlog از گزارشات کاربر و وظایفی که باید در sprint تکمیل شوند، ساخته شده است. تمام اعضای تیم در کنار اسکرام مستر و صاحبان محصول در نشست برنامه ریزی اسپرینت درگیر هستند. بار دیگر جلسه برنامه ریزی متشکل از اعضای تیم و بدون صاحبان محصول برای بحث در مورد طراحی سطح بالای سیستم برگزار خواهد شد.

planning poker
planning poker یک بازی است که اعضای تیم را تشویق میکند تا ارزیابی درستی در مورد پیچیدگی گزارش کاربری (user story) که در ارتباط با سایر گزارشات (stories) است، داشته باشند. ابزارهای مورد نیاز برای این بازی خیلی ساده هستند: شما میتوانید از دست خود استفاده کنید؛ یا حتی میتوانید مجموعه کارت‌های Planning Poker را برای انجام بازی، خریداری کنید. برای انجام این بازی، صاحب محصول، گزارش کاربر (user story) را خوانده و برای تیم توضیح خواهد داد. تیم برای پرسیدن سوال در باره این گزارش کاربر، آزاد است. وقتی که تمام سوالات پاسخ داده شدند، اسکرام مستر از اعضای تیم خواهد خواست که یک عدد را به صورت خصوصی که به بهترین شکل پیچیدگی user story را ارئه میکند، تعیین کنید. توجه داشته باشید برای اینکه این انتخاب به صورت سهوی تحت تاثیر انتخاب سایر اعضا نباشد، باید برای دیگران آشکار نشود. بار دیگر  اسکرام مستر از همه میخواهد تا شماره‌های خود را برای همه آشکار کنند. اگر تمام اعضای تیم، یک شماره یکسان را تعیین کرده باشند، آن شماره به user story مورد نظر نسبت داده شده و همه سراغ user story بعدی میروند.
اگر شماره‌ها باهم یکسان نباشند، عضوی با بیشترین  و کمترین شماره، انتخاب شده و از آنها خواسته میشود دلیل تعیین شماره خود را شرح دهند. بعد از بحث، یک راند دیگر از بازی بین اعضایی که یک شماره را برای user story انتخاب کرده‌اند، انجام میشود. این کار تا زمانیکه تیم در یک شماره اتفاق نظر داشته باشند، ادامه خواهد داشت. به طور متوسط برای رسیدن به یک شماره یکسان، بیشتر از 3 راند طول نخواهد کشید. اگر بعد از 3 راند باز هم به شماره‌ای که همه با آن موافق هستند، دست نیابند، ما به اسکرام مستر پیشنهاد میکنیم که میانگین را انتخاب کرده و سراغ user story بعدی بروند.

Daily Stand Ups 
در طول یک اسپرینت، تیم، اسکرام مستر و صاحب محصول، برای حضور در جلسات روزانه که یکبار در هر روز و در یک مکان و زمان یکسان برای بحث در مورد موضوع‌هایی که موجب مانع از اتمام کار میشوند، متعهد میشوند. در جلساتی که برگزار میشود، همه به صورت ایستاده بوده و زمان آن بیشتر از 15 دقیقه طول نخواهد کشید. هرکسی که به نوعی ذینفع در پروژه هستند، برای حضور در جلسات دعوت میشوند. هر چند فقط افرادی که رده بندی شده‌اند، اجازه صحبت در این جلسات را خواهند داشت. در این جلسات، هر عضو تیم به 3 سوال زیر پاسخ خواهد داد:
  1. شما چه چیزی را از دیروز تا حالا انجام داده‌اید؟
  2. شما چه برنامه‌ای برای امروز دارید؟
  3. آیا شما مشکل دیگری که مانع رسیدن به هدفتان باشد، ندارید؟ چه جریانی باعث ایجاد این موانع شده‌اند؟ آیا میتوان مانع را حذف کرد یا باید تشدید شود؟

Sprint Review
 جلسه "بررسی اسپرینت" در پایان اسپرینت برگزار میشود. هدف از آن ارائه گزارشات کاربری  (user stories) هست که در طول اسپرینت تکمیل شده‌اند. تیم، صاحب محصول  و اسکرام مستر به همراه سایر ذینفعان، مخصوصا مدیران و مشتریان، در این جلسه حضور خواهند داشت. این بررسی شامل یک دموی غیررسمی از نرم افزار توسعه داده شده در اسپرینت، میباشد. این جلسه دموی محصول، فرصتی است برای مشتری تا بازخورد‌های خود از محصول را به تیم توسعه انتقال دهند. هدف اصلی از این بازنگری، نمایش محصول با کارکرد واقعی است. این جلسه با اصل "بالاترین اولویت ما عبارت است از راضی کردن مشتری با تحویل سریع و مداوم نرم افزار با ارزش" چابک در یک راستا میباشد.
اشتراک‌ها
مروری بر .net core توسط اسکات هانتر

There has never been a better time to be a .NET developer, you can now build Android, iOS, Linux, Mac, and Windows applications with .NET all in Open Source. In this session we will run through some of the new innovations including the .NET Framework updates, .NET Standard, Universal Windows Platform updates, .NET Core, managed languages and more. We will also review the updates to Visual Studio and Visual Studio Code to make you a better developer, come see some of the latest productivity features in these tools including managing code style, searching your source and more.
 

مروری بر .net core  توسط اسکات هانتر
اشتراک‌ها
ILSpy 8.0 منتشر شد

New Language Features
C# 10: record structs
C# 11: Required members
C# 11: ref fields
C# 10: Support DefaultInterpolatedStringHandler
Output attributes on lambda expressions
Updated pattern detection for Roslyn 4.4.0
 

ILSpy 8.0 منتشر شد