احسان میرسعیدی

در جهان تنها یک چیز ثابت است، تغییر...

برنامه نویسی، حرفه ای مدرن یا کارگریِ نوین

خیلی خلاصه می خواهم در مورد دغدغه ای صحبت کنم که مدتی است ذهن ام را درگیر کرده است. دردِ مستور در سخن ام را آن هایی بیشتر درک خواهند کرد که مدت به نسبت زیادی است در این حوزه فعالیت می کنند. گمان می کنم حرف هایم برای جوان تر ها و نو رسیده هایی که در گیر زرق و برقِ فریب دهنده ی این حرفه مدرن شده اند، حرف های ناخوشایندی باشد که حتی آن را توهین به ساحت مدرن تکنولوژی قلمداد کرده و برخی گامی فراتر رفته و در ذهن خود این نوشته را به سان تسلیم شدن یک سرباز قدیمی در برابر دشمنی تندخو تصویر کنند.
من از دوم دبیرستان برنامه نویسی را با QBasic شروع کردم. پس از آن در سال 2005 برنامه نویسی با سی شارپ، تبدیل شده بود به عجیب ترین تجربه ای که یک پسر 17 ساله می توانست برای خودش خلق کند. خبری از اینترنت پرسرعت و اطلاعات مختلف نبود. به همراه ویژوال استودیو پکیجی با نام MSDN نصب می کردم که سرشار بود از اطلاعات ناب و غنی ایی که می توانستم تا سحر در آن غرق شوم و بخوانم و یاد بگیرم و لذت ببرم که چیز جدیدی فهمیده ام. در من تعهدی ایجاد شده بود تا بهترین و به روز ترین در حرفه خودم باشم. این "تعهد مسموم" تا امروز هم ادامه پیدا کرده است. خواندن ها و تمرین های بیمارگونه برای برتر بودن و عقب نماندن از زمان (= تکنولوژی) یعنی مطالعه کتاب های مختلف، وب سایت ها و وبلاگ ها و مجلات گوناگون و بازی کردن با هر ابزار جدیدی که هر احمقی می سازد تا به خیال خودش جهان بهتری خلق کند.


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


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



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


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


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

 

حمله Cross Site Request Forgery

عموما برنامه های وب به گونه ای توسعه داده می شوند که فقط در ظاهر کار کنند، بدون آنکه توسعه دهندگان توجهی به مسائل مربوط به امنیت داشته باشند. همچنین رواج انواع مختلف CMS ها موجب شده است تا بسیاری از توسعه دهندگان دغدغه مسائل حرفه ای تر را نداشته باشند و با این امید که CMS این مسائل را مدیریت می کند، از زیر بار مسئولیت کسب آگاهی، پیاده سازی و تست امنیتی شانه خالی می کنند. البته جالب است که سایت هایی مانند facebook هم در برابر این حمله آسیب پذیر بوده اند. ( لینک خبر )

حمله CSRF ( که Sea-Surf تلفظ می شود) یکی از انواع حملات رایج در دنیای وب می باشد و جزو OWASP TOP 10 می باشد. پیش از بیان یک مثال و شرح دقیق تر آناتومی و ویژگی های این حمله، ذکر نکات زیر مفید به نظر می رسند:

 

  •  این حمله به صورت مستقیم یک وب سایت را مورد هدف قرار نمی دهد. بلکه به طور غیرمستقیم و توسط یک واسط به هدف می رسد.

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

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

  • از آنجا که این حمله از session کاربر در سایت قربانی استفاده می کند، برای اینکه حمله موفقیت آمیز باشد حتما بایستی فرد قربانی دارای session فعالی باشد. در غیر این صورت حمله موفقیت آمیز نخواهد بود.

برای آنکه مطالب بالا را به صورت ملموس تری داشته باشیم، لازم است تا مثالی رو مطرح کنیم. برای بررسی سناریو، موجودیت های زیر را در نظر بگیرید:

 

  • سایت قربانی: این سایت دارای دامنه فرضی www.safebank.com می باشد.

  • شخص قربانی: این شخص – که از قضا فرد ثرومندی نیز هست - با نام کاربری victim در سایت قربانی عضو می باشد و دارای session فعالی در  سرور www.safebank.com می باشد.

  • شخص بدخواه: این شخص تلاش می کند تا از session  کاربر استفاده کرده و به نیابت از victim به انتقال مبلغ هنگفتی بپردازد.

حال شخص بدخواه می تواند ایمیلی را به victim ارسال کند. در این ایمیل که در قالب HTML می باشد، می تواند المان زیر را قرار دهد:

<img src="http://www.safebank.com/user/victim/transaction?to=hackeraccount&amount=5000$" height=0 width=0 />

با وجود این المان، مرورگر درخواستی را به آدرس زیر ارسال می کند. 

http://www.safebank.com/user/victim/transaction?to=hackeraccount&amount=5000$

نکته: مرورگرها وقتی درخواستی را برای یک آدرس ارسال می کنند، تمامی کوکی های مربوط به آن آدرس را همراه با هر بار درخواست ارسال خواهد کرد. پس در این سناریو، مرورگر به همراه ارسال درخواست به  www.safebank.com، کوکی ها و session مربوط به کاربر را نیز ارسال می کند. در نتیجه وب سایت قربانی گمان خواهد کرد که منبع درخواست از سمت victim می باشد.

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

نکته: در طراحی آدرس ها و API با معماری و ساختار RESTFULL هیچگاه نباید درخواستی که با متد get فرستاده می شود، در داده ها و وضعیت سرور تغییری ایجاد کند. متد get تنها باید برای خوانش اطلاعات استفاده شود. در نتیجه، هیچگاه کاربران نباید بتوانند تا ازطریق یک URL، در داده ها و وضعیت سرور تغییر ایجاد کنند. این امر البته درست برخلاف معماری سایت www.safebank.com می باشد. این مسئله همچنین باعث خواهد شد تا حملات CSRF به این راحتی رخ ندهند.

در نتیجه، اولین گام تغییر ساختار درخواست ها از متد get به متد post می باشد. در این صورت دیگر شخص بدخواه نمی تواند با ساختن یک لینک، victim را هدف قرار دهد. البته تغییر از متد get به post تنها روش حمله را عوض می کند، اما به هیچ وجه آسیب پذیری CSRF را از بین نخواهد برد. برای شرح حمله هایی از نوع post، سناریوی زیر را در نظر بگیرید:

  •  سایت قربانی: این سایت دارای دامنه فرضی www.safebook.com می باشد. این سایت یک شبکه اجتماعی است.

  • شخص قربانی: فرض می کنیم دوست دختر این شخص می خواهد از فعالیت های پنهانی او در این شبکه اجتماعی سر در بیاورد. این شخص با نام کاربری victim در سایت قربانی عضو می باشد و دارای session فعالی در  سرور www.safebook.com می باشد.

  •  شخص بدخواه: دوست دختر victim می خواهد تا ازsession  کاربر استفاده کرده تا رمزعبور victim را تغییر دهد و وارد پروفایل اش شود.

در ابتدا دوست دختر victim او را دعوت می کند تا به سایتی که به مناسبت سالگرد رابطه شان تهیه کرده است، سری بزند. اما او در این سایت اسکریپت زیر را قرار داده است:

 

<html>
<head>
    <title>Our Lovely Anniversary</title>
</head>
<body>
    <form name="badform" method="post"
     action="http://www.safebook.com/user/victim/profile">
        <input type="email" name="email" value="lovelygirl@gmail.com" />
    </form>
    <script type="text/javascript">
        document.badform.submit();
    </script>

    <!-- pictures and other stuffs -->
