وب‌سایت شخصی من

بالاخره من هم در آخرین روز سال ۲۰۱۰ تسلیم وسوسه شدم و یک domain اختصاصی به آدرس http://afsharm.com ثبت کردم. از این به بعد اطلاعات مربوط به خودم را در اینجا قرار می‌دهم. وبلاگم هم از آدرس قبلی به آدرس http://blog.afsharm.com منتقل شده است. البته این همان وبلاگ اصلی خودم است که فقط آدرسش عوض شده. یعنی اگر از طریق فید مطالب را دنبال می‌کرده‌اید نیاز به تغییر چیزی ندارید. علاوه بر این همه لینک‌های قبلی هم همچنان کار می‌کنند. چون هر ارجاعی به آدرس قبلی وبلاگم به آدرس جدید آن Redirect می‌شود.

محدودیت‌های شدید در استفاده از منابع image/file hosting مجانی، پیش‌بینی محدودیت‌های جدید در راستای محدودیت‌های سه‌گانه اینترنت و اعتبار نسبی domainهای اختصاصی نسبت به آدرس‌های عمومی مثل blogspot از جمله دلایل این مهاجرت بود. مشتاق شنیدن نظرهای دوستان هستم.

‫پیدا کردن پروژه‌ی خوب در vWorker

مدتی است که در راستای «‫کار پروژه‌ای در سایت‌های Freelance» سایت vWorker.com را به دنبال پروژه‌های برنامه‌نویسی زیر نظر دارم به این امید که بتوانم روی آنها Bid دهم و چیزی برنده شوم. به همین دلیل پروژه‌ها را به دسته‌های زیر تقسیم کردم:

تقسیم بندی

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

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

‫برنامه‌های مربوط به یک platform خیلی خاص مثل facebook یا iPhone
پروژه‌های تقلیدی و clone. کار خاصی که فلان نرم‌افزار یا وب‌سایت مشهور می‌کند، من هم بتوانم بکنم یا این که من هم عین همان را داشته باشم:
کارهایی که نیاز به دانستن یک روش یا الگوریتم خاص دارد و بیشتر شبیه به پروژه‌های دانشجویی هستند:
پروژه‌های وصله پینه‌ای که یا برنامه‌نویس قبلی آن را نیمه کاره گذاشته، یا یک برنامه قدیمی است که سال‌ها پیش نوشته شده
پروژه‌های دستکاری و کمکی. مثلاً برنامه‌ای بنویسید که خروجی فلان برنامه‌ی عجیب و غریب را گرفته، یک سری اطلاعات از آن استخراج کرده و به خورد یک برنامه‌ی عجیب و غریب دیگر بدهد.
پروژه‌های استخراج اطلاعات از صفحات سایت‌ها که خیلی هم زیاد هستند:
البته نا امید نشوید اگر در طول یک دوره زمانی یکی دو ماهه سایت را زیر نظر بگیرید چندتایی پروژه‌ی مناسب و بعضاً بزرگ هم پیدا می‌شود که ارزش کار کردن داشته باشند:
نکات

در طول این مدت که vWorker را زیر نظر داشته‌ام به نکاتی پی برده‌ام. هر چند که این نکات در مورد پروژه‌های خوب vWorker زیاد صدق نمی‌کنند اما در مورد بیشتر پروژه‌ها این نکات وجود دارند:

۱- به نظر می‌رسد vWorker شبیه به ادارات و سازمان‌های داخلی خودمان باشد که همیشه درخواست‌های عجیب و غریب دارند و می‌خواهند این درخواست‌ها با زمان و هزینه‌ی خیلی کم انجام شود.

۲- vWorker بیشر برای کسانی مناسب است که همان پروژه‌ها یا برنامه‌ها را قبلاً به نحوی انجام داده و سورس آن را دارند. حالا فقط باید آن را کمی دستکاری کرده و مجدداً بفروشند.

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

۴- بیشتر پروژه‌های خوب vWorker دیتابیسی هستند. یعنی پیچیدگی خیلی خاصی نداشته و مشابه سیستم‌های مالی-اداری خودمان هستند.

۵- هر روز تعداد زیادی پروژه به vWorker اضافه می‌شوند. اگر می‌خواهید با سرعت بیشتری پروژه‌های خوب‌تر را پیدا کنید در دسته‌بندی‌هایی مثل C#‎، ASP.NET وDesktop Applications بیشتر بگردید. چون در آنجا پروژه‌های بهتری وجود دارد. سورت کردن بر اساس تعداد Viewهای یک پروژه یا rating شخص سفارش دهنده هم می‌تواند کمک خیلی خوبی برای پیدا کردن سریع‌تر پروژه‌های بهتر باشد.

Update Schema in Castle ActiveRecord

NHibernate has a feature named “Schema Update”. This feature help updating schema of existing database based on new changes in mapping files. Schema update do not change current data, just changes schema (table, view, … structure) in an additive manner. Castle ActiveRecord exposes this feature too.

The problem is with NHibernate you have choice for seeing update scripts first and if you were satisfied then do actual update. But in Castle ActiveRecord you must do actual update without any preview of possible changes. This is all because ActiveRecordStarter.UpdateSchema() does not emit NHibernate.SchemaUpdate.Execute’s parameters “scriptAction” and “doUpdate” to the user. It calls SchemaUpdate as follow:

updater.Execute(false, true);

As I needed schema update in Castle ActiveRecord with preview update scripts option, I wrote a method for it:

private static IList UpdateSchema(Action action, bool doUpdate)
{
CheckInitialized();
ArrayList exceptions = new ArrayList();


foreach (Configuration config in ActiveRecordMediator.GetSessionFactoryHolder().GetAllConfigurations())
{
SchemaUpdate updater = CreateSchemaUpdate(config);

try
{
updater.Execute(action, doUpdate);

exceptions.AddRange((IList)updater.Exceptions);
}
catch (Exception ex)
{
throw new ActiveRecordException("Could not update the schema", ex);
}
}

return exceptions;
}

private static void CheckInitialized()
{
if (!ActiveRecordStarter.IsInitialized)
{
throw new ActiveRecordException("Framework must be Initialized first.");
}
}

private static SchemaUpdate CreateSchemaUpdate(Configuration cfg)
{
return new SchemaUpdate(cfg);
}

Hope Castle ActiveRecord add an overload to ActiveRecordStarter.UpdateSchema that let seeing update schema scripts before actually doing the update.

‫رکورد اضافی در NHibernate

من مشکلی با NHibernate دارم که نمی‌دانم آیا بقیه هم این مشکل را با NHibernate یا دیگر ORMها یا حتی ADO دارند یا نه. البته اصل این مشکل در صفحات ASP.NET Webform وجود دارد. مشکل این است که وقتی می‌خواهم یک آیتم را در دیتابیس ذخیره کنم یا حتی وقتی می‌خواهم یک رکورد را روی صفحه نمایش دهم مجبور می‌شوم یک یا چند رکورد اضافی را هم از دیتابیس بخوانم.

به عنوان مثال یک صفحه ASP.NET را به شکل زیر تصور کنید:





protected void btnSave_Click(object sender, EventArgs e)
{
Company company = new Company()
{
City = City.Find(drpCity.SelectedValue),
Address = txtAddress.Text
};

company.Save();
}


protected void Search()
{
IList result = MyCustomSearch.SearchCompanies(
City.Find(drpCity.SelectedValue), txtAddress.Text);

//display results in GridView
}

در صفحه بالا، همه Cityها به طور خودکار به drpCity بایند می‌شوند. سپس با کلیک روی دکمه btnSave یک Company با کمک اطلاعات txtAddress و drpCity ذخیره می‌شود. البته کد بالا با Castle ActiveRecord نوشته شده ولی اصل مشکل با دیگر ORMها همان است. همان طور در متود btnSave_Click مشاهده می‌کنید من مجبور هستم برای ذخیره آبجکت Company یک بار به دیتابیس مراجعه کرده و City مورد نظر را از آن فراخوانی نمایم. در متود Search هم همین اتفاق می‌افتد چون متود SearchCompanies پارامتری از نوع City نیاز دارد.

مدتی است که با خودم فکر می‌کنم اگر بتوان این مراجعات بی‌مورد به دیتابیس را حذف کرد، به performance بسیار بهتری می‌رسیم. به همین دلیل به دنبال راه‌هایی هستم که نیاز به load مجدد object را از بین ببرد. در اولین قدم می‌توان همه‌ی متودهایی را که به عنوان ورودی به کل object نیاز دارند را پیدا کرده و آنها را طوری تغییر دهیم که صرفاً بتوانند با ID آبجکت مورد نظر کار کنند. مثلاً متود زیر را در نظر بگیرید:

IList SearchCompanies(City city, string address)
{
var query = from company in ActiveRecordLinq.AsQueryable()
where City == city
select company;

//...
}

این متود را به راحتی می‌توان طوری تغییر داد که به جای City از CityID استفاده کند:

IList SearchCompanies(long cityID, string address)
{
var query = from company in ActiveRecordLinq.AsQueryable()
where City.ID == cityID
select company;

//...
}

بی‌توجهی به گزارشات سیستم

یکی از مراحل تولید هر سیستمی بخش گزارشات آن است. با این که در بیشتر سیستم‌ها خصوصاً سیستم‌های مالی و اداری و امثال آنها که پر از Businness هستند، درک و پیاده‌سازی گزارشات بخش مهمی از سیستم را تشکیل می‌دهد، ولی متاسفانه اهمیت کافی به آنها داده نمی‌شود.

معمولاً در تحلیل و طراحی سیستم چندان توجهی به گزارشات نشده و پیاده‌سازی آن تا آخرین روزهای فاز توسعه عقب انداخته می‌شود. در چنین روزهایی هم افراد اصلی تحلیل و طراحی چندان در دسترس نیستند، دیگر افراد تیم تا اندازه‌ای منطق پشت گزارشات را به فراموشی سپرده‌اند و حتی نمایندگان مشتری هم عوض شده یا دیگر وقت کافی برای پاسخگویی به سوالات مجری را ندارند. علاوه بر این‌ها اگر برای پیاده‌سازی گزارشات نیاز به دستکاری مختصری در ساختار برنامه یا جداول آن باشد انجام آن کمی سخت می‌شود چون ساختار برنامه در مراحل قبلی نهایی شده و به تایید رسیده. در بعضی شرکت‌ها هم پیاده‌سازی گزارشات به طور کامل به افرادی سپرده می‌شود که تخصص آنها صرفاً کار با ابزارهای گزارش‌ساز مثل SQL Server Reporting Services است و چندان از Businness سیستم خبر ندارند.

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

Limitations of LINQ-to-NHibernate

Some applications are using NHibernate 2.1.2 yet. So they are forced to use old LINQ-to-NHibernate that comes with NHibernate 2.1.2 and can’t benefit new LINQ provider in NH 3.

There are two annoying problems with old LINQ-to-NHibernate. The first is inheritance related queries: “is” operator can’t be used. The second problem is not supporting “distinct”. For the first problem I added a read-only formula field based on discriminator column to “hbm” mapping file. After this, a query can use this fake field instead of “is” operator. But for the second problem I didn’t find any solution. Possibly I should use ICriteria instead of LINQ-to-NHibernate.

More info: link 1, link 2, link 3.

محدودیت‌های سه گانه در اینترنت

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

یک: محدودیت دولتی
دولت بنا به دلایل خاص خودش دسترسی به بسیاری از سایت‌های اینترنتی را مسدود کرده. تا زمانی که این سایت‌ها فقط سایت‌ها خبری فارسی و حتی خبری انگلیسی زبان و سایت‌های غیر اخلاقی (نسبت به عرف رایج جامعه ما) بودند نگرانی زیادی وجود نداشت. اما وقتی که دایره حملات گسترش یافت و به جای بستن یک یا چند وبلاگ خاص کل وردپرس (صفحه login یا صفحه tagها) بسته شد و وقتی که ف.ی.ل.ت.ر.ی.ن.گ کور شد و هر نوع search گوگل را که دارای کلمات دو پهلو بودند را هدف قرار داد (مثلا عبارت asp.net error number assembly version 1.xxx را در گوگل جستجو کنید) و وقتی که امکانات اجتماعی مشترک مثل FeedBurner در محاق توقیف فرو رفت، دیگر نمی‌شد نگران نبود. با این محدودیت‌ها استفاده از اینترنت حتی برای کسانی که فقط قصد استفاده از اینترنت برای موارد فنی و علمی را داشتند هم به شدت سخت شده است.

دو: محدودیت‌های بین‌المللی
سایت‌های خارجی خصوصاً آمریکایی هم ما را بی‌نصیب نگذاشته‌اند. روز به روز سرویس دهندگان بیشتری ما را از دایره خارج می‌کنند. یک بار SourceForge نمی‌گذارد پروژه‌ها Open Source را دانلود کنیم. یک بار گوگل جلوی استفاده از Chrome را می‌گیرد. یک بار فلان Data Center که اتفاقاً تعدادی سایت برنامه‌نویسی معروف را هم میزبانی می‌کند جلوی IPها ایرانی را می‌گیرد و همین طور الی آخر. توی خیلی از سایت‌ها موقع ثبت نام از شما قول می‌گیرند که نکند یک وقت ایرانی باشید! بیشتر سایت‌ها هم که در لیست کشورهایشان اصلاً اسم ایران را ندارند. آن وقت ما بیچاره‌ها مدام باید IPمان را از این و اون مخفی کنیم که مبادا هویت‌مان معلوم شود. هر جا هم خواستیم عضو شویم خودمان را اماراتی، عراقی یا افغانستانی معرفی کنیم.

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

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

خاطرات شاد مخصوص یلدا

دوست خوبم آقای مجید آواژ (وبلاگ بهساد) من را دعوت کرده به یک بازی وبلاگی به نام «خاطراتی برای یلدا» که قرار است ذکر چند خاطره‌ی شاد مخصوص شب یلدا باشد. هر چند که الان یک شب از یلدا گذشته اما این هم سهم من از این بازی:

آتاری

یکی از زنده‌ترین خاطرات شاد دوران کودکی من مربوط می‌شود به بازی با آتاری. حول و حوش سال ۱۳۶۴ یا ۱۳۶۵ من و برادرهام می‌مردیم برای یک دقیقه آتاری بازی خصوصاً دو مدل بازی هواپیما، زیر دریایی و دزد و پلیس. اون موقع هر چقدر پول توجیبی و توان التماس کردن داشتیم را جمع می‌کردیم تا بتوانیم یک شب آتاری کرایه کنیم با دسته گوشت کوبی یا دسته خلبانی! فیلم‌های ۳۲ لبه یادتون می‌یاد؟ آتاری و ساعت دیجیتال اولین برخوردهای من با دنیای کامپیوتر بودند و فکر می‌کنم از همون جا بود که افتادم تو خط کامپیوتر. البته چند وقت بعد بمباران‌های هوایی شدید غرب کشور شروع شد و روزگارمان را سیاه کرد.

نمره ۱۰

در دوران دانشگاه برای ما که نرم‌افزاری بودیم درس آمار و احتمال درس کم اهمیتی بود و تقریباً پیش‌نیاز هیچ درس دیگه‌ای نبود. من هم چون با ریاضیات کلاسیک به شدت مشکل داشتم این درس را گذاشته بودم برای آخرین ترم. آخر ترم امتحان خیلی سختی بزگرار شد و من که فکر می‌کردم بتوانم نمره قبولی بگیرم ۳ گرفتم! ۷ نمره زیر نمره قبولی. التماس و گریه و زاری به استاد هم هیچ افاقه‌ای نکرد. فکر می‌کردم حسابی بدبخت شده‌ام. چون تمام برنامه‌های سربازی، کار و خونه‌ی اجاره‌ای با افتادن اون درس لعنتی به هم می‌خورد. قرار شده بود استاد مربوطه نمرات قطعی را چند روز دیگر اعلام کند. روز اعلام نمرات به دانشکده ریاضی رفتم و با کمال ناباوری دیدم نمره‌ها رفته روی نمودار و نمره من ۱۰ شده بود! داشتم از خوشحالی بال در می‌آوردم. اون روز فقط توی دانشگاه راه می‌رفتم و به همه می‌گفتم که چه *ر شناسی آورده‌ام! اون روز دقیقاً اول بهمن ۱۳۸۱ بود. هنوز هم که هنوزه روزهای اول هر ماه را به افتخار اون استاد بامرام جشن می‌گیرم. استاد باز هم دمت گرم!

رژه

بهمن ۱۳۸۲ در پادگان ولیعصر تبریز در حال گذراندن دوران آموزشی بودم. تقریباً ۴۰ روز از شروع دوره گذشته بود و بچه‌های گروهان ۱۰۱ هم رژه را خوب یاد گرفته بودند و هم حسابی با هم هماهنگ شده بودند. تمرینات بدنی زیاد ۴۰ روز گذشته و منظم شدن ساعات خواب و غذا هم باعث شده بود بدنم سرحال بیاد و حسابی نرم بشه. شاید برای خیلی‌ها باور کردنش سخت باشد اما رژه‌های روزهای آخر آموزشی جز شادترین لحظات آن دوران من حساب می‌شد. وقتی که همه افراد گروهان با اون ژ-۳ های یک تنی هماهنگ با طبل کوچک و بزرگ پا بر زمین می‌کوبیدند زمین می‌لرزید. لرزش زمین، نظم و انضباط فوق‌العاده، اسلحه‌های ژ-۳ و آمادگی بدنی چنان حس قدرتی در آدم ایجاد می‌کرد که فکر می‌کرد همین الان می‌تواند با هر ارتش دیگری در دنیا بجنگد. البته ناگفته نماند که ما نیروی انتظامی بودیم نه ارتش!

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

جمع‌های برنامه‌نویسی

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

متاسفانه چنین جمع‌هایی در حوزه برنامه‌نویسی و توسعه‌ی نرم‌افزار کم هستند و اگر هم هستند در موضوعات خیلی پراکنده‌ای کار می‌کنند. معمولاً همکارات داخل شرکتی هم هر کدام روی یک بخش متفاوت کار می‌کنند و نمی‌توانند جمع‌هایی راجع به مثلاً C#‎، Software Design، ORM و… تشکیل دهند یا اگر هم بتوانند، افراد جمع بیش از دو سه نفر نخواهد بود.

یکی از راه‌های جایگزینی که جدیداً برای این مشکل پیدا کرده‌ام، حضور مستمر در StackOverflow است. کاربران این سایت می‌توانند تعدادی tag مثل nhibernate، tfsbuild یا log4net را به عنوان tagهای مورد علاقه اضافه کرده و سوال و جواب‌های آنها را به طور مداوم زیر نظر داشته باشند. به این ترتیب می‌توانند نظرات و تجارب آدم‌های مختلف را دیده و در پاسخگویی و نظر دهی شرکت کنند. علاوه بر این سایت StackOverflow جدیداً بخش جدیدی به عنوان chat به سایت خودش اضافه کرده که آن هم می‌تواند ذره‌ای از این خلأ تنهایی تکنولوژیک را کم کند.

‫IEnumerable و IQueryable

اگر می‌خواهید از یک کوئری LINQ به عنوان خروجی یک متود استفاده کنید دو راه برای آن وجود دارد. یکی آن که خروجی متود را از نوع IEnumerable تعریف کنیم و یکی دیگر آن که خروجی آن را از نوع IQueryable تعریف کنیم. استفاده از IEnumerable به معنی پایین آمدن Performance است. به همین دلیل بهتر است از IQueryable استفاده کنیم. نکته‌ی جالب‌تری که فهمیدم این است که اگر از IEnumerable به عنوان خروجی متود استفاده شود دیگر نمی‌توان از متودهایی نظیر Skip و Take که در Data Pagination استفاده زیادی دارند استفاده کرد. به عنوان مثال به کد زیر دقت کنید:
IEnumerable MakeQuery()
{
  var query = from m in session.Linq()
              select m;
  return query;
}

List m1()
{
  return MakeQuery()
    .Skip(10)
    .Take(20)
    .ToList();
}
توابع Skip و Take در متود m1 بی‌تاثیر هستند. البته نه این که عمل نمی‌کنند بلکه باعث می‌شوند کل دیتا از منبع مورد نظر، که در مورد من Linq-to-NHibernate و دیتابیس بود، فراخوانی شوند نه آن که صرفاً آن بخش خاص بازیابی شوند.