2010/09/28

Backing up TFS 2010

While using TFS 2010 as the only repository of source code and project management repository for a company with more than 10 developer, it is very important to handle backup/restore plans as accurate as possible. As I needed to backup such a TFS server correctly, I have compiled a check list for myself that I'd like to share it with all.



1. DVD of softwares must be kept at a separate reachable place. Including  Windows Server 2008 R2, SQL Server 2008, TFS 2010, SharePoint and any original/modified template process like Scrum for Team System version 3's x64 template process.

2. Know of any good online/offline documentation for backup/restore: Backing up and Restoring Your Deployment. Some good key points of this document are:
-Databases to backup: TFS_Configuration, TFS_Warehouse, TFS_CollectionName (all collections), TFS_Analysis (if any), ReportServer, ReportServerTempDB, WSS_Config (if any), WSS_Content (if any), WSS_AdminContent (if any)
-TFS_Configuration database must be last database to backup and first database to restore.

3. Backup the Reporting Services Encryption Key using "Reposrting Services Configuration Manager".  It's a tiny file. This file must be protected with a password. Don't forget to write down the password for future use. Alternatively you can use a simple password like 123 so you never forget it.

4. Use this guidline for: Restore Data to the Same Location and use this for Restore a Single Server Deployment to New Hardware.

5. You can always use a virtual machine to test you backups.




2010/09/25

مشکل ارتقای اجزای نرم‌افزار

یکی از مشکلات بزرگی که نرم‌افزار نویس‌ها مدام با آن دسته و پنجه نرم می‌کنند مشکل ارتقا اجزا و بخش‌های مختلف یک نرم‌افزار است. برای این مشکل مثال‌های زیادی وجود دارند:
۱- برنامه را با VB6 نوشته‌اید ولی حالا که به VB.NET ارتقا داده‌اید متوجه شده‌اید که پیش‌فرض VB.NET برای اعضای کلاس private است نه public.
۲- برنامه را با NHibernate 1.2 نوشته‌اید ولی بعد از ارتقا به NHibernate 2.0 فهمیده‌اید که برنامه با آن configuration قدیمی کار نمی‌کند و باید web.config/app.config را هم عوض کنید.
۳- برنامه را با فلان library نوشته‌اید و بعد از ارتقا به نسخه جدید فهمیده‌اید که نسخه جدید به خیلی از مسائلی که قبلاً گیر نمی‌داد حالا گیر می‌دهد و نمی‌گذارد برنامه اجرا شود.
۴- در برنامه‌های ASP.NET از کنترل‌های Telerik استفاده کرده‌اید و بعد از ارتقا فهمیدید که tagهای استفاده شده در markup اسمشان عوض شده و حالا دچار parser error شده‌اید.
۵- در برنامه‌ای که برای ویندوز ۹۵ نوشته شده از یک API خاص استفاده شده که دیگر در ویندوزهای جدیدتر وجود ندارد.
۶- در بخشی از برنامه از نسخه x یک library استفاده کرده‌اید و بعداً لازم می‌شود بخشی از یک نرم‌افزار دیگر را به نرم‌افزار فعلی‌تان الحاق کنید اما این بخش جدید از نسخه y استفاده می‌کند نه x.
۷-...

این مسئله که برای برنامه‌نویسان عذاب‌آور و برای مدیران ترس‌آور است را می‌توان به دو بخش خارجی و داخلی تقسیم کرد. بخش خارجی مربوط است به dllها، libraryها، APIها و platformهایی که از خارج شرکت/تیم می‌آیند و معمولاً حق انتخاب زیادی در مورد آنها وجود ندارد. بخش داخلی مربوط است به اجزا و dllهایی که در داخل شرکت ساخته می‌شود و version زدن آنها یک مصیبت بزرگ است. در مورد dllهای داخلی مسئله backward comaptiblity و وابستگی به dllهای دیگر هم باید چک شود. چیزی که معمولاً در مورد dllهای خارجی بهتر رعایت می‌شود.


برای کاهش مشکلات ارتقا به نظر بنده موارد زیر را می‌توان در نظر گرفت:
۱- مثبت‌نگر باشید. ارتقا dllها خصوصاً در مورد dllهای خارجی معمولاً نوید دهنده امکانات بهتر و کامل‌تر است. معمولاً هدف از ارائه نسخه جدیدتر رفع اشکالات نسخ قبلی، بهبود عملکرد و… است. پس بنابراین خوشحال باشید که رفع مشکلات مربوط به نسخه جدید به معنی ارتقا کیفیت نرم‌افزار شما خواهد بود.
۲- پیروی از اصل KISS (Keep It Simple Stupid)‎: یعنی تا آنجا که می‌توانید برنامه را ساده نگه داشته و بیخودی از هر کتابخانه، class و dll دیگری استفاده نکنید.
۳- Dependency Injection: برنامه‌ها با حداقل وابستگی به هم نوشته شوند.
۴- موتوا قبل ان تموتوا (بمیرید قبل از آن که بمیرید): قبل از آن که مجبور شوید ارتقا دهید، ارتقا دهید. تولید کنندگان نرم‌افزار معمولاً قبل از ارائه نهایی نسخ جدید آنها را به صورت نسخه‌های آزمایشی ارائه می‌دهند و حتی قبل از آن کلی بحث راه می‌اندازند، نظر سنجی و اطلاع‌رسانی می‌کنند که ما قرار است فلان چیز را به نرم‌افزارمان اضافه کنیم یا تغییر بدهیم. بنابراین فرصت خیلی زیادی دارید که خود را به موقع ارتقا دهید.
۵- پیروی از تجارب TDD مثل Unit Test و Continuous integration: این راه‌حل خصوصاً در مورد dllهای داخلی خیلی خوب جواب می‌دهد. اگر برای همه بخش‌هایی ممکن unit test نوشته باشید آن وقت نگرانی کمتری برای ارتقا دارید چون خیلی سریع می‌فهیمد که آیا چیزی خراب شده یا نه. Continuous integration هم به همین شکل کمک می‌کند که در حداقل زمان ممکن خطا را کشف کنید.
۶- به هیچ وجه Warningهای هنگام کامپایل را دستکم نگیرید. خیلی از warningهای نسخه امروز به compile errorهای نسخه فردا تبدیل خواهند شد.
۷- استفاده از الگوهای جدیدی مثل MVC چون کار تست را راحت‌تر کرده و decoupling که با استفاده از dependency injection محقق می‌شود را بهتر اجرا می‌کنند.




شما چه راه‌هایی برای کاهش این طور مشکلات سراغ دارید؟




2010/09/21

Continuous Integration with TFS

It's a few months that I am dealing with continuous integration, automatic builds, TFS and Team Foundation Build deeply. Experiences during this period learned me some points that I'm glad to share with all:

1. Don't assume anything about build agent. Specifically don't assume any library is installed on the agent, any assembly registered in build agent's GAC, any specific file/folder structure exists in build agent, etc. Otherwise you may encounter build breaks in other agents or at another time. Best practices here is to assume that build agent has just .Net framework installed on it and nothing more.

2. Always add assembly references from source control maintained dlls in same project and just as relative path not as absolute path. Otherwise you may encounter build breaks.

3. Never ever let anyone direct access to live machine that is dedicated to install continuous integration results instantly, specifically for web application projects. Because someone may manually add/modify a file/folder in the web application path. So you may end with a software that needs manual modifications that are never documented nor automated.

4. Automate database creation. Either via maintaining database creation scripts in source control or with help of ORM's database auto generating feature.




2010/09/17

Implementing History model

In many applications, data change is tracked. For example in TFS whenever you change any section of a work item, you can then see that change has been logged in work item history. It says that, for instance, owner of work item or time estimation field has been changed from a value to another value. Another example is article history in Wikipedia. Both TFS and Wikipedia are large applications. So what should you do if you want to add history feature for a small or medium application? Suppose your application have 20 domain classes (tables) that all of them needs to keep tracking of changes. Is it a good idea to add an extra class/table for each of them to save their history? Is there any other way?

As a solution I used a simple way: having a single class/table as main history repository, using Xml Serialization for persisting changes and Reflection to explore field changes. This way you need to use two events of your ORM: AfterLoad and OnSave or something similar. You must serialize objects in AfterLoad as old (current) value, serialize each object in OnSave as new value, saving in database and consequently showing data change by deserializing them and using Reflection to explore changes. This way has a large overload as a very long record will be saved in database with each change in data, but if history feature is forced to be done then it is a concise and centralized solution. Specially when compared to ways that developer must save history manually by adding code to each UI section that modifies data.




2010/09/13

Using NHibernate event model in Castle ActiveRecord

Castle ActiveRecord is a thin layer over NHibernate and provides easy and fast use of NHibernate. Regarding data save/retrieve in Castle ActiveRecord, there is some useful events like OnSave and OnUpdate that can be utilized to automate features like automatic data tracing or data auditing. Unfortunately there is situations that we need events that are not supported directly in Castle ActiveRecord. For example we need an event like AfterLoad or PostLoad in order to do some specific operations in our application. But Castle ActiveRecord didn't provide us with such an event. Googling showed me that I can leverage NHibernate events to achieve this goal. But how can I catch firing of NHibernate's events in Castle ActiveRecord? This was not an easy question to be googled. BTW asking in StackOverflow and some extra googling here and here showed me the way.

Listening to NHibernate events in Castle ActiveRecord was very easier than I thought. All you must do is creating a class that implements a special interface and add a special attribute in class file. That's it. You are done! No need to modify web.config or add code when initializing Castle ActiveRecord. So here is my listener class:

using Castle.ActiveRecord.Attributes;
using NHibernate.Event;

[assembly: AddEventListener(typeof(MyNameSpace.MyPostLoadEventListener))]

namespace MyNameSpace
{
    public class MyPostLoadEventListener : IPostLoadEventListener
    {
        public void OnPostLoad(PostLoadEvent @event)
        {
            //do what ever you want with @event.
        }
    }
}




2010/09/09

پادکست‌های اسکات هنزلمن

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

تعدادی از پادکست‌های جالب اسکات:
۱- Learning about NHibernate 3 with Jason Dentler : فایل صوتی پادکست، فایل PDF

۲- Geek Relationship Tips with Scott's Wife : فایل صوتی پادکست، فایل PDF

۳- Aspect Oriented Programming (AOP) and LinFu with Philip Laureano : فایل صوتی پادکست، فایل PDF

۴- Jeff Atwood on the Future of Stack Overflow : فایل صوتی پادکست، فایل PDF

۵- John Lam and the Science of Fitness : فایل صوتی پادکست، فایل PDF

۶- Women in Technology in the Muslim World : فایل صوتی پادکست، فایل PDF

۷- Jon Skeet - World's Greatest Living Programmer, or just a nice English guy?‎ : فایل صوتی پادکست، فایل PDF

۸- Hello World: Computer Programming for Kids and Other Beginners : فایل صوتی پادکست، فایل PDF

۹- Spolsky, Atwood, Blyth, Hanselman = Crazy-Delicious || Content-Free?‎ : فایل صوتی پادکست، فایل PDF

۱۰- The Art of Unit Testing with Roy Osherove : فایل صوتی پادکست، فایل PDF




وبلاگ «اسکات هنزلمن»
بایگانی پادکست‌های «اسکات هنزلمن»




2010/09/05

Castle ActiveRecord and GridView's Paging and Sorting

Paging and sorting is a common need in ASP.NET applications. GridView itself have a default paging and sorting mechanism. Default paging has performance issues while manipulating large amounts of data. So people use a custom paging mechanism. This way they must note that only needed data must be extracted from database. For example when page 3 just shows 10 records from 21 to 30, there is no reason to load all data from database. With sorting there is two problem. First: default sorting mechanism only work with few specific data sources like Typed DataSet and not every other data sources like those come from NHibernate or Castle ActiveRecord. Second: default sorting sorts only current page not all data.

In order to have an efficient paging and proper sorting mechanism we should use custom paging and custom sorting. Scott Mitchell has a great tutorial series on paging and sorting with GridView. These series are based on an object data source of typed DataSets. So as I'm working with Castle ActiveRecord as my data access layer, I was unable to use Scott's solution. So I decided to create my own solution using Castle Active Record based on Scott's original solution.

Doing paging and sorting with Castle Active Record is very very easy. Because Castle ActiveRecord has an API dedicated to paging and sorting: SlicedFindAll. In my solution, firstly I have added 2 method to a typical domain class named Company, secondly notice GridView's markup that has no codebehind at all. Notice that all my domain classes are inheriting from ActiveRecordBase:

public static Company[] FindAll(int maximumRows, int startRowIndex, string sortExpression)
{
    Order[] orders;

    if (string.IsNullOrEmpty(sortExpression))
        orders = new Order[0];
    else
    {
        orders = new Order[1];
        const string DESC = " DESC";
        if (sortExpression.EndsWith(DESC))
            orders[0] = Order.Desc(sortExpression.Replace(DESC, string.Empty));
        else
            orders[0] = Order.Asc(sortExpression);
    }

    return SlicedFindAll(startRowIndex, maximumRows, orders);
}

public static int TotalCount()
{
    return Count();
}


<asp:GridView runat="server" ID="gvCompany" AllowPaging="true" AllowSorting="true"
    DataSourceID="odsCompany" DataKeyNames="Id">
    <Columns>
        <asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
        <asp:BoundField DataField="Address" HeaderText="Address" SortExpression="Address" />
        <asp:BoundField DataField="Tel" HeaderText="Tel" SortExpression="Tel" />
        <asp:BoundField DataField="Field" HeaderText="Field" SortExpression="Field" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource runat="server" ID="odsCompany" TypeName="MyDomainNamespace.Company"
    SelectMethod="FindAll" EnablePaging="True" SelectCountMethod="TotalCount" SortParameterName="sortExpression" />




2010/09/01

Pros and cons of declarative data binding in ASP.NET

While binding data to ASP.NET data aware controls like GridView and FormView, there is always two choices. Firstly you can do updating, inserting and deleting operations just in code behind. This way you should reference controls, get/set values and do actual operation in codebehind. Secondly it's possible to do almost everything in markup of your aspx/ascx declaratively. This way you just tell ASP.NET that which method it should use and ASP.NET take cares of it for you. What of this ways is better? I've thought of about it and here is my findings:



Pros

1. Need less logic in code.
2. All logic is centralized in a single place in the place where data source or data web control is defined.
3. You are not forced to work with sophisticated API of data web control events and properties.
4. Development with this style is fast.
5. Suitable for small/medium projects and average ASP.NET developers.

Cons
1. Working with none primitive data types is a bit hard.
2. Their bug will not be detected unless in runtime instead of compile time. Because field and method names names are defined as embedded strings and will not be checked during compile.
3. Debugging is hard as you can not set a break point in declarative code.
4. Testing is a bit hard.
5. Declarative data binding turns your program a bit inflexible. Because web controls is placed in item template and edit templates so accessing them is not so easy. One example is when you want to add an ASP.NET AJAX ConfirmButton to a GridView CommandField. For this purposes you should use various events.


References:
Scott Mitchel training series about data access in ASP.NET controls