</body>
</html>

وقتی که victim مشغول مرور عکس ها و نوشته های عاشقانه سایت می باشد، مرورگر درخواستی را برای آدرس زیر، با استفاده از متد POST ارسال می کند:

http://www.safebook.com/user/victim/profile

این درخواست به صورت post می باشد و دوست دختر victim، ایمیل خودش را جایگزین ایمیل فرد قربانی می کند. حال او می تواند با استفاده از قابلیت forgot password، نام کاربری پروفایل victim را تغییر داده و وارد پروفایل قربانی شود!!!

 

روش های مقابله باآسیب پذیری CSRF

در مطلبی در وب سایت OWASP راه های مقابله به تفصیل توضیح داده شده اند. این روش ها به طور خلاصه به صورت زیر می باشند.

  1. استفاده از روش Challenge-Response: این روش کاربر پسند نیست و کاربر تجربه راحتی را نخواهد داشت. در این روش لازم است تا پیش از هر درخواست، سوالی از کاربر پرسیده شود. این سوال الزما بایستی تنها توسط انسان قابل پاسخ باشد. این روش ها می توانند به صورت های زیر باشند:

  • CAPTCHA

  • ReAuthentication:  از کاربر خواسته شود تا پیش از هر درخواست، نام کاربری اش را وارد نماید.

  • One-Time Token: یعنی به طریقی (با استفاده از یک دستگاه یا نرم افزاری در گوشی همراه اش) کاربر یک token معتبر بسازد و این token را لازم باشد تا به ازای هر درخواست برای سرور ارسال نماید.

     2. بررسی Referer: در هر درخواست HTTP در قسمت header، بخشی به نام Referer وجود دارد. این بخش مشخص می کند که درخواست از چه آدرسی برای سرور ارسال شده است. در نتیجه می توان با بررسی این مقدار، درخواست هایی که از سایت های غیر معتبر می آیند را فیلتر نمود. اما متاسفانه این روش، روش مقاومی در برابر حمله نیست. چرا که :

 

  • در برخی مواقع شخص بدخواه می تواند مقدار referer را تغییر دهد.

  • در برخی مرورگرها قابلیت referrer به دلایل امنیتی می تواند غیر فعال شود.

  • برخی از proxy ها مقدار referrer را تغییر می دهند.

 

    3. استفاده از روش Synchronizer Token Pattern: این روش، راه حل توصیه شده می باشد و بدون آنکه به دخالت کاربر نیازی باشد، ایمنی را فراهم می کند. ASP.NET MVC به صورت توکار از این روش پشتیانی می کند. این روش را به صورت مرحله به مرحله توضیح خواهم داد:

  • به ازای session کاربر، یک مقدار random در سمت سرور تولید می شود. (به طور مثال با مقدار AntiForgeryToken)

  • در هر کدام از HTML FORM های مهم وب سایت، یک hidden input با مقدار AntiForgeryToken قرارداده می شود.

  • وقتی HTML FORM ها به سمت سرور ارسال می شوند، سرور مقدار AntiForgeryToken ای که از سمت کاربر آمده است را با مقدار AntiForgeryToken مربوط به session کاربر که در سرور وجود دارد، مقایسه می کند.

  • در صورتی که این دو مقدار برابر بودند، درخواست معتبر شناخته می شود.

به طور مثال، form مثال قبلی به صورت زیر درخواهد آمد. این فرم در وب سایت www.safebook.com وجود خواهد داشت:

 

<form name="edit_profile_form" method="post"
     action="/user/victim/profile">
        <input type="email" name="email" value="lovelygirl@gmail.com" />
        <input type="hidden" name="csrftoken" value="AntiForgeryToken" />
    </form>

در این روش، درصورتی که وب سایت در برابر حمله XSS آسیب پذیر نباشد، شخص نفوذگر راهی برای بدست آوردن AntiForgeryToken نخواهد داشت. (به دلیل وجود قواعد SameOrigin Policy و  Cross Origin ResourceSharing که در مرورگر ها پیاده سازی شده است)

از هر پلتفرم وچارچوبی که استفاده می نماییم، بایستی بدانیم که این چارچوب چگونه در برابر حملات خود را ایمن می سازد و به توسعه دهنده چه امکاناتی را خواهد داد. در مطلب بعدی به توضیح مقابله با این حمله در ASP.NETMVC خواهم پرداخت.

 

چرا یک پروژه ملی شکست خورد؟

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

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

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

 

  1. ابزارهای توسعه بی کیفیت

        برای توسعه این سامانه از ابزاری به نام Wavemaker استفاده شده است. این ابزار اگر چه از فریم ورک های مهمی چون Hibernate و Spirng و Dojo بهره می گیرد اما به طور کلی ابزاری است که کاری جز خراب نمودن و کند کردن روند کار شما نخواهد داشت. این ابزار اگر چه ادعا می کند که از نوع RAD می باشد، اما هنر اصلی این ابزار ارائه کاری بی کیفیت، غیر قابل پیشبینی و زشت و برهنه (البته از لحاظ امنیتی!) است که در زمانی بسیار بیشتر از حداکثر زمان ممکن، طراحی و توسعه داده می شود. ابزاری است که جز در سایت خودش مطالبی در موردش پیدا نخواهید کرد. دنیای Wavemaker دنیای ایزوله ای است که از باقی فضای وب به شدت فاصله دارد و کسی که وقت و عمرش را هزینه کار با این ابزار می کند، عملا تبدیل به شخص بی سوادی می شود که نمی تواند بفهمد ابزار ها و مفاهیم مدرن - حتی قدیمی - و کاربردی حوزه وب چه می باشند. پس نه تنها عمرش را هدر می دهد، که شخصی می شود خام و بی تجربه که مهارت کار با ابزارهای شاخص وب را نخواهد داشت و از فرایند یادگیری و رشد عقب خواهد افتاد. اگر بخواهم در مورد چرایی انتخاب Wavemaker توضیح بدهم، باید بگویم این بر می گردد به انتخاب مدیران فنی مجموعه، که به عقیده من انتخاب اشتباهی بود. احتمالا گمان می کردند با این ابزار می شود کارها را با سرعت انجام داد، اما کسی که کمی تجربه توسعه وب داشته باشد، می داند چنین ابزاری به تنهایی می تواند پاشنه آشیل پروژه های بزرگ شود.

      2.  کم مهارت بودن اعضای تیم

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

       3.  کم بودن نفرات تیم

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

        4.  ضعف در استخراج نیازمندی ها

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

آن فرد کنار رفت و فرد دیگری به تیم ما اضافه شد و مسئولیت مصاحبه ها و استخراج نیازمندی ها را بر عهده گرفت. این فرد، متاسفانه پیش از این هیچ سابقه ای در نیازسنجی نداشت و نبایستی تمامی این کار در اختیار و حیطه مسئولیت این فرد، به تنهایی، قرار می گرفت. آیا جز این است که برای این مدیران، مبحث مهم و خطیر نیازسنجی، چیزی جز یک کار کم ارزش و فرمالیته نیست؟ حاصل کار این فرد هم این بود که در مدت 5 تا 6 ماه فعالیت اش، اگر چه زحمت بسیار کشید، اما به دلیل نداشتن تجربه و تصوری دقیق و جزئئ از کلیت کار، مسیر را اشتباه طی کرد. نه نتوانست به طور دقیق و جزیی فرایند های کاری کل سازمان، زیربخش ها و ارتباطات بین آن ها را در بیابد، و نتوانست از دانسته هایش به درستی بهره بگیرد و عملیات طراحی سامانه را به انجام رساند، او نتوانست که اطلاعاتی را که در مصاحبه و جلسات کسب کرده مکتوب کند و در اختیار تیم بگذارد. او نتوانست در مصاحیه هایش تفکرات ناصحیح کارفرما را اصلاح کرده و به او دید صحیح بدهد. او نتوانست در خلال مصاحبه هایش، ریزه کاری های مهمی را که از زبان کارفرما بیرون نمی آید، را بیرون بک��د. کار به گونه ای پیش رفت که ما بعد از 9 ماه، حتی یک صفحه از دانسته هایمان را مستند نکرده بودیم. مسئول همه این ها به عقیده من مدیرانی هستند که کارهای بزرگ را به افراد تازه کار می سپارند. از شخصی که مسئولیت استخراج نیازمندی های این پروژه بزرگ را بر عهده داشت، حتی درخواست تهیه یک صفحه مستند نشده بود.

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

          5. حقوق پایین و حتی عدم پرداخت

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

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

          6. دروغگویی در جلسات

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

           7. ارائه تخمین های غلط به کارفرما

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

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

           8. مهارت و تعهد پایین مدیران 

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

           9. عدم احترام به پرسنل

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

           10. عدم تعهد پرسنل به انجام کار خوب

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

          11. عدم وجود تست

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

          12. عدم مستند سازی

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

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

          13. عدم وجود متدلوژی برای توسعه نرم افزار  

          توسعه نرم افزار، بسیار وابسته به نحوه تعاملات اعضای تیم و رابطه  اصولی و تدوین شده کارفرما و پیمانکار می باشد. پروژه های بزرگ نرم افزاری را نمی توان به سبک یک هیئت اداره کرد و انتظار داشت تا همه چی طبق برنامه و خواست ذهنی ما پیش برود. بسیار بسیار پیشتر، بزرگان این صنعت در غرب این مسیر را طی کرده اند و از شکست های شان آموخته اند که باید پروژه های نرم افزاری بر اساس قاعده و اصول خاص و مشخصی در حیطه تولید، تعاملات داخلی و خ��رجی پیش برد. یادگیری اصولی  و رعایت این قوانین و چارچوب ها در کتاب ها پیدا نمی شود. نمی توان صرفا با مطالعه کتب مختلف راجع به SCRUM، به مدیریت نکات و تقاط بحرانی پروژه واقف شد. چرا که هر پروژه شرایط خاص خودش را دارد.
کارها در شرکت نظم و ترتیب مشخصی برای انجام نداشت. کارها زمان مشخصی برای پایان نداشت. برای همین کار برای مدت ها در شرکت به حال خود رها میشد. نبودن milestone و نداشتن deadline تیم را تنبل و بی انگیزه می کند. تیم برای جنگیدن بهانه و انگیزه ای نخواهد داشت و این اتفاق تیم را سست و فشل می کند. از طرف دیگر، نداشتن نظم موجب می شد تا کارفرما ناگهان اعلام کند که درخواست های زیادی را که در گذشته مطرح کرده برای یکی دو روز آینده می خواهد. این موجب میشد تا تیم از خواب خرگوشی بلند شود و شب و روز در شرکت بماند تا کار را تحویل دهد. (البته چه کاری!!!؟)
یکبار تلاش کردم تا در شرکت یک روش و چارچوبی شبیه SCRUM تهیه کنم  تا با همکاری تیم بتوانیم کار ها را منظم تر جلو ببریم. بورد هایی شبیه بورد های اسکرام تهیه کردیم و سعی نمودیم تا کارها و وظایف هر کس مشخص تر باشد. میزان سختی کارها و زمان پایان هر کار تعیین گردد. سعی کردیم در صبح ها جلساتی تشکیل دهیم و در مورد موانع پروژه با یکدیگر صحبت کنیم و از این قبیل کارها...!!! ناگفته پیدا است که این حرکت شکست خورد. دلیل آن هم چیزی جز این نیست که تدوین چارچوب برای تیم، بدون تدوین و تصویب چارچوب برای مدیران و کارفرما محتوم به شکست است. برای مدیر یا کارفرما، کارهای فعلی و برنامه تیم برای هفته آینده اهمیتی ندارد. از آنجا که کار بی برنامه است، آن ها از تیم می خواستند تا همه کارهایی را که برایش برنامه ریزی کرده کنار بگذارد و انبوهی از کارهای دیگری را که اخیرا تعریف شده، انجام دهد. به این ترتیب کارها، وظایف و برنامه هایی که تدوین کرده بودیم یتیم می شدند و کارهای جدید هم سرنوشتی مشابه پیدا می کردند. همین امر هم باعث شد تا هیچ گاه به طور قابل پیش بینی، با روندی آرام، مطمئن و البته مستمر، نتوانیم پروژه  را به پیش ببریم.
در ضمن نبود تعریفی برای مفهوم "The Definition Of Done" در تیم، موجب می شد تا نظارتی برای بررسی صحت ادعای نفر برای انجام وظیفه اش وجود نداشته باشد و صرفا به گفته او اتکا شود. این قضیه  و عدم تعریف فرایند نظارت موجب شد تا بسیاری از کارها، اگر چه به ظاهر و بنا بر ادعای اعضای تیم انجام شده بودند، اما از نقص های عمده و بعضا ابتدایی رنج می بردند.

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

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

بهینه سازی وب، حذف Render Blocking Scripts

در طراحی صفحات وب مفهومی به نام Above The Fold وجود دارد. این مفهوم از دنیای روزنامه نگاری به عاریت گرفته شده است و به معنای نیم صفحه بالایی و اولیه روزنامه است که در کیوسک ها پیش چشم مخاطبین قرار می گیرد و روزنامه ها سعی می کنند در این فضای محدود نکاتِ مهم خبری و عناوین اختصاصی شان را به همراه عکس و چیدمانی زیبا به مخاطبینشان عرضه کنند. در طراحی صفحات وب نیز این مفهوم به معنای آن بخشی از صفحه است که بدون اسکرول کردن پیش چشم مخاطب قرار می گیرد. اگر چه این این روزها به دلیل ابعاد مختلف دستگاه ها دیگر نمی توان تعریف دقیق و مشخصی از above the fold ارائه کرد و آن را با یک مرزبندی مشخص نسبت به باقی صفحه متمایز نمود، اما کماکان این مفهومی کاربردی است و حائز اهمیت می باشد. یکی از نکات اصلی در بهینه سازی صفحات آن است که قسمت above the field در سریع ترین زمان ممکن توسط مرورگر parse شده و به کاربر نمایش داده شود.

مشکل Render Blocking Scripts

مرورگر ها، صفحات HTML را به صورت خط به خط اجرا می کنند. به این معنی که پیش از parse، تحلیل و اجرای یک دستور، به سراغ اجرای دستور و یا تحلیلِ تگ بعدی نمی روند. به طور مثال اگر مرورگر به دستوری مانند دستور زیر برخورد کند:

 

<link rel="stylesheet" type="text/css" href="mystyle.css">
<script src="javascript.js"></script>

 

ابتدا فایل CSS را بارگزاری کرده و پس از اتمام بارگزاری به سراغ بارگزاری فایل js می رود. مشکل Render Blocking Scripts هم از همین مورد ناشی می شود. این که بارگذاری فایل های خارجی در قسمت head صفحه و یا هر جایی که مانع پردازش سریعِ صفحه ( و علی الخصوص قسمت above the fold ) توسط مرورگر شود، منجر به این خواهد شد که سرعت بارگذاری صفحات به شدت کاهش پیدا کند. 

 

 

 

 

برای رفع این مشکل در HTML 5 یک ویژگی به نام async اضافه شده است که می توان با افزودن به تگ های script، مرورگر می تواند بارگذاری فایل های js و parse صفحات را به طور موازی و کنار هم انجام دهد انجام داد:

 

<script async src="javascript.js"></script>

با این دستور دیگر مرورگر منتظر نخواهد ماند که فایل به طور کامل بارگذاری شود و به سراغ پردازش سطرهای بعدی خواهد رفت. برای اینکه از زمان پایانِ بارگذاری یک script که با روش async انجام شده است، با خبر شویم می توانیم متدی را برای رخداد onload مربوط به تگ script پیاده سازی کنیم:  

 

 

<script async onload="alert('loaded');" src="javascript.js"></script>

 

 

همچنین راهکار دیگری در HTML 5 برای حل این موضوع اندیشیده شده است. در HTML 5، می توان ویژگی ای به نام defer به تگ های script افزود. با این کار بارگذاری script، پس از پایان بارگذاری صفحه و در انتهای parse کامل HTML DOM صورت خواهد گرفت:

 

<script defer src="javascript.js"></script>

نکته دیگری که می تواند به افزایش سرعت بارگذاری صفحات کمک کند، آن خواهد بود که تا جای ممکن از بارگذاری فایل های js و css در قسمت head و یا در محدوده above the fold پرهیز کرده و تا جای ممکن این دستورات را در انتهای سند و پیش تگ <body/> قرار دهیم.

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

در ASP.NET MVC

در ASP.NET MVC اگر از Bundling استفاده می کنید، برای بارگذاری async و یا defer اسکریپت ها می توان از متد RenderFormat به صورت زیر استفاده کرد:

 

Scripts.RenderFormat(@"<script src=""{0}"" async></script>", "~/bundles/jquery")

 

حرکت همگانی وب به سمت الگوی MVC

به نظرم اتفاق جالبی در یکی دو سال اخیر در حوزه طراحی نرم افزارهای مبتنی بر وب افتاده است. این اتفاق بزرگ، چیزی نیست جز حرکت همگانی همه فریم ورک های مهم و معتبرِ طراحیِ وب به سمت الگوی MVC. این الگو اگر چه به روزهای قدیم و ایام smallTalk باز می گردد اما به خوبی توانسته با نیازمندی های نرم افزارهای مدرن و امروزی خود را تطبیق بدهد. شاید پیشتاز این جنبش را بتوان Ruby and Rails دانست که در سال 2005 با معماری و طراحی الهام بخش اش، الگوی مناسبی از MVC پیاده سازی کرد. این الگو در سال 2006 تحت زبان PHP در فریم ورک Zend تجلی پیدا کرد. سپس در سال 2008،  زبان Python میزبان فریم ورک Django  شد که بر مبنای الگوی MVC پیاده سازی شده بود. همچنین در این سال تیمی قدرتمند و خلاق در مایکروسافت پروژه ASP.NET MVC را برروی شانه هایASP.NET پیاده سازی می کنند. اگر چه ASP.NET MVC با الگو برداری از Rails شروع شد اما خود الهام بخش پروژه مهم دیگری به نام Play در پلتفرم جاوا شد. این پروژه حقیقتا طراحی وب در جاوا را به مرحله دیگری برد. Play در عین ساده سازی مفاهیم و کاربردها، آزادی عمل و قدرت زیادی به توسعه دهندگان می دهد و شاید در آینده ای نزدیک فریم ورک Play معادل معنی وب در پلتفرم جاوا باشد - همان اتفاقی که برای ASP.NET MVC افتاد - 

اما در ماه های اخیر شاید مهم ترین اتفاق این حوزه باز نویسی فریم ورک قدرتمند Drupal بر پایه فریم ورک Symfony باشد. Drupal 8 با اهدافی بسیار جاه طلبانه بازنویسی شده است و توانسته با استفاده از زیرساخت فریم ورک Symphony ( که بر مبنای الگوی MVC است ) و با پیاده سازی بر مبنای مفاهیم OOP، رنگ و رویی به شدت مدرن بگیرد. به نظرم این CMF اکنون به راحتی می تواند هر توسعه دهنده مشتاق و کنجکاوی را وسوسه کند. خواندن مطلبی که یکی از توسعه دهندگان دیروز مایکروسافت و توسعه دهنده امروز Drupal درباره مقایسه پلتفرم ها نوشته خالی از لطف نیست.

این یکپارچه سازی مفاهیم و چارچوب ها، برای ما توسعه دهندگان به این معنی است که می توانیم بر مبنای هر کدام از این تکنولوژی ها، نرم افزارهایمان را توسعه دهیم. البته به راحتی و بدون اینکه درگیر یادگیری و سروکله زدن با مفاهیمِ مختص به هر تکنولوژی شویم. درس دوم شاید این باشد که باید از تعصباتی که دنیای نرم افزار را صفر و یکی می بینند دست برداشته و بدانیم در پس هر کدام از این ها تیم های قدرتمندی مشغول فعالیت هستند و با هر کدام از آن ها کارهای بزرگی انجام شده است. اگر چه معتقدم پلتفرم NET. و زبان #C به شدت برای باقی تکنولوژی ها الهام بخش بوده اند(چه در Java8 و یا Swift و Hack و.... ) اما مسئله ما نباید بدی و خوبی این زبان ها و فریم ورک ها باشد. مسئله بایستی تحلیل نیاز و انتخاب راه حل مناسب باشد. پس بهتر است همه این آن ها را تا حدی بشناسیم و بتوانیم با آن ها حداقل کارهای روتین را انجام دهیم.

تعریف رابطه ها در Entity Framework با استفاده از Fluent API

زیبایی معماری و الگوی شاخصی که در طراحی Entity Framework به کار گرفته شده است، استفاده از الگوی طراحی Convention To Configuration می باشد. وجود این الگو در این فریم ورک موجب می گردد تا بسیاری از امورِ روتینِ طراحیِ پایگاه داده به سادگی هر چه تمام تر انجام بگیرد. Convention یعنی با پیروی از یک سری قواعد و قوانین از پیش تعریف شده در نام گذاری ها، می توانیم پایگاه داده مان را طراحی و تنظیم نماییم. به طور مثال تنها با پیروی از قوانین نام گذاری Entity Framework می توانیم کلید های اصلی، کلیدهای خارجی و رابطه های میان جدولی را برای EF مشخص نماییم که انصافا پیروی از همین قواعد برای بسیاری از کارها می تواند راه گشا باشد. در مرحله بعدی برای ایجاد و تعیین ویژگی ها و مشخصات دقیق تر، EF کاربرانش را تشویق به استفاده Attribute ها می کند که برای آن ها در Entity Framework نام Data Annotation را انتخاب کرده اند. ( باید گفت کلاس Data Annotation تنها متعلق به EF نیست و در تکنولوژی های دیگر .NET نیز از آن استفاده می شود.

هدف من تشریح و بسط این دو الگو در Entity Framework نیست، چرا که اینها به سادگی تمامی قابلیت شان را در اختیار کاربر قرار می دهند. مورد سوم و البته مهم تر در Config کردن Entity Framework استفاده مستقیم از API این فریم ورک می باشد. در موارد معدود و البته مهمی که نیازمندی ما در طراحی توسط دو مورد اول پوشش داده نمی شود بایستی از این API استفاده کنیم که به آن Fluent API گفته می شود. که این هم از یکی دیگر از الگوهای طراحی نرم افزار به نحو کامل و آموزند ای استفاده کرده است. پس الگوهای موجود در EF برای در اختیار قرار دادن قابلیت هایش به کاربر، به ترتیب زیر می باشد:

  1. Convention To Configuration

  2. Attribute Based Programming

  3. Fluent Interface: به این معنی که قابلیت ها و متد ها را می توانیم به طور زنجیروار (chaining) صدا کنیم که موجب آسانی در پیاده سازی، فهم و خوانش کد می گردد. همچنین عموما ترتیب صدا زدن متد ها در زنجیره مهم نیست و می توان به ترتیب دلخواه متدها را فراخوانی کرد. مثال معروف این الگوی طراحی در دنیای وب jQuery می باشد.

یکی از قابلیت های مهمی که Fluent API در اختیار ما می گذارد، تعریف رابطه ها و انواع مختلف آن هاست. با مثالی شروع می کنم و در ادامه توضیحات بیشتر و دقیق تری خواهم زد. فرض کنید که کلاس کامنت به تعریف زیر را داشته باشیم:

 

	public class Comment
    {
        public int Id { get; set; }

        [Required]
        public string Content { get; set; }

        public DateTime DateTime { get; set; }

        public int PostId { get; set; }

        public virtual Post Post { get; set; }

        public int? ParentCommentId { get; set; }

        public virtual Comment ParentComment { get; set; }

        public virtual ICollection<Comment> ReplyComments { get; set; }
    }

 

از تعریف کلاس مشخص است که می خواهیم رابطه ای Self Refrencial تعریف کنیم تا بتوانیم مشخص کنیم که: 

 

  1. هر کامنت، پاسخ به چه کامنت دیگری بوده است.

  2. فهرست پاسخ های داده شده به یک کامنت را داشته باشیم.

برای انجام این امر ملزم هستیم از Fluent API استفاده کنیم. به این معنی که باید در DataContext متد OnModelCreating را به نحو زیر override کنیم:

        protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Comment>()
                .HasOptional(c => c.ParentComment)
                .WithMany(c => c.ReplyComments)
                .HasForeignKey(c=>c.ParentCommentId);

            base.OnModelCreating(modelBuilder);
        }

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

 

  1. شی modeBuiler دروازه ورودی ما به fluent API می باشد.

  2. یکی از وظایف Fluent API طراحی و تعریف رابطه هاست که این از طریق متد Entity صورت می گیرد. این متد یک  EntityTypeConfiguration برمی گرداند که مسئول ساخت رابطه می باشد.

  3. هر رابطه از دو سمت تشکیل شده است. همانطور که می دانید هر سمت از یک رابطه، می تواند به صورت اختیاری (صفر یا یک)، اجباری (یک) و یا چندتایی (صفر یا چند) باشد.

  4. متد اولی که در زنجیره پس از متد Entity صدا زده می شود، می تواند یکی از حالت های HasMany، HasRequired، HasOptional باشد. که هرکدام مشخص می کند سمت اول رابطه چه نوع قیدی دارد (اختیاری، اجباری، چندتایی)

  5. متد دومی که در زنجیره پس از متد Entity صدا زده می شود، می تواند یکی از حالت های WithMany، WithRequired، WithOptional باشد. که مشخص می کنند در سمت دوم رابطه چه قیدی را خواهیم داشت.

  6. در اینجا یک رابطه ساخته شده است و باید حالا کلید های خارجی رابطه را مشخص کنیم. در برخی سناریو ها Entity Framework نیازی به تعریف کلیدهای خارجی رابطه ندارد و می تواند آن ها را بر اساس Conventions استخراج نماید. پس نیازی به صدا زدن متد سوم نیست.

  7. در صورتی که با قواعد نتوان کلید های خارجی را استخراج نمود از متد های HasForeignKey (برای رابطه هایی که یک سمت اش اختیاری و یا اجباری باشد) و یا Map استفاده خواهیم کرد.

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

نکات جالب توجه در طراحی این متد ها آن است که این متد ها lambda expression دریافت می کنند  - قابلیتی فانکشنال که بقیه زبان ها به سرعت از سی شارپ تقلید کردند -  و این امر موجب می شود تا بسیاری از خطاها پیش از کامپا��ل گرفته شود که در حین کار با این API متوجه مزایای این امر خواهید شد. در ضمن lambda expression باعث می شود که با توجه با قابلیت Type Inference کامپایلر سی شارپ، نتوان هر متدی را در زنجیره صدا زد که این امر هم از بسیاری از خطاهای متداول جلوگیری خواهد کرد.

برای دیدن مثال های بیشتر بهترین منبع سایت Entity Framework می باشد و البته مشاهده مثال های وبلاگی از MSDN خالی از لطف نیست.

تولید فید در ASP.NET

 پیش از شروع این مطلب، توصیه می کنم که مطلب "درباره فرمت فید ها" را مطالعه کنید. در پلتفرم .Net قابلیت توکاری برای تولید و خواندن فید ها پیش بینی شده است. در نتیجه در تمامی برنامه های وب وغیر وبی که تحت این پلتفرم تولید بشود، می توانیم از این قابلیت استفاده کنیم.همچنین نیازی به طراحی و کد نویسی چندانی نیست و اکثر امور و ریزه کاری ها توسط کلاس های تعبیه شده انجام می گیرد. کلاس های مرتبط به مطلب ما، در فضای نامی System.ServiceModel قرار گرفته اند و پیش از شروع کار بایستی این فضای نام را به reference های پروژه تان اضافه کنید. مطالبی که گفته می شود عموما در مورد فرمت استاندارد و جدیدتر ATOM می باشد، اما ساختار اصلی مطلب فرمت RSS هم پوشش می دهد.

زیبایی طراحی این کلاس ها آن است که مستقل از نوع فرمت –RSS یاATOM  - فید می باشند. شما در سطحی که با آبجکت ها کار می کنید نیازی به مشخص نمودن نوع فید خود ندارید و تنها در هنگام تهیه فایل xml مربوط به فید، به کلاس مربوطه خواهید گفت که فید شما را با چه نوع فرمتی تولید نماید. بسیاری از قابلیت هایی که در این مجموعه تعریف شده مربوط به فرمت ATOM می باشد و فرمت RSS به علت نقص ها و سادگی های ذاتی طراحی اش نیازی به خیلی از این قابلیت ها ندارد.

برای ساخت فید عمدتا با کلاس های SyndicationFeed ، SyndicationItem روبه رو خواهیم بود که خود این کلاس ها در برخی موارد از کلاس های SyndicationLink، SyndicationPerson و مشتقات SyndicationContent استفاده می کنند.

دربالاترین سطح کلاس SyndicationFeed را داریم که نماینده یک فید می باشد. در سطح فایل xml اگر بررسی کنیم:

·        در فرمت RSS محتویات این کلاس در تگ rss قرار می گیرد.

·        در فرمت ATOM محتویات این کلاس در تگ feed قرار می گیرد.

کلاس SyndicationFeed کنار ویژگی های معمولش، از فهرستی از  SyndicationItem ها تشکیل شده است. این آیتم ها در واقع نماینده هر یک از خبرها یا مطالبی است که میخواهیم خواننده هایمان را از انتشار آن ها آگاه کنیم. پس کار تولید فید به راحتی کار با همین دو کلاس می باشد و می توان همه مطالب مربوطه را در میان مستندات MSDN مطالعه کرد. در ادامه تنها مثال و برخی نکته ها را بیان خواهم کرد.

برای ساخت SyndicationFeed به طور نمونه می توانیم داشته باشیم:

 

            SyndicationFeed feed = new SyndicationFeed(
                 "Title",
                 "Description",
                 new Uri("absolute url of your blog"))
                 {
                     Authors = { new SyndicationPerson("mirsaeedi@outlook.com", "Ehsan Mirsaeedi", "www.mirsaeedi.net") },
                     Categories = { new SyndicationCategory("Software Development") },
                     Language = "fa-IR",
                     Id = "http://www.mirsaeedi.net/blog",
                     Links = { new SyndicationLink(new Uri("absolute url of feed"),"self",null,null,0) }

                 };

 

نکته: متاسفانه ساختار SyndicationFeed و کلاس های مربوطه به گونه ای نیستند که کاربر را مجبور کنند ازقوانین فرمت های ATOM و RSS تبعیت کند. در نتیجه خروجی این کلاس ها، گاهی منجر به تولید فیدهایی می باشد که صحیح نبوده و از قوانین تعریف شده تبعیت نمی کنند. به طور مثال می توانیم موارد زیر را ذکر کنیم:

  • در کانستراکتور یک آدرس پاس داده می شود که بیانگر آدرس سایت یا وبلاگ ما خواهد بود. اما در کنار این، در فرمت ATOM، سند xml نهایی بایستی حتما دارای یک لینک با rel=self باشد.این لینک به آدرسی اشاره می کند که فید را می توان از آنجا دریافت کرد. ولی در API مربوط به Syndication هیچ کجا کاربر ملزم به ساخت این لینک نشده است.

  • در فرمت ATOM، در فایل xml بایستی تگ authors را به عنوان فرزند تگ feed تعریف کرد. در صورتی که کاربر متاسفانه هیچ جا ملزم به این کار نشده است و این کار باید آگاهانه توسط کاربر انجام بگیرد.

  • در فرمت ATOM، در فایل xml حتما بایستی تگ id را به عنوان فرزند تگ feed تعریف کرد. در این فرمت مقدار تگ id بایستی آدرس URL و منحصر به فرد باشد. در صورتی که به خاطر پشتیانی از RSS، طراحان مجموعه کلاس های Syndication مجبور بوده اند که id را به صورت string تعریف نمایند و نه URI. همچنین متاسفانه کاربر ملزم به وارد نمودن این تگ نشده است. لازم است بدانید که مقدار id باید همیشه منحصر به فرد بماند و پس از تعریف تغییر نکند.

حالا نوبت به تعریف فهرستی از آیتم ها می باشد. پس از اینکه فهرست آخرین اخبار و یا مطالب وبلاگ را بارگزاری کردیم، می توانیم از آن ها برای ساخت SyndicationItem ها استفاده کنیم. به طور مثال خواهیم داشت:

            foreach (var item in feedItems)
            {
                string absoluteUrl="absolute url of your post";
                DateTimeOffset LastUpdatedTime=(item.UpdateDate.HasValue)?item.UpdateDate.Value:item.PublishDate;
                string content="<div xmlns=\"http://www.w3.org/1999/xhtml\"> <![CDATA[" 
                    + item.Content 
                    + "]]></div>";

                var xhtmlContent = new TextSyndicationContent(content, TextSyndicationContentKind.XHtml);

                syndicationItems.Add(
                         new SyndicationItem(item.Title,
                             xhtmlContent,
                             new Uri(absoluteUrl), 
                             absoluteUrl, 
                             LastUpdatedTime)
                         {
                             Authors = { new SyndicationPerson("mirsaeedi@outlook.com",
                                 "Ehsan Mirsaeedi", 
                                 "www.mirsaeedi.net") 
                                       },
                             PublishDate = item.PublishDate
                         }
                         );
            }

            feed.LastUpdatedTime = syndicationItems[0].PublishDate;
            feed.Items = syndicationItems;

            return new SyndicationResult(feed);



 

دانستن نکات زیر برای ساخت آیتم ها ضروری است:

  • در فرمت ATOM، هر آیتم حتما بایستی مقادیر id، Title و Updated را داشته باشد.

  •  در فرمت ATOM، هر Id باید به صورت یک Url  باشد. اگر چه الزامی نیست که این Url به آدرس مطلب اشاره کند. فید خوان ها با مقایسه Id ها می توانند پی به وجود اخبار و مطالب جدید ببرند و id های جدید را به عنوان آیتم جدید در نظر می گیرند. یعنی حتی اگر خبری قدیمی را به روز رسانی می کنید، کافیست با تغییر id آن خبر، فیدخوان ها را از وجود اصلاحیه مطلع کنید.

  • در فرمت ATOM، تگ Content بیانگر محتویمطلب ما می باشد. این تگ می تواند انواع متعددی داشته باشد که سه تای آن ها به نظرمن کاربردی ترند. یکی plain، یکی html و دیگری xhtml می باشد. برای اینکه مشخص نمایید از کدام یک از انواع زیر استفاده می کنید کافیست به عنوان پارامتر دوم برای TextSyndicationContent منظورتان را اعمال کنید.

  • یکی از ایرادات کلاس های Syndication در زمینه Content می باشد. به طور مثال در فرمت ATOM اگر نوع content  از قالب xhml  تبعیت کند، بایستی که محتوا را میان تگ  <div xmlns=http://www.w3.org/1999/xhtml></div> بگذاریم، که متاسفانه این عمل توسط کلاس ها صورت نمی گیرد و بایستی خودمان اقدام کنیم.

 

مرحله آخر تبدیل اطلاعات از سطح کلاس ها به فرمت فایل xml و مطابق با قواعد ATOM یا RSS می باشد. برای این منظور نیاز است تا کلاسی را از ActionResult ارث بری کنیم و در متد ExecuteResult مربوط به آن، فایل xml را تولید کرده و در response قرار دهیم و برای کاربر ارسال کنیم. این کار توسط تکه کد زیر می تواند انجام بگیرد:

public class SyndicationResult : ActionResult
    {
        public SyndicationResult(SyndicationFeed feed)
        {
            Feed = feed;
        }

        public SyndicationFeed Feed { get; set; }

        public override void ExecuteResult(ControllerContext context)
        {
            context.HttpContext.Response.ContentType = "application/atom+xml";
            using (XmlTextWriter writer = new XmlTextWriter(context.HttpContext.Response.Output))
            {
                writer.WriteStartDocument();
                writer.Formatting = Formatting.Indented;
                Feed.SaveAsAtom10(writer);
            }
        }
    }

تصدیق فیدهای تولید شده

 

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

درباره فرمت فید ها یا Syndication Feed Formats

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

 

فید ها دارای دو نوع RSS و ATOM می باشند. پیش از سال 1999 تلاش های مستقل و ضعیفی جهت ساخت فرمت های Syndication انجام گرفت که هیچ یک از آن ها نتواست اقبال چندانی کسب کند. در سال 1999 شرکت netscape پروتکل RSS را طراحی می کند و پس از فراز و فرود های این شرکت، این پروتکل از دست آن خارج شده و نسخه دوم آن با نام RSS 2.0 توسط فردی در دانشگاه هاروارد در سال 2002،  تهیه و تدوین می شود. این همان نسخه ای از RSS است که در حال حاضر در دنیای وب مورد استفاده قرار می گیرد. نکات جالب توجه در مورد این پروتکل آن است که :

 

عدم توسعه در آینده: در مستندات مربوط به RSS 2.0 ذکر شده است که این پروتکل دیگر هیچ گونه توسعه ای نخواهد داشت و این آخرین نسخه پروتکل می باشد. 

 

  •  

     عدم پذیرفته شدن توسط ietf: در نتیجه این امر هیچ گونه سند رسمی RFC برای توصیف پروتکل تهیه نشد. اسنادی هم که هست در وضعیت پیش نویس می باشد.

     

  •  

    عدم تعریف MIME-TYPE استاندارد: اگر چه MIME-TYPE فایل های RSS دارای مقدار application/rss+xml می باشد، اما همانطور که در سند مربوطه ملاحظه می شود، این صرفا یک قرارداد غیر رسمی است و استاندارد قطعی و پذیرفته شده صنعت نمی باشد.

     

  •  

    تگ هایی که برای توصیف اسناد RSS تعریف شده است، کامل و کافی نمی باشند.

     

  •  

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

     

  •  

     پروتکل RSS، هیج اجباری برای مقدار دهی تگ ها و ویژگی های آیتم ها اعمال نکرده است.

     

  •  

    مطابق با اسناد تعریف RSS، در این فایل ها امکان استفاده از relative url ها وجود ندارد.

 

با توجه به نواقصی که در طراحی پروتکل وجود داشت و متوقف شدن پروژه RSS از طرف دانشگاه هاروارد، در سال 2005 با کوشش جمعی از افراد و کمپانی های معتبر حاضر در صنعت (و نه دیگر محیط آکادمیک!) پروتکلی به نام ATOM تهیه و تدوین شد. نسخه ای از این پروتکل که در حال حاضر استفاده می شود، نسخه ATOM 1.0 می باشد. این پروتکل به تایید ietf رسیده است و دارای سند RFC نهایی می باشد. نکاتی که در مورد این پروتکل می توان بیان کرد:

  •  

    برای توصیف آیتم های یک فید، تگ ها  و ویژگی های بیشتری تعریف کرده است. در نتیجه سند مربوطه ساخت یافته تر است. 

     

  •  

    دارای MIME-TYPE استاندارد و پذیرفته شده از سمت IANA می باشد. مقدار MIME-TYPE این نوع اسناد برابر است با application/atom+xml

     

  • درپروتکل ATOM، مقدار دهی title، id و published ضروری می باشد.

  •  

    از آنجا ATOM بر خلاف RSS یکی از پروتکل های xml namespace  می باشد، می توان به استفاده از ویژگی xml:base امکان تعریف relative url ها را فراهم نمود.

     

  •  

    آیتم های پروتکل اتم محدود به plaintext  نیست و می تواند انواع دیگری مانند Well Formed XHTML و حتی فرمت باینری تحت پروتکل base64 را پشتیبانی کند. حتی می توان به جای متن، به مطلبی در وب سایت دیگر اشاره کرد. انواع مختلف content و ریزه کاری های هر یک را در سند rfc این فرمت می توان مشاهده کرد.

     

 

همانطور که مشاهده شد، اگر چه RSS واژه ای پرکاربرد شده و تقریبا برابر با Syndication Feed در نظر گرفته می شود، اما پروتکل پیشرفته و قابل اطمینانی نمی باشد. این پروتکل صرفا در زمانی مناسب و پیش از ATOM پا به میدان گذاشت و به شدت محبوب شد. اما فرمت توصیه شده صنعت برای ایجاد فید های خبری همان ATOM می باشد.

 

شناسایی مطالب جدید توسط Feed Reader ها

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

نکته: پس به هیچ عنوان فراموش نشود که برای آیتم ها حتما شناسه ای منحصر به فرد در نظر گرفته شود. اگر چه RSS این فیلد را اجباری نکرده است.

 

شناسایی خودکار Feed ها توسط Feed Reader ها

نرم افزارهای فید خوان این قابلیت را دارند که به طور مثالبا مشاهده وبلاگ من (http:www.mirsaeedi.net/blog)، آدرس فایل ATOM این وبلاگ  (http:www.mirsaeedi.net/blog/feed) را استخراج کرده و به کاربر و بازدید کننده وجود فید را اعلامکنند. به این عملیات Auto Discovery گفته می شود.

برای فید های ATOM باید سطر زیر را به صفحه اضافه کنیم:

<link href="atom.xml" type="application/atom+xml" rel="alternate" title="ATOM">



 

 

 

 

 

برای فید های RSS باید سطر زیر را به صفحه اضافه کنیم:

 

 

<link rel="alternate" type="application/rss+xml" title="RSS" href="RSS">



 

 

 

 

در این مطلب سعی کردم مطالبی را بیان کنم که مستقل ازپلتفرم های توسعه وب باشد. در مطلب بعدی روش توسعه یک فید ATOM را در ASP.NET MVC شرح خواهم داد.

رویکرد جدید مایکروسافت

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

شرکت مایکروسافت در حال بیرون آمدن از دیوارهای محصوری است که دور خود کشیده بود. جهان فناوری امروز، جهانی یک صدا نیست. دورانی که مایکروسافت در همه زمینه های فناوری یکه تاز بود به سر آمده است. صدای این انقلاب پر سرعت فناوری را، اگر چه بسیار دیر ، اما بزرگان و رهبران مایکروسافت اکنون به وضوح شنیده اند. این تغییر مسیر، به خصوص پس از بر سرکار آمدن Satya Nadella سرعتی دو چندان گرفته است. در کنفرانس Build 2014، سخنی که بسیار از زبان ارائه دهندگان شنیده شد، عبارت Cloud First-Mobile First World بود. عبارتی که دیدگاه جدید مایکروسافت را در سیاست گذاری هایش منعکس می کند و بیان می کند که این شرکت در چه مسیری گام بر خواهد داشت و چه آینده ای نوینی را در جهان بنا خواهد کرد. در مقالاتی که هم در مجموعه وبلاگ های MSDN دیده می شود، این عبارت به کرات دیده می شود.  این جهت گیری نوین مایکروسافت، تلنگری هم برای توسعه دهندگان پلتفرم های مایکروسافتی است که باید به سرعت تکانی به خود بدهند و دانش خود را به روز نمایند.

با توجه به مطالبی که در وبلاگ Scott Hanselman خوانده ام، گمان می کنم که تیم های ASP.NET و تیم Microsoft Azure نقش به سزایی در این تغییر نگرش داشته اند. این تیم های به روز و پرقدرت شرکت مایکروسافت، به دلیل ماهیت کارشان، از آنجا که بسیار بیشتر با دنیای پویای بیرون از مایکروسافت در تماس بوده اند، ایده ها و حرکت های الهام بخش دنیای Open Source را از نزدیک لمس کرده اند و در پیاده سازی های شان بسیار از آن ها ایده گرفته اند.

شاید کمتر در خاطر کسی مانده باشد، اما قریب به یک سال و نیم پیش، وقتی مایکروسافت پشتیبانی از git را به طور رسمی آغاز کرد و در Visual Studio و Team Foundation به صورت توکار، از git استفاده کرد، بسیاری از تحلیل گران این حرکت را تعجب بر انگیز دانستند و از اینکه مایکروسافت از یکی از سمبل های شاخص دنیای Open Source پشتیبانی می کند، حیرت زده شدند. در ASP.NET MVC می بینیم که با همت Scott Hanselman و تیم ASP.NET از بسیاری از ویژگی های مهم Ruby and Rails و node.js و باقی ایده های شاخص توسعه وب الهام گرفته شده و این ها هراسی از این موضوع نداشته اند. به اصرار این ها بسیاری از پروژه های جدی و جدید مایکروسافت متن باز شده و نگاه جدیدی در بدنه این سازمان عریض و طویل در حال شکل گیری می باشد. همچنین در سطحی بالاتر و جدای از لای توسعه، می بینیم که مایکروسافت با پذیرش دنیای گوناگون سیستم عامل ها (اعم از موبایل و دسکتاپ و ....)، به جای نادیده گرفتن ابزارهای غیرمایکروسافتی، سعی می کند تا در تمامی آن ها ریشه بدواند و کاربران آن ها را محتاج به استفاده از سرویس های خود کند. سرویس هایش را برای iOs، Andoroid و Linux و Mac ارائه می کند و به جای نفی آن ها، سعی کرده است با احترام به دنیای مدرن و نیاز کاربران، سرویس های خود را بیش از پیش فراگیر نماید. تمرکز و دورخیز ویژه ای بر فناوری Internet Of Things کرده است و می خواهد این بار از رقیبان قدرتمندش جا نماند. حرکت مایکروسافت تا آن حد رادیکال شد که در کنفرانس Build 2014 اعلام کرد که ویندوز بر روی تمامی دستگاه های زیر 9 اینچ رایگان خواهد بود. تا بلکه با کاهش هزینه های فناوری های مبتی بر ویندوز، بتواند در دنیای تبلت ها، گوشی ها و Internet of Things خود را بیش از پیش شاخص نماید. این البته خبر خوشی برای ما توسعه دهندگان بستر .NET است که به سمتی پیش می رویم که می توانیم با این تکنولوژی برای تمامی سیستم عامل ها و کاربران، نرم افزارهای مان را توسعه دهیم. همچنین این جهت گیری موجب می شود که دیگران از کیفیتِ شاخص و ممتازی که توسط مایکروسافت - چه در لایه توسعه و چه لایه ابزارها و سرویس ها - ارائه می شود بهره، بگیرند.

در کنفرانس Build 2014 و TechEd 2014 خبرهای بسیار خوشی از این کمپانی به گوش رسید. مایکروسافت به طور روشن و مشخصی جهت گیری بسیار زیرکانه ای را دنبال می کند و شخصا بسیار نسبت به این رویکرد و آینده این شرکت امیدوار و خرسندم. خبرهای کنفراس های مذکور عموما حول توسعه نرم افزار می باشد که آن ها را در مقاله ای دیگر توضیح خواهم داد.

نحوه گزارش باگ ها

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

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

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

در ضمن معتقدم که مهم نیست که برای مدیریت چرخه تولید نرم افزار از چه ابزاری استفاده می نماییم. نباید اولین دغدغه تیم مان، انتخاب Jira، Team Foundation و یا RedMine و غیره باشد. از همه این ابزارها در کارهای بزرگی استفاده شده است و همه این ها آزمون خود را گذرانده اند. حتی گامی جلوتر می روم و عقیده دارم استفاده از این ابزارها می تواند الزامی نباشد. مهم این است که فرایند داخل شرکت و تیم برای چرخه تولید مشخص و تبیین شود. یک فرایند استاندارد و دارای چارچوب که تیم خودش را به آن متعهد بداند. به طور مثال بسیاری از تیم های حرفه ای و قدرتمند بهترین و سریع ترین راه را، استفاده از تخته وایت بورد و استکی نوت ها و در نهاین Trello می دانند. پس مهم ابزار نیست، مهم وجود یک فرایند دقیق و مشخص است که تیم به آن پایبند باشد. تیمی که عادت کند چرخه تولید و توسعه نرم افزارش را سرسری گرفته و به طریقه هیئتی کار ها را به پیش ببرد، هیچگاه بیش از حد معین (و البته کمی) پیشرفت نمی کند و خود را برای شرکت در پروژه های بزرگ و سنگین آماده نخواهد کرد.

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

  • گزارش دهنده : در این فیلد نام شخصی که خطا را گزارش می کند، نوشته می شود. در صورت لزوم بایستی ایمیل و شماره تماس فرد هم در گزارش آورده شود. بدین صورت تیم توسعه و کسی که خطا را گزارش کرده، در صورت لزوم می توانند با هم ارتباط داشته باشند.
  • محصول : در این فیلد بیان می شود که این گزارش خطا برای کدام محصول می باشد.
  • نسخه : در کدام نسخه از نرم افزار خطا مشاهده شده است.
  • تاریخ : در چه تاریخی خطا مشاهده شده است.
  • سیستم عامل : در چه سیستم عاملی برنامه اجرا شده است.
  • نوع و نسخه مرورگر  ( برای نرم افراز تحت وب) : در کدام مرورگر نرم افزار اجرا شده است.
  • اولویت : این فیلد توسط مدیر گروه تست و یا مدیر گروه توسعه مقدار دهی می شود. در این جا مشخص می کنیم که رفع خطا در چه درجه ای از اولویت قرار دارد. این فیلد عموما 5 مقدار می گیرد. مقدار 1 به معنی رفع خطا در کمترین زمان ممکن و مقدار 5 یعنی در صورتی که از لحاظ زمانی معذوریتی نداشتیم، خطا برطرف گردد.
  • شدت : میزان تاثیرِ وقوع خطا در نرم افزار بیان می شود. این فیلد می تواند دارای مقدار های زیر باشد :
    • Blocker  : به معنی اینکه بروز خطا مانع ادامه فرایند تست می گردد.
    • Critical : نرم افزار داده ها را از بین می برد و یا اینکه برنامه بسته می شود.
    • Major : پیاده سازی تابع و یا Usecase بسیار مشکل دار می باشد.
    • Minor : پیاده سازی تابع و یا Usecase دارای مشکل کوچکی است.
    • Trivial  : بهبود ظاهر برنامه
    • Enhancement : درخواست اضافه نمودن قابلیت و یا بهبودی در عملکرد یکی از قابلیت های کنونی سیستم
  • وضیعت خطا : بیان می کند که خطای گزارش شده در چه مرحله ای از حیاتِ خود (bug lifecycle) قرار دارد. به طور مثال مقدارهای ممکن برای این فیلد می تواند "اصلاح شد"، "نامعتبر"، "نیاز به جزییات بیشتر" و یا "محول شده" باشد. 
  • مسئول رفع خطا : این فیلد توسط مدیر تیم توسعه مقدار دهی می شود. این فیلد شخصی را به عنوان مسئول رفع خطا معرفی می کند.
  • خلاصه خطا : سعی شود به طور خیلی خلاصه اما واضح و دقیق و حداکثر در 60 کلمه، در مورد خطا توضیحی داده شود.
  • توضیحات : در این قسمت به طور دقیق و با جزییات کامل خطا توضیح داده می شود. این فیلد از قسمت های زیر تشکیل شده است :
    • گام های باز تولید : در این قسمت گام هایی که برای وقوع خطا بایستی طی شوند، به ترتیب توضیح داده می شوند. کسی که گزارش خطا را می نویسد، بایستی حداقل سه بار این گام ها را طی کرده باشد و مطمئن باشد که برنامه نویس با طی کردن این گام ها، می تواند خطا را بازتولید نماید.
    • نتیجه : بیان می شود که پس از پیمودن گام های بالا، چه نتیجه ای حادث شده است. همچنین در صورت لزوم عکسی از لحظه رخداد خطا گرفته می شود و به این بخش اضافه می گردد.

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