مطالب
الگوی طراحی Builder همراه با اصول Interface Segregation
الگوی طراحی builder، برای ساختن اشیاء بسیار مفید است؛ اما پروسه ساختن اشیاء آن بسیار پیچده هست و به صورت معمول، این پروسه شامل چندین قسمت می‌شود.
در این مثال ما مشکلات ساختن شیء Person را مورد بررسی قرار می‌دهیم و این شیء از اشیایی کوچکتر مانند Name ، Surname و یا Primary Contact و غیره نیز تشکیل شده است.
class Person : IPerson
{

    private string Name { get; }
    private string Surname { get; }
    private IContact PrimaryContact { get; set; }
    private IList<IContact> AllContacts { get; }

    public Person(string name, string surname, IContact primaryContact)
    {
        if (string.IsNullOrEmpty(name))
            throw new ArgumentException(nameof(name));
        if (string.IsNullOrEmpty(surname))
            throw new ArgumentException(nameof(surname));

        this.Name = name;
        this.Surname = surname;
        this.AllContacts = new List<IContact>();

        this.SetPrimaryContact(primaryContact);
    }

    public void SetPrimaryContact(IContact contact)
    {
        this.AddContact(contact);
        this.PrimaryContact = contact;
    }

    public void AddContact(IContact contact)
    {
        if (contact == null)
            throw new ArgumentNullException(nameof(contact));

        this.AllContacts.Add(contact);
    }
}
همان طور که مشاهده می‌کنید، مقدار دهی شیء IContact  پیچیده‌تر از Name و Surname هست و روش اضافه کردن Contact‌ها نیز بسیار پیچیده است؛ زیرا آنها به دو گروه PrimaryContact و Contacts تقسیم شده‌اند.
 شی Person شامل تعدای Contact مانند تلفن، ایمیل و یا هر چیزی دیگری میتواند باشد. 
در این مثال ما دو نوع Contact داریم که به صورت زیر پیاده سازی شده‌اند: 
interface IContact
{
}

class PhoneNumber : IContact
{

    private string AreaCode { get; }
    private string Number { get; }

    public PhoneNumber(string areaCode, string number)
    {

        if (string.IsNullOrEmpty(areaCode))
            throw new ArgumentException(nameof(areaCode));
        if (string.IsNullOrEmpty(number))
            throw new ArgumentException(nameof(number));

        this.AreaCode = areaCode;
        this.Number = number;
    }
}

class EmailAddress : IContact
{
    private string Address { get; }

    public EmailAddress(string address)
    {
        if (string.IsNullOrEmpty(address))
            throw new ArgumentException(nameof(address));   

        this.Address = address;
    }
}
به صورت کلی سه راه برای ساختن اشیاء وجود دارد:
1) استفاده از سازنده کلاس Person و سپس استفاده از متدهای AddContact و  SetPrimaryContact برای ساختن شیء، به صورت کامل.
2) استفاده از Abstract Factory برای ساختن Person و سپس استفاده از متدهای AddContact و  SetPrimaryContact برای ساختن شیء به صورت کامل.
3) استفاده از Builder برای ساختن شیء به صورت کامل و یکجا همراه با contact‌‌های آن.

 طراحی PersonBuilder : 
interface IPerson
{
    void SetPrimaryContact(IContact primaryContact);
    void AddContact(IContact contact);
}

interface IPersonBuilder
{
    void SetName(string name);
    void SetSurname(string surname);
    void SetPrimaryContact(IContact primaryContact);
    void AddContact(IContact contact);
    IPerson Build();
}
همانطور که مشاهده می‌کنید، یک اینترفیس معمولی از این الگوی طراحی هست که شامل متدهایی است که برای ساختن شیء مورد استفاده قرار میگیرند و در ادامه نحوه پیاده سازی این اینترفیس بیان شده‌است:
class PersonBuilder: IPersonBuilder
{
    private string Name { get; set; }
    private string Surname { get; set; }
    private IContact PrimaryContact { get; set; }
    private IList<IContact> OtherContacts { get; } = new List<IContact>();

    public void SetName(string name)
    {
        if (string.IsNullOrEmpty(name))
            throw new ArgumentException(nameof(name));
        this.Name = name;
    }

    public void SetSurname(string surname)
    {
        if (string.IsNullOrEmpty(surname))
            throw new ArgumentException(nameof(surname));
        this.Surname = surname;
    }

    public void SetPrimaryContact(IContact primaryContact)
    {
        if (primaryContact == null)
            throw new ArgumentNullException(nameof(primaryContact));
        this.PrimaryContact = primaryContact;
    }

    public void AddContact(IContact contact)
    {
        if (contact == null)
            throw new ArgumentNullException(nameof(contact));
        this.OtherContacts.Add(contact);
    }

    public IPerson Build()
    {        
        IPerson person = new Person(this.Name, this.Surname, this.PrimaryContact);

        foreach (IContact contact in this.OtherContacts)
            person.AddContact(contact);

        return person;
    }
}
خوب، اولین مشکلی که در این پیاده سازی مشهود است، مربوط به متد Build هست. اگر مقدار‌های سازنده کلاس Person را به صورت null ارسال کنیم، باعث خطا میشود و این خطا به این خاطر نیست که ما مقدار Null را به کلاس PersonBuilder ارسال کرده‌ایم؛ زیرا ما تمام متد‌های Set را با استفاده NullGurd مورد حفاظت قرار داده‌ایم. مشکل اصلی از وضعیت داخلی شیء PersonBuilder  هست. اگر متد‌های Set را فراخوانی نکنیم، تمام فیلد‌های خصوصی، مقدار null میگیرند و یکی از راه‌های رفع این مشکل این است که پارامتر‌ها را از طریق سازنده PersonBuilder مقدار دهی کنیم. ولی کمی بعدتر متوجه خواهیم شد که این پیاده سازی مانند کلاس person هست و در نتیجه این روش بی استفاده است.

راه حل: استفاده از  Interface Segregation principle در PersonBuilder :
اصل ISP  می‌گوید: "کلاینت‌ها نباید وابسته به متدهایی باشند که آنها را پیاده سازی نمی‌کنند." برای رسیدن به این امر در مثال بالا، باید آن واسط را به واسط‌های کوچکتری تقسیم کرد. این تقسیم بندی باید بر اساس استفاده کنندگان از واسط‌ها صورت گیرد.
برای اینکه شیء Person را بسازیم، متوجه خواهید شد بعضی از داده‌ها الزامی و بعضی دیگر اختیاری هستند؛ مانند PrimaryContact که از داده‌های ضروری شیء Person است. ولی AllContacts می‌تواند به صورت اختیاری تعریف شود و در  پیاده سازی PersonBuilder بالا، کلاینت متوجه نخواهد شد کدام متد اختیاری یا اجباری  هست و در نتیجه ممکن است فراموش کند متد SetPrimaryContact را فراخوانی کند و همین مساله باعث می‌شود تا نرم افزار با خطا مواجه شود.
راه حل: به کد زیر توجه فرمایید: 
class PersonBuilder
{

    private PersonBuilder() { }

    public static IExpectSurnamePersonBuilder WithName(string name)
    {
        ...
    }
}
همانطور که مشاهده می‌فرمایید، سازنده کلاس به صورت خصوصی تعریف شده‌است. درنتیجه بیرون از کلاس نمی‌توان از آن وهله ساخت و ‌‌آن‌را مورد استفاده قرار داد و تنها راه وهله سازی از کلاس PersonBuilder از طریق متد WithName خواهد بود. ثانیا این متد PersonBuilder را برنمی‌گرداند؛ بلکه شیء‌ایی را برمیگ‌رداند که منتظر فراهم کردن مقدار Surname  است و با استفاده از این روش می‌توانیم پروسه فراخوانی متد‌ها را مشخص کنیم.
درنتیجه پروسه ساختن شیء، به چندین قسمت تقسیم شده که به صورت زیر میباشد:
1) فراهم کردن مقدار Surname
2) فراهم کردن مقدار Name
3) فراهم کردن مقدار PrimaryContact
4) فراهم کردن مقدار سایر Contact‌های شخص
5) ساختن شیء Person

پس به ازای هر کدام از عملیات‌ها، یک اینترفیس خواهیم داشت: 
interface IExpectSurnamePersonBuilder
{
    IExpectPrimaryContactPersonBuilder WithSurname(string surname);
}

interface IExpectPrimaryContactPersonBuilder
{
    IExpectOtherContactsPersonBuilder WithPrimaryContact(IContact contact);
}

interface IExpectOtherContactsPersonBuilder
{
    IExpectOtherContactsPersonBuilder WithOtherContact(IContact contact);
    IPersonBuilder WithNoMoreContacts();
}

interface IPersonBuilder
{
    IPerson Build();
}
حالا نوبت به پیاده سازی PersonBuilder بر اساس اصول ISP است :
class PersonBuilder :
    IExpectSurnamePersonBuilder,
    IExpectPrimaryContactPersonBuilder,
    IExpectOtherContactsPersonBuilder,
    IPersonBuilder
{

    private string Name { get; }
    private string Surname { get; set; }
    private IContact PrimaryContact { get; set; }
    private Person Person { get; set; }

    private PersonBuilder(string name)
    {
        if (string.IsNullOrEmpty(name))
            throw new ArgumentException(nameof(name));
        this.Name = name;
    }

    public static IExpectSurnamePersonBuilder WithName(string name)
    {
        return new PersonBuilder(name);
    }

    public IExpectPrimaryContactPersonBuilder WithSurname(string surname)
    {
        if (string.IsNullOrEmpty(surname))
            throw new ArgumentException(nameof(surname));
        this.Surname = surname;
        return this;
    }

    public IExpectOtherContactsPersonBuilder WithPrimaryContact(IContact contact)
    {
        if (contact == null)
            throw new ArgumentNullException(nameof(contact));
        this.Person = new Person(this.Name, this.Surname, contact);
        return this;
    }

    public IExpectOtherContactsPersonBuilder WithOtherContact(IContact contact)
    {
        if (contact == null)
            throw new ArgumentNullException(nameof(contact));
        this.Person.AddContact(contact);
        return this;
    }

    public IPersonBuilder WithNoMoreContacts()
    {
        return this;
    }

    public IPerson Build()
    {
        return this.Person;
    }

}
این طراحی به کلاینت کمک خواهد کرد اشیایی را با وضعیت پایدار ایجاد کند و نرم افزاری تولید کند که دارای کمترین خطا باشد.
و اگر کلاینت بخواهد وهله‌ای را از کلاس PersonBuilder بسازد، به صورت زیر خواهد بود:
IPerson person =
    PersonBuilder
    .WithName("Ali")
    .WithSurname("Karimi")
    .WithPrimaryContact(new EmailAddress("admin@gmail.com"))
    .WithOtherContact(new EmailAddress("Test1@work.com"))
    .WithOtherContact(new EmailAddress("Test2@home.com"))
    .WithNoMoreContacts()
    .Build();
اصول طراحی ISP باعث می‌شوند، کد خواناتر شود و همین خوانایی سبب می‌گردد نگهداری و توسعه نرم افزار راحت‌تر شود.

چکیده:
ساختن اشیا در زبان‌های object oriented کار بسیار ساده‌ای است و همین سادگی، خطاهای جبران ناپذیری را به نرم افزار تحمیل میکنند و باعث ایجاد اشیایی ناپایدار در سیستم می‌شود. در اولین گام، الگوی طراحی Builder را به صورت ساده مورد بررسی قرار دادیم و در نهایت این طراحی را تا جای پیش بردیم که بتوانیم اشیایی پایدار را بسازیم. ولی این طراحی هنوز با مشکلاتی رو به رو هست؛ مانند نقض کردن قانون  command query separation  که این مشکل را در مقاله‌ی بعدی برطرف خواهیم کرد.
نظرات مطالب
آشنایی با WebDav و نحوه استفاده از آن
سلام. با تشکر از آموزش و تهیه کتابخونه.

وقتی فایل رو با word باز میکنم، بصورت readonly باز میشه و گزینه save بصورت آیکن sync نیست.
هم توی نمونه سورس کد گیت و هم یک وب‌اپ که خودم ایجاد کردم و رفرنس و پکیج نصب کردم مشکل بود. روی iis هم پابلیش گذاشتم فرقی نکرد.
مطالب
بررسی الگوی Chain of Responsibility در جاوا اسکریپت
الگوی Chain of Responsibility، یک زنجیر، از اشیاء متصل شده‌ی به هم را فراهم می‌کند که یکی از آنها می‌تواند درخواست رسیده را راضی کند؛ به عبارتی دیگر به محض دریافت درخواست، آن را پردازش می‌کند. این الگو اساسا یک جستجوی خطی ( linear search )، برای یک شیء می‌باشد که می‌تواند یک درخواست ویژه را handle کند. 

الگوی chain-of-responsibility، ارتباط با الگوی Chaining دارد که به دفعات در جاوا اسکریپت استفاده شده‌است (jQuery  استفاده‌ی گسترده‌ای از این الگو کرده‌است).
این الگو اجازه میدهد که یک درخواست ارسال شده‌ی توسط کلاینت، توسط یک یا بیش از یک object، دریافت شود. یک مثال عمومی از این الگو،  event bubbling در DOM  می‌باشد. یک رویداد از طریق element‌‌‌های تودرتوی متفاوت انتشار پیدا می‌کند؛ تا زمانیکه یکی از آن‌ها، آن را handle کند.


مثال زیر را در نظر بگیرید:
class HandlerChain 
{ 
   setNextObj(nextObjInChain){}
   processMultiple(req){
     console.log("No multiple for: " + req.getMultiple());
   }
} 
  
class Multiple
{
  constructor(multiple){
    this.multiple = multiple;
  }
  
  getMultiple(){ 
    return this.multiple; 
  } 
  
} 
  

class MultipleofTwoHandler extends HandlerChain
{
  constructor(){
    super()
    this.nextObjInChain = new HandlerChain()
  } 
  
  setNextObj(nextObj){ 
    this.nextObjInChain = nextObj; 
  } 
  
  processMultiple(req) { 
    if ((req.getMultiple() % 2) == 0) { 
      console.log("Multiple of 2: " + req.getMultiple()); 
    }else{ 
      this.nextObjInChain.processMultiple(req); 
    } 
  } 
} 
  
class MultipleofThreeHandler extends HandlerChain 
{ 
  constructor(){
    super()
    this.nextObjInChain = new HandlerChain()
  } 
  
   setNextObj(nextObj){ 
    this.nextObjInChain = nextObj; 
  } 
  
  processMultiple(req) 
  { 
    if ((req.getMultiple() % 3) == 0) { 
      console.log("Multiple of 3: " + req.getMultiple()); 
    }else{ 
          this.nextObjInChain.processMultiple(req); 
        } 
    } 
} 


class MultipleofFiveHandler extends HandlerChain
{ 
  constructor(){
    super()
    this.nextObjInChain = new HandlerChain()
  }
  
  setNextObj(nextObj){ 
    this.nextObjInChain = nextObj; 
  } 
  
  processMultiple(req) { 
    if ((req.getMultiple() % 5) == 0) { 
      console.log("Multiple of 5: " + req.getMultiple()); 
    }else{ 
      this.nextObjInChain.processMultiple(req); 
      } 
    } 
} 

//configuring the chain of handler objects
var c1 = new MultipleofTwoHandler(); 
var c2 = new MultipleofThreeHandler(); 
var c3 = new MultipleofFiveHandler(); 
c1.setNextObj(c2); 
c2.setNextObj(c3); 
  
//the chain handling different cases
c1.processMultiple(new Multiple(95));  // Multiple of 5: 95  
c1.processMultiple(new Multiple(50));  // Multiple of 2: 50 
c1.processMultiple(new Multiple(9));   // Multiple of 3: 9 
c1.processMultiple(new Multiple(4));   // Multiple of 2: 4 
c1.processMultiple(new Multiple(21));  // Multiple of 3: 21 
c1.processMultiple(new Multiple(23));  // No multiple for: 23  
مثال بالا، الگوی chain of responsibility را پیاده سازی می‌کند و بررسی می‌کند که آیا عدد وارد شده، مضربی از 2، 3 یا 5 است و یا نه.
چگونه می‌توانیم این قابلیت را پیاده سازی کنیم؟ ما می‌خواهیم که یک عدد داشته باشیم و سپس به handler‌ها در زنجیره اجازه بدهیم که تصمیم گیری کنند که آیا آنها می‌خواهند عدد وارد شده را پردازش کنند، یا به handler بعدی پاس بدهند.

ما 3 نوع handler در این زنجیره داریم:

  • MultipleofTwoHandler: بررسی می‌کند که آیا عدد وارد شده، مضربی از 2 است یا نه. 
  • MultipleofThreeHandler: بررسی می‌کند که آیا عدد وارد شده، مضربی از 3 است یا نه 
  • MultipleofFiveHandler: بررسی می‌کند که آیا عدد وارد شده، مضربی از 5 است یا نه. 

اولین قدم، ایجاد یک زنجیره از handler‌های بالا می‌باشد. در اینجا یک کلاس را به نام HandlerChain، برای همین منظور داریم و این کلاس شامل دو تابع، به نام‌های setNextObj و processMultiple می‌باشد.
class HandlerChain 
{ 
   setNextObj(nextObjInChain){}
   processMultiple(req){
     console.log("No multiple for: " + req.getMultiple());
   }
}

پیاده سازی پیش فرض processMultiple، زمانی اجرا می‌شود که هیچ مضربی برای یک عدد، وجود نداشته باشد. به عبارت دیگر، عدد مورد نظر، مضربی از 2،3 و 5 نباشد ( از بین مضرب‌های تعین شده). 
تمام handler‌ها در این زنجیره، از این کلاس ارث بری می‌کنند. هر handler می‌تواند دو عملیات را انجام دهد:

  1. تنظیم کردن handler بعدی در زنجیره 
  2. پردازش عدد وارد شده به این منظور که آیا در مضرب مورد نظر قرار دارد یا نه. 

class MultipleofTwoHandler extends HandlerChain
{ 
  constructor(){/*code*/}
  setNextObj(nextObj){/*code*/}  
  processMultiple(req){/*code*/}
}
  
class MultipleofThreeHandler extends HandlerChain
{
  constructor(){/*code*/}
  setNextObj(nextObj){/*code*/}  
  processMultiple(req){/*code*/}
}


class MultipleofFiveHandler extends HandlerChain
{
  constructor(){/*code*/}
  setNextObj(nextObj){/*code*/}  
  processMultiple(req){/*code*/}
}

constructor برای هر handler، همانند زیر تعریف شده‌است:
constructor(){
    super()
    this.nextObjInChain = new HandlerChain()
}

در ابتدا توسط  super ،  مقدار دهی اولیه‌ای برای متد‌های setNextObj و processMultiple از کلاس پدر انجام میشود. همچنین در constructor، متغیر nextObjInChain
مقدار دهی اولیه می‌شود که تعیین کننده‌ی شیء بعدی در زنجیره می‌باشد. 
 
 چگونه شیء جاری، شیء بعد را در زنجیره تعیین می‌کند؟ اجازه بدهید برای این منظور نگاهی به تابع setNextObj داشته باشیم. setNextObj در هر handler، همانند زیر تعیین شده‌است: 
setNextObj(nextObj){ 
    this.nextObjInChain = nextObj; 
}

اکنون می‌توانیم زنجیره‌ای از handler‌ها را همانند زیر ایجاد کنیم: 
var c1 = new MultipleofTwoHandler(); 
var c2 = new MultipleofThreeHandler(); 
var c3 = new MultipleofFiveHandler(); 
c1.setNextObj(c2); 
c2.setNextObj(c3);

در اینجا ما handler‌‌‌های c2, c1  و c3 را به منظور پردازش کردن مضرب‌های 2، 3 و 5 ایجاد کرده‌ایم. آن‌ها به یکدیگر به حالت زیر متصل شده‌اند:
 c2 به عنوان handler بعدی برای c1 و c3 به عنوان handler بعدی برای c2. 


اکنون که زنجیره ایجاد شده‌است، زمان آن است که عدد وارد شده را پردازش کنیم. اجازه بدهید که کار را با ایجاد کردن شیء “multiple”  با استفاده از کلاس Multiple، شروع کنیم.

class Multiple
{
  constructor(multiple){
    this.multiple = multiple
  }
  
  getMultiple(){ 
    return this.multiple; 
  }  
}

یک شیء Multiple، شامل یک خصوصیت به نام multiple و یک متد است به نام getMultiple که به منظور برگشت دادن multiple می‌باشد.
 
MultipleofTwoHandler به صورت زیر تعریف شده‌است:
processMultiple(req) { 
    if ((req.getMultiple() % 2) == 0) { 
      console.log("Multiple of 2: " + req.getMultiple()); 
    }else{ 
      this.nextObjInChain.processMultiple(req); 
    } 
}

در اینجا، یک multiple دریافت شده و چک می‌شود که آیا مضربی از 2 می‌باشد یا نه؛ اگر چنین است، سپس عدد دریافت شده را به عنوان مضربی از 2 نمایش می‌دهد. در صورتیکه مضربی از 2 نباشد، handler آن را به شیء بعدی در زنجیره، پاس میدهد و سپس همین روال دوباره تکرار می‌شود و تا زمانیکه یکی از handler ‌ها، جواب را برگشت دهد، این روال ادامه پیدا می‌کند. 
 
تعریف تابع processMultiple  برای هر 3 handler یکسان میباشد؛ با این تفاوت که MultipleofThreeHandler، برای بررسی مضربی از 3 بودن و MultipleofFiveHandler  برای بررسی مضربی از 5 بودن است.

اجازه بدهید یک مثال بزنیم و ببینیم که چه اتفاقی می‌افتد:
c1.processMultiple(new Multiple(95)) // Multiple of 5: 95  

اولین handler در زنجیره که c1 است، یک multiple (95) را دریافت می‌کند و چک می‌کند که آیا مضربی از 2 است یا نه. جواب خیر است؛ بنابراین multiple به دومین handler  در زنجیره پاس داده میشود؛ یعنی به handler بررسی کننده‌ی مضربی از 3 . در اینجا دوباره بررسی میشود که آیا عدد مورد نظر، مضربی از 3 است یا نه؟ که جواب خیر است. در ادامه multiple به handler سوم در زنجیره که بررسی کننده‌ی مضربی از 5 است، پاس داده میشود. در اینجا، شرط درست است و عدد 95 به عنوان مضربی از 5 چاپ میشود. 


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

برای استفاده از jQuery Ajax یکی از روش‌های ارسال دیتا به برنامه، تبدیل داده‌ها به فرمت JSON می‌باشد. برای داده‌های ساده، تشخیص این فرمت ساده است. مثلا اگر امضای تابع وب سرویس اجکس ما به صورت زیر باشد:
public static bool IsUserAvailable(string username)
اطلاعات جی‌سونی را که قرار است ارسال کنیم، فرمت زیر را باید داشته باشد:
{'username':'value'}
حال اگر آرگومان‌های ما پیچیده‌تر بودند چطور؟ مثلا بجای یک رشته ساده، یک لیست جنریک داشتیم، فرمت ورودی را چگونه باید تشخیص داد؟
برای این منظور در دات نت 3 و نیم، کلاسی جهت انجام اینگونه تبدیلات پیش بینی شده است که شرح مختصر آن به صورت زیر است:
ابتدا باید ارجاعی را به اسمبلی system.web.extensions به برنامه افزود و سپس جهت سهولت کار می‌توان یک extension method از کلاس JavaScriptSerializer مهیا در فضای نام System.Web.Script.Serialization ایجاد کرد:

public static string ToJson(this object data)
{
return new JavaScriptSerializer().Serialize(data);
}
اکنون چند مثال زیر را در نظر بگیرید:
        public static string GetJsonTest0()
{
var data = "a1";
return data.ToJson();
}

public static string GetJsonTest1()
{
var data = new List<string> { "a1", "a2", "a3" };
return data.ToJson();
}

public static string GetJsonTest2()
{

var lst =
new List<KeyValuePair<string, object>>
{
new KeyValuePair<string, object>("Name", "علی"),
new KeyValuePair<string, object>("Number", 10),
new KeyValuePair<string, object>("Desc", "منابع مورد نیاز")
};

return lst.ToJson();

}
خروجی‌های آن‌ها به ترتیب به صورت زیر خواهند بود:

"a1"
["a1","a2","a3"]
[{"Key":"Name","Value":"علی"},{"Key":"Number","Value":10},{"Key":"Desc","Value":"منابع مورد نیاز"}]

این کلاس همچنین قابلیت Deserialize و تبدیل داده‌هایی به فرمت JSON به اشیاء مورد نظر ما را نیز دارا است.

مطالب
الگوی Service Locator
الگوی Service Locator، به صورت گسترده‌ای به عنوان یک ضد الگو شناخته می‌شود و هنگامیکه از این الگو استفاده می‌کنیم ما را با یک سری از مشکلات رو به رو می‌کند. ولی این الگوی طراحی به خودی خود منشاء مشکل نیست. مشکل اصلی این الگو نحوه استفاده از آن است که در این مقاله درباره آن بحث می‌کنیم. 

مشکل اصلی الگوی Service Locator
زمانیکه یک کلاس، وابسته به یک Service Locator است، آن تمام وابستگی‌های واقعی کلاس را مخفی می‌کند.
 ما نمی‌توانیم وابستگی‌ها را با نگاه کردن به تعریف سازنده‌ی کلاس بیان کنیم. در عوض، ما باید کلاس و شاید مشارکت کنندگانش را بخوانیم تا برای تشخیص اینکه چه کلاس‌های دیگری برای کار آنها لازم است. 
فرض کنید ما یک کارخانه تولید ماشین را مدل می‌کنیم. کارخانه، ماشین‌ها را تولید می‌کند و آنها را به مکان فروش می‌رساند:
class Car
{

}

class CarProducer
{
    public void DeliverTo(int carsCount, string town)
    {
        Car[] cars = new Car[carsCount];
        ...
    }
}
در حال حاضر سازنده نیاز به کمک یک نهاد دیگر حمل کننده دارد که به آن کمک می‌کند تا اتومبیل را به محل مشخص شده ارسال کند: 
class Transporter
{

    public string Name { get; private set; }

    public Transporter(string name)
    {
        this.Name = name;
    }

    public void Deliver(Car[] cars, string town)
    {
        Console.WriteLine("Delivering {0} car(s) to {1} by {2}",
                            cars.Length, town, this.Name);
    }
}
چگونه می‌توانیم تولید کننده را در این راه حل ملاقات کنیم؟ یک راه برای رسیدن به آن این است که از Service Locator استفاده کنید:
static class TransporterLocator
{
    static IList<Transporter> transporters = new List<Transporter>();

    public static void Register(Transporter transporter)
    {
        transporters.Add(transporter);
    }

    public static Transporter Locate(string name)
    {
        return
            transporters
                .Where(transporter => transporter.Name == name)
                .Single();
    }
}
این کلاس استاتیک است که مجموعه‌ای از حمل کننده‌های موجود را در آن نگهداری می‌کند و هر حمل کننده به واسطۀ نام آن شناسایی می‌شود. بنابراین زمانیکه مشتری (تولید کننده خودرو در این مورد) نیاز به یک حمل کننده دارد، فقط باید نام آن را صدا بزند:
class CarProducer
{
    public void DeliverTo(int carsCount, string town)
    {
        Car[] cars = new Car[carsCount];

        Transporter transporter = null;
        if (carsCount <= 12)
            transporter = TransporterLocator.Locate("truck");
        else
            transporter = TransporterLocator.Locate("train");

        transporter.Deliver(cars, town);

    }
}

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

شناسایی مشکلات Service Locator
برای درک مشکلات راه حل قبلی، باید سعی کنیم تا از آن استفاده کنیم:
TransporterLocator.Register(new Transporter("truck"));
TransporterLocator.Register(new Transporter("train"));

CarProducer producer = new CarProducer();
producer.DeliverTo(7, "Tehran");
producer.DeliverTo(74, "Tehran");
همانطور که می‌بینید، ما نمی‌توانیم از کلاس CarProducer استفاده کنیم، اگر قبل از آن، مکان را مشخص نکرده باشیم. کلاس CarProducer مستقل نیست و یکی از اصول اساسی طراحی نرم افزار را نقض می‌کند: اگر ما یک ارجاع به یک شیء داشته باشیم، آن شیء به درستی تعریف شده است. اگر ما قبل از استفاده از کلاس CarProducer محل آن را مشخص نکرده باشیم، عملیات با خطا مواجه خواهد شد: 
TransporterLocator.Register(new Transporter("truck"));

CarProducer producer = new CarProducer();
producer.DeliverTo(7, "Tehran");
producer.DeliverTo(74, "Tehran");
این قطعه از کد دارای خطاست؛ زیرا انتظار دارد قطار در Service Locator ثبت شده باشد. به صورت خلاصه همان شیء ممکن است به درستی کار کند یا با خطا رو به رو شود.
بهتر است که کلاس CarProducer را به گونه‌ای طراحی کنید که اگر اشیای مورد نیاز آن به درستی تنظیم نشده باشند، آنگاه نتوان از آن نمونه سازی کرد.

 حذف Service Locator
اگر ما ارجاعی را به یک شیء داشته باشیم، می‌خواهیم مطمئن باشیم که این شیء به خوبی تشکیل شده است و ما نمی‌خواهیم با یک سری از خطا‌های اولیه که از نیازهای اولیه شیء می‌باشند، مواجه شویم. یکی از راه‌ها برای حل این مشکل آن است که تمام وابستگی‌های اجباری  آن‌را در سازنده کلاس تعریف کنیم. به این ترتیب، اگر وابستگی‌ها در دسترس نباشند، راهی قانونی برای ساخت یک شیء وجود نخواهد داشت.
class CarProducer
{
    private Transporter truck;
    private Transporter train;

    public CarProducer(Transporter truck, Transporter train)
    {
        if (truck == null)
            throw new ArgumentNullException("truck");

        if (train == null)
            throw new ArgumentNullException("train");

        this.truck = truck;
        this.train = train;
    }

    public void DeliverTo(int carsCount, string town)
    {
        Car[] cars = new Car[carsCount];
        Transporter transporter = this.truck;
        if (carsCount > 12)
            transporter = this.train;

        transporter.Deliver(cars, town);
    }
}
در این پیاده سازی، CarProducer نیاز به تمام وابستگی‌های خود را دارد و به هیچ عنوان نمی‌توان از کلاس carProducer وهله‌ای ساخت، تا زمانیکه وابستگی‌های آن را مشخص کرده باشیم. حتی بیشتر از آن، در پیاده سازی سازنده با دو شرط محافظ آغاز می‌شود. اگر هر یک از دو حمل کننده تهی باشند، سازنده CarProducer یک استثناء را بر می‌گرداند و شیء ساخته نخواهد شد. با استفاده از این پیاده سازی، مطمئن هستیم که شیء موجود معتبر است که یک مفهوم بسیار مهم است که ما را از وضعیت ناپایدار در سیستم، در امان نگه می‌دارد.

آیا وضعیتی وجود دارد که در آن Service Locator  یک راه حل قابل قبول باشد؟

در برخی موارد بجای اینکه وابستگی‌ها را به صورت صریح قید کنیم، بهتر است از این الگو استفاده کنیم.
این مثال را میتوان از زوایای مختلفی مورد بررسی قرار داد:
    1)  ما نمی‌توانیم با نگاه کردن به پیاده سازی کلاس بفهمیم که چه شرایطی قبل از نمونه سازی از کلاس باید رعایت شده باشند.
    2) ما نمی‌توانیم بدانیم زمانیکه یک متد فراخوانی می‌شود، عملیات به درستی به انجام می‌رسد و یا با خطا رو به رو می‌شود.
    3) ما نمی‌توانیم این کلاس را در یک تست بررسی کنیم؛ زیرا آن کلاس وابسته به اشیاء مبهمی هست که در جای دیگری تنظیم شده‌اند. 
همه این مسائل جدی هستند. با این دلایل است که Service Locator به عنوان یک ضد الگو در نظر گرفته شده است. اما ... این ضد الگوی در کدها شیء گرا است. اما تمام کد‌های ما شیء گرا نیستند. 
زمانیکه ما از یک پایگاه داده رابطه‌ای در حال استفاده هستیم، منطق Persistence از حالت شیء گرایی خود خارج می‌شود. منطق Persistence به صورت عمده‌ای برای نگاشت مدل‌های داده به جداول است. منطق رابط کاربری ( User Interface ) نیز شیء گرا نیست؛ زیرا عمدتا از نگاشت بین داده ساده و عناصر رابط کاربر تشکیل شده‌است.
در نتیجه، عنصر مشترک در هر دو مورد، نگاشت است و این دقیقا همان چیزی است که Service Locator انجام می‌دهد؛ نگاشت کلید‌ها به اشیاء. پس چرا ما نباید از Service Locator در لایه‌هایی که عمدتا شیء گرا نیستند استفاده کنیم؟
 
نتیجه گیری
در این مقاله ما به الگویی پرداختیم که در عمل به صورت گسترده‌ای از آن اجتناب می‌شود. مشکل Service Locator این است که اصول طراحی شیء گرا را نقض می‌کند. اما در عین حال، مناطقی از کد وجود دارند که طبیعت آنها شیء گرا نیستند. لایه‌های Presentation و persistence شیء گرا نیستند. در عوض، آنها در حال نگاشت مدل به چیزهای دیگری، جداول و ستون در پایگاه داده و یا عناصر رابط کاربری هستند. اینها مکان هایی هستند که الگوی طراحی Service Locator را می‌توان با خیال راحت و بدون نقض هر یک از دستورالعمل‌های شیء گرایی، صرفا به این دلیل که این مکان‌ها به هیچ وجه شیء گرا نیستند، استفاده کرد.
مطالب
الگوی بازدیدکننده Visitor Pattern
این الگو یکی دیگر از الگوهای رفتاری است که به قاعده OCP یا Open Closed Principle کمک بسیاری می‌کند. این الگو برای زمانی مناسب است که ما سعی بر این داریم تا یک سری الگوریتم‌های متفاوت را بر روی یک سری از اشیاء پیاده سازی کنیم. به عنوان مثال تصور کنید که ما در یک سازمان افراد مختلفی را از مدیریت اصلی گرفته، تا ساده‌ترین کارمندان، داریم و برای محاسبه حقوق و مالیات و ... نیاز است تا برای هر کدام دستور العمل‌هایی را اجرا کنیم  و ممکن است در آینده تعداد این دستور العمل‌ها بالاتر هم برود.
در این مثال ما سه گروه Manager,Employee و Worker را داریم که می‌خواهیم با استفاده از این الگو برای هر کدام به طور جداگانه، حقوق و دستمزد و اضافه کاری را محاسبه کنیم. با توجه به اینکه فرمول هر یک جداست و این احتمال نیز وجود دارد که هر کدام خواص مخصوص به خود را داشته باشند که در دیگری وجود ندارد و در آینده این احتمال می‌رود که سمت جدید یا دستورالعمل‌های جدیدی اضافه شود، بهترین راه حل استفاده از الگوی Visitor است.

الگوی visitor دو بخش مهم دارد؛ یکی Element که قرار است کار روی آن انجام شود. مثل سمت‌های مختلف و دیگری Visitor هست که همان دستورالعمل‌هایی چون محاسبه حقوق و دستمزد و ... است که روی المان‌ها صورت می‌گیرد.
ابتدا برای هر کدام یک اینترفیس را با مشخصات زیر می‌سازیم:
 public interface IElement
    {
        void Accept(IElementVisitor visitor);
    }

    public interface IElementVisitor
    {
        void Visit(Manager manager);
        void Visit(Employee manager);
        void Visit(Worker manager);
    }
همانطور که می‌بینید در کلاس Visitor سه متد هستند که سه کلاس مدیر، کارمند و کارگر را که مشتق شده از اینترفیس Element هستند، به صورت آرگومان می‌پذیرند. توصیف هر کلاس المان به شرح زیر است:
 public class  Manager: IElement
    {
        public int WorkingHour = 8;
        public int Wife = 1;
        public int Children = 3;
        public int OffDays = 6;
        public int OverHours = 12;

        public void Accept(IElementVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

public class Employee: IElement
    {
        public int WorkingHour = 8;
        public int Wife = 1;
        public int Children = 3;
        public int OffDays = 6;
        public int OverHours = 12;

        public void Accept(IElementVisitor visitor)
        {
            visitor.Visit(this);
        }
    }

public class Worker:IElement
    {
        public int WorkingHour = 8;
        public int Wife = 1;
        public int Children = 3;
        public int OffDays = 6;
        public int OverHours = 12;

        public void Accept(IElementVisitor visitor)
        {
            visitor.Visit(this);
        }
    }
ما اطلاعات هر کلاس را در این مثال، مشابه گذاشته‌ایم تا نتیجه فرمول را ببینیم. ولی هیچ الزامی به رعایت آن نیست.
حال وقت آن رسیده تا از روی کلاس Visitor، برای حقوق، دستمزد و اضافه کاری، کلاس‌های جدیدی را بسازیم:
 class SalaryCalculator:IElementVisitor
    {
        public void Visit(Manager manager)
        {
            var salary = manager.WorkingHour*10000;
            salary += manager.Wife*25000;
            salary += manager.Children*20000;
            salary -= manager.OffDays*5000;
            Console.WriteLine("Manager's Salary is " + salary);
        }

        public void Visit(Employee employee)
        {
            var salary = employee.WorkingHour * 7000;
            salary += employee.Wife * 15000;
            salary += employee.Children * 10000;
            salary -= employee.OffDays * 6000;
            Console.WriteLine("Employee's Salary is " + salary);
        }

        public void Visit(Worker worker)
        {
            var salary = worker.WorkingHour * 6000;
            salary += worker.Wife * 5000;
            salary += worker.Children * 2000;
            salary -= worker.OffDays * 7000;
            Console.WriteLine("Worker's Salary is " + salary);
        }
    }

    class WageCalculator:IElementVisitor
    {
        public void Visit(Manager manager)
        {
            var wage = manager.OverHours*30000;
            Console.WriteLine("Employee's wage is " + wage);
        }

        public void Visit(Employee employee)
        {
            var wage = employee.OverHours * 20000;
            Console.WriteLine("Employee's wage is " + wage);
        }

        public void Visit(Worker worker)
        {
            var wage = worker.OverHours * 15000;
            Console.WriteLine("Employee's wage is " + wage);
        }
    }
اکنون نیاز است تا ارتباط بین المان‌ها و بازدید کننده‌ها را طوری برقرار کنیم که برای تغییر آن‌ها در آینده، مشکلی نداشته باشیم. به همین جهت یک کلاس جدید به نام سیستم مالی ایجاد می‌کنیم:
class FinancialSystem
    {
        private readonly IList<IElement> _elements;

        public FinanceSystem()
        {
            _elements=new List<IElement>();
        }

        public void Attach(IElement element)
        {
            _elements.Add(element);
        }

        public void Detach(IElement element)
        {
            _elements.Remove(element);
        }

        public void Accept(IElementVisitor visitor)
        {
            foreach (var element in _elements)
            {
                element.Accept(visitor);
            }
        }
    }
در این روش تمام المان‌ها را داخل یک لیست قرار داده و سپس با استفاده از متد Accept، یکی از کلاس‌های مشتق شده از Visitor را به آن نسبت می‌دهیم که وظیفه آن صدا زدن متد Accept درون المان هاست. وقتی متد Accept المان‌ها صدا زده شد، شیء، المان را به متد Visit در Visitor داده و فرمول را روی آن اجرا می‌کند.
بدنه اصلی:
IElement manager=new Manager();
IElement employee=new Employee();
IElement worker=new Worker();

var fine=new FinancialSystem();
fine.Attach(manager);
fine.Attach(employee);
fine.Attach(worker);

fine.Accept(new SalaryCalculator());
fine.Accept(new WageCalculator());
نتیجه خروجی:
Manager's Salary is 135000
Employee's Salary is 65000
Worker's Salary is 17000
Manager's wage is 360000
Employee's wage is 240000
Worker's wage is 180000
مطالب
به روز رسانی View ها و رویه‌های ذخیره شده در SQL server

یکی دیگر از معایب کوئری‌های select * در SQL server این است که تغییرات حاصل در فیلدهای جداول یک بانک اطلاعاتی را در view های ساخته شده از این نوع کوئری‌ها منعکس نمی‌کند.
برای مثال جدول tblTreeItems را با سه فیلد id ، parent و title در نظر بگیرید. فرض کنید بر این اساس view زیر را ساخته‌ایم:

CREATE VIEW GetData
as
SELECT * FROM tblTreeItems

اکنون به جدول فوق ، فیلد جدید isActive را اضافه می‌کنیم. پس از این عملیات اگر کوئری ساده SELECT * FROM GetData را اجرا کنیم، فیلد جدید isActive را در آن نخواهیم دید (برخلاف انتظار که می‌بایست کوئری select * رکوردهای تمام فیلدهای جدول را بر می‌گرداند. در این‌جا ممکن است مدتی وقت صرف دیباگ کردن سیستم شود که چرا تغییرات جدید اعمال نشده و چرا سیستمی که تا چند لحظه پیش داشت کار می‌کرد الان از کار افتاد!).
باید در نظر داشت که هنگام ایجاد یک view ، تصویری از تمامی فیلدهای مورد استفاده در آن زمان، جهت بالابردن کارآیی کوئری و عدم محاسبه مجدد فیلدها در جداول سیستمی ذخیره می‌گردد ( * با نام فیلدهای همان زمان ایجاد (نه زمان فعلی)، جایگزین خواهد شد). این تصویر ایستا است و با تغییر فیلدهای یک جدول به روز نخواهد شد.
برای به روز کردن view ها و stored procedures پس از تغییرات ساختاری در جداول، باید مجددا آنها را کامپایل کرد. برای این منظور راه‌های زیادی وجود دارد، برای مثال drop کردن یک view و ایجاد مجدد آن. یا باز کردن آن view در management studio (حالت alter query) و سپس فشردن دکمه F5 جهت اجرای مجدد کوئری که این‌بار بر اساس اطلاعات جدید به روز خواهد شد. یا استفاده از رویه‌های سیستمی sp_refreshview و sp_recompile که برای کامپایل مجدد view ها و رویه‌های ذخیره شده بکار می‌روند.

برای مدیریت ساده‌تر این موارد ، اسکریپت زیر تمامی view ها و رویه‌های ذخیره شده یک دیتابیس را به صورت خودکار یافته و آنها را مجددا کامپایل می‌کند: (جهت مشاهده آن نیاز به ثبت نام دارد و رایگان است)
Refreshing Views and Recompiling Stored Procs

مطالب
ایجاد گزارشات Crosstab در PdfReport
پیشنیازها
تهیه گزارشات Crosstab به کمک LINQ 
تهیه گزارشات Crosstab به کمک LINQ - قسمت دوم 

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

روش حل این نوع مسایل را در PdfReport در مثال‌های جدید ذیل می‌توانید مشاهده کنید:
1) DynamicCrosstab (یک گزارش Crosstab با تعداد ستون متغیر)



2) WorkedHours (یک گزارش Crosstab با تعداد ستون متغیر به علاوه تابع تجمعی سفارشی محاسبه جمع ساعات اشخاص)



3) ExtraHeadingCells (یک گزارش Crosstab به همراه ردیف‌های header اضافی و نحوه تعریف آن)



4) ExpensesCrosstab (یک گزارش Crosstab کلاسیک)



5) PdfA (یک گزارش Crosstab که به صورت استاندارد PdfA تهیه شده است. PdfA حالت خاصی از استاندارد PDF است که برای مستند سازی عموما مورد استفاده قرار می‌گیرد. رمزنگاری اطلاعات در آن ممنوع است. تصاویر بکارگرفته شده نباید شفاف باشند. قلم‌های مورد استفاده حتما باید در فایل مدفون شوند و مواردی از این دست)
 

مطالب دوره‌ها
ابزاری برای تولید کدهای Reflection.Emit
برنامه معروف Reflector دارای افزونه‌ای است به نام Reflector.ReflectionEmitLanguage که سورس آن از آدرس ذیل قابل دریافت است:


مشخصات آن‌را نیز در آدرس زیر می‌توانید مشاهده نمائید:

به این ترتیب به منوی انتخاب زبان‌های Reflector، یک زبان جدید به نام ReflectionEmit اضافه خواهد شد:




مشکل!
این افزونه مدت زیادی است که به روز نشده و با آخرین نگارش Reflector سازگار نیست. برای رفع این مشکل ابتدا سورس آن‌را از کدپلکس دریافت و سپس تغییرات ذیل را به آن اعمال کنید:
الف) به قسمت ارجاعات پروژه افزونه مراجعه و ارجاع به Reflector قدیمی آن‌را حذف و آدرس فایل exe برنامه Reflector جدید را به عنوان ارجاعی تازه، ثبت کنید.
ب) در فایل Visitor.cs آن باید تغییر کوچکی در متد ذیل به نحوی که مشاهده می‌کنید صورت گیرد:
public virtual void VisitOrderClause(IOrderClause value)
{
    this.VisitOrderClause(value);
}
پس از آن، پروژه را کامپایل کرده و فایل dll حاصل را در پوشه Addins نگارش جدید Reflector کپی کنید. سپس به منوی Tools و گزینه Addins در برنامه مراجعه کرده و آدرس فایل Reflector.ReflectionEmitLanguage.dll را برای معرفی به برنامه مشخص نمائید.
به این ترتیب نگارش قدیمی افزونه Reflector.ReflectionEmitLanguage.dll با نگارش جدید برنامه Reflector سازگار خواهد شد.
سورس تغییر یافته این افزونه را از اینجا نیز می‌توانید دریافت کنید:
بدیهی است به ازای هر نگارش جدید Reflector، یکبار باید قسمت الف توضیحات فوق تکرار شود.
مطالب
چطور باید یک پروژه سورس باز را خوب مدیریت کرد؟
اگر مایل هستید که پروژه خود را به صورت سورس باز ارائه دهید، نیاز است یک سری شرایط را رعایت کنید تا کاربران این پروژه بتوانند به سادگی از آن استفاده نمایند.

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

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

ب) وضعیت بلوغ پروژه خود را مشخص کنید
آیا از این برنامه، مدتی است که در محیط کاری استفاده می‌کنید؟ آیا به نظر شما هنوز ناتمام است؟ آیا API کتابخانه شما در نگارش بعدی کاملا دگرگون خواهد شد؟ تمام این مسایل و سؤالات را به نحو واضحی توضیح دهید و مشخص کنید. همین توضیحات کوتاه می‌توانند ساعت‌های بسیاری از زندگی دیگران را صرفه جویی کند.

ج) اگر پروژه شما یک کتابخانه است، نوع زبان و Runtimeهای پشتیبانی شده را مشخص کنید
برای مثال اگر یک کتابخانه دات نتی را ارائه می‌دهید، مشخص کنید که از کدام نگارش دات نت به بعد را پشتیبانی می‌کنید.

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

- یک پروژه نیاز به مستندات دارد
مستند سازی کار، سخت و زمانبر است؛ اما بهترین لطفی است که می‌توانید به کاربران خود نمائید. مستندات نه تنها زمان جستجوی بسیاری را صرفه جویی خواهند کرد، همچنین حس اطمینان خاطر را به کاربر القاء می‌کنند. از این جهت که احساس می‌کنند شما برای کارتان ارزش قائل بوده‌اید و احتمال اینکه این برنامه در آینده نزدیک به یک abandonware تبدیل شود، کم است (منظور یک برنامه فراموش شده و خاتمه یافته).

- به روز رسانی را ساده کنید
بالاخره زمانی نیاز خواهد بود تا نگارش جدیدی از کار خود را ارائه دهید. در این حالت نیاز است یک سری از شرایط را مدنظر داشته باشید:
الف) سازگاری قبلی را مدنظر داشته باشید
یکی از بدترین حالات به روز رسانی یک کتابخانه زمانی است که کاربر آن با ده‌ها خطای کامپایل حاصل از به روز رسانی مواجه شود. اگر نیاز است قسمتی از کد خود را حذف کنید یا تغییر دهید، استفاده از ویژگی Obsolete را فراموش نکنید و اینکار باید مرحله به مرحله انجام شود. در یک نگارش، ویژگی Obsolete را معرفی کنید. در دو نگارش بعد، API را تغییر دهید.
ب) حتما یک Change log را تکمیل کنید
پس از ارائه یک نگارش جدید، حداقل در چند سطر مشخص کنید که چه مواردی تغییر کرده‌اند، چه مواردی اضافه شده‌اند و چه مواردی را حذف کرده‌اید.
همچنین اگر مواردی تغییر کرده‌اند، نحوه ارتقاء کدهای قدیمی را به نگارش جدید، شرح دهید. اگر مورد جدیدی اضافه شده‌است، لینکی را به مثالی درباره‌ی آن ارائه دهید.

- نگارش‌های جدید را اعلام کنید
برای مثال در طی ارائه یک مطلب جدید در وبلاگ خود، ارائه نگارش جدیدی از کتابخانه یا برنامه خود را به عموم اعلام کنید. در این حالت، حتما لینکی را به change log، ارائه داده و مشخص کنید که وضعیت سازگاری آن با قبل چگونه است.

- محلی را برای دریافت بازخوردهای پروژه خود مشخص کنید
نیاز است بتوانید پروژه خود را پشتیبانی کنید یا به سؤالات مربوطه پاسخ دهید. اگر سورس کنترل یا برنامه مدیریت پروژه شما، امکان پرسش و پاسخ را دارد، که بسیار خوب. اگر خیر، می‌توانید مثلا یک گروه گوگل جدید و امثال آن‌را برای دریافت بازخوردهای پروژه ایجاد کنید.
همچنین نیاز است لینک به این محل را در فایل ReadME پروژه به صراحت مشخص کنید.

- گذر از پروژه
بالاخره روزی فراخواهد رسید که دیگر علاقه‌ای به نگهداری پروژه نداشته باشید. این مساله را در مکان جمع آوری بازخوردهای خود اعلام کنید یا شخص دیگری را به نگهداری پروژه دعوت نمائید. اگر این کار را انجام ندهید، سبب خواهید شد forkهای متعددی از این پروژه بی‌جهت ایجاد شده و در نهایت مشخص نباشد که کدامیک بهتر است و کدامیک مشکلات کمتری دارند.