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

اپل، استیو جابز و کسب و کار نرم‌افزار

اپل و استیو جابز و همکارانش درس‌های زیادی برای کسب و کارها دارند. در سری نوشته‌های «درس‌هایی از اپل برای کسب و کار نرم‌افزار» کتاب زندگینامه استیو جابز را با هم مرور می‌کنیم و درباره نکاتی که به کسب و کار نرم‌افزار مربوط است بیشتر صحبت می‌کنیم.

حکایت ۱۰۰ نفر اول اپل

اپل شرکت بزرگی است. نیروی کار شرکت‌های بزرگ مدام در حال کم و زیاد شدن هستند. در ابتدای فصل سی کتاب زندگینامه جابز درباره ۱۰۰ نفر اول اینطور می‌خوانیم:

«... جابز سالی یک بار، ارزشمندترین کارمندان اپل را به تفرجی می‌برد که "۱۰۰ نفر اول" نام داشت. انتخاب بر اساس یک راهبرد ساده انجام می‌شد: اگر مجبور بودی فقط ۱۰۰ نفر را با خودت سوار قایق نجات کنی و به شرکت بعدی ببری، چه کسانی را انتخاب می‌کردی؟
او در پایان هر تفرج، جلوی یک وایت‌بورد می‌ایستاد و می‌پرسید: ۱۰ پروژه بعدی که باید انجام دهیم چیست؟ افراد برای این که پیشنهادشان در فهرست قرار بگیرد می‌جنگیدند. جابز پیشنهادات را می‌نوشت و بعد آن‌هایی را که معتقد بود گنگ هستند ضربدر می زد. بعد از کلی شوخی، گروه به فهرستی ۱۰ تایی می‌رسید. اینجا بود که او زیر ۷ تا از آن‌ها را خط می‌کشید و می‌گفت: فقط از عهده انجام ۳ کار برمی‌آییم»

دریافت فیدبک از کارمندان

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

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

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


اهمیت فیدبک کارمندان

نگاه سنتی به کارمندان (صرفنظر از صنعتی که در آن کار می‌کنند) این است که یک کارمند در ازای صرف وقت یا ارائه مهارت‌های خود، دستمزد می‌گیرد. در همین نگاه سنتی، واحدی که امور کارکنان را پیگیری می‌کند کارگزینی یا منابع انسانی نامیده می‌شود. اما در نگاه جدیدتر، کارکنان صرفاً اجرا کننده کار نیستند، بلکه جزئی ارزشمند از خود کسب و کار محسوب می‌شوند و لذا حتی کارگزینی به واحد سرمایه‌های انسانی تغییر می‌کند یا منابع انسانی (Human Resources) به People Operation تغییر نام می‌دهد.

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

تولید‌کنندگان نرم‌افزاری یکی از بهترین گزینه‌ها برای استفاده از نظرات نیروهای متخصص خود هستند. نظر شما چیست؟

به اشتراک گذاری این نوشته در شبکه‌های اجتماعی

۳۰ روز با TDD: روز یازدهم - درباره Mocking

 

داستان ۳۰ روز با TDD

سپتامبر سال گذشته آقای James Bender در وبلاگ‌های تلریک یک مجموعه نوشته منتشر کرد به نام ۳۰ روز با TDD. در ترجمه‌ای آزاد در وبلاگ آرایه، با هم در طول یک ماه با Test Driven Development آشنا می‌شویم. لینک سایر نوشته‌های این سری را در صفحه ۳۰ روز با TDD می‌توانید مشاهده کنید.

و اما یازدهمین روز: درباره Mocking

نوشته به زبان انگلیسی روز دهم را در این آدرس می‌توانید مطالعه کنید. هدف آزمون‌های واحد خوب نوشته شده این است که تست‌های شما را ایزوله نگه دارد. این جمله به آن معنی است که اگر حتی کد زیر تست شما، به کلاس یا سرویس خارجی دیگری وابستگی دارد، شما باید بتوانید تستی بنویسید که صرفنظر از آن وابستگی‌ها آنچه در کد کلاس یا متد شماست را تست کند. به نظر غیرممکن می‌‌‌آید؟ در واقع این طور نیست و اگر نوشته مربوط به Dependency Injection را مطالعه کرده باشید، نیمی از جواب را می‌دانید. نیم دیگر جواب mocking است.

Mocking چیست؟

اغلب نرم‌افزارهایی که شما توسعه می‌دهید، از کلاس‌ها و اجزا (component) مختلفی تشکیل می‌شوند. در حالت ایده‌آل، هر کلاس یا جزء برای اجرای وظایف خاصی طراحی می‌شوند که این همان Single Responsibility Principle است. این کلاس‌ها و اجزا در کنار هم یک برنامه (Application) را تشکیل می‌دهند. طبیعت خاص کلاس‌های و اجزای واحد، وابستگی را غیرقابل اجتناب می‌کند. رابط کاربر (User Interface) شما به کلاس‌های business domain وابسته است و خود کلاس‌های business domain به چیزهایی مثل انبارهای خارجی داده (دیتابیس، فایل سیستم)، وب سرویس یا منابع و سیستم‌های خارجی دیگر وابسته هستند.

وقتی ما آزمون واحد می‌نویسیم، باید به یاد داشته باشیم که این آزمون‌ باید بر روی کد خاصی که می‌خواهیم تست کنیم متمرکز باشد. کد زیر را در نظر بگیرید:


using System;
using System.Linq;
namespace ThirtyDaysOfTDD.UnitTests
{
    class OrderService
    {
        private ICustomerService _customerService;
        private ILoggingService _loggingService;
        private IOrderDataService _orderDataService;
        public OrderService(IOrderDataService orderDataService, ICustomerService customerService, ILoggingService loggingService)
        {
            _orderDataService = orderDataService;
            _customerService = customerService;
            _loggingService = loggingService;
        }
        public Guid PlaceOrder(Guid customerId, IShoppingCart shoppingCart)
        {
            var order = new Order();
            
            // Business logic that validates order and creates Order object
            var orderId = Save(order);

            _customerService.AddOrderToCustomer(customerId, orderId);
            _loggingService.LogNewOrder(orderId);
            return orderId;
        }  
        private Guid Save(Order order)
        {
            return _orderDataService.Save(order);
        }
    }
    public interface IOrderDataService
    {
        Guid Save(Order order);
    }
    public interface ICustomerService
    {
        bool AddOrderToCustomer(Guid customerId, Guid orderId);
    }

    public interface ILoggingService
    {
        bool LogNewOrder(Guid orderId);
    }

    public interface IShoppingCart
    {
    }

    public class Order
    {
    }
}

کد بالا یک کد معمول در برنامه‌های LOB یا Line of Business محسوب می‌شود. احتمالاً ده‌ها و شاید صدها بار کدهایی مثل این نوشته‌اید. در مورد این مثال، متد مربوط به قرار دادن یک سفارش در یک برنامه تجارت‌الکترونیکی است. یک متد به نام PlaceOrder داریم که یک سفارش برای یک مشتری از پیش تعریف شده ایجاد می‌کند. مانند بسیاری از برنامه‌‌های مشابه من باید بعضی داده‌ها را ذخیره کنم که در اغلب موارد به معنی ذخیره در دیتابیس است. کلاس من متدی به نام Save دارد که یک فراخوانی از شی که IOrderDataService را پیاده‌سازی کرده را صدا می‌زند. این اینترفیس، یک abstraction (تجرد) از دیتابیس من است. من همچنین باید با Customer Service کار کنم تا سفارشات و مشتریان به هم مرتبط شوند. در این مثال همچنین نیازمند لاگ کردن همه سفارشات هستیم، پس فراخوانی logging service را هم نیاز داریم.

این یک متد، که وقتی با TDD پیاده‌سازی شود نیازمند چندین تست خواهد بود، به سه نوع منبع خارجی مختلف وابسته است. اما به عنوان یک برنامه‌نویس که آزمون واحد می‌نویسد، نمی‌خواهم کد موجود در منابع خارجی را اجرا کنم، بلکه فقط می‌خواهم کد موجود در کلاس و متدهای زیر تست را اجرا کنم. این یعنی کدهای متد عمومی PlaceOrder و متد خصوصی Save که توسط PlaceOrder صدا زده می‌شود و کلاس OrderService.

دلایل زیادی وجود دارد که از کلاس‌ها و اجزا زمان اجرا (run time) مربوط به وابستگی‌ها استفاده نکنم. همانطور که اشاره شد، می‌خواهم تست من روی کد خاصی شامل کلاس‌ها و متدهای زیر تست متمرکز شود. در این شرایط اگر زمانی تست من fail شود، بخش بسیار کوچکتری از کد که مشکل در آن وجود دارد را خواهم داشت. سه یا چهار لایه معماری برای جستجو به دنبال مشکل را ندارم، فقط چند متد و چند ده خط کد. این باعث می‌شود که پیدا کردن مشکل سریع‌تر و راحت‌تر شود.

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

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

همانطور که در ابتدای این نوشته اشاره کردم، Dependency Injection گام نخست برای راه حل این مشکل است. همانطور که در کد مثال بالا می‌توانید مشاهده کنید من یک سازنده (constructor) برای این کلاس دارم که که وابستگی‌ها را به عنوان پارامتر دریافت می‌کند. همچنین می‌توانید ببینید که این وابستگی‌ها بر اساس interface ایجاد شده‌اند. همانطور که از مطالب قبلی این سری نوشته‌ها به یاد دارید، این بدان معنی است که من فقط محدود به پاس دادن اشیا معمول در زمان اجرا نیستم، بلکه می‌توانیم هر چیزی که آن interface ها را پیاده‌سازی کند پاس بدهم. این نکته mocking است: من می‌توانم اشیا mock شده یا fake را پاس بدهم که به عنوان اشیا معمولی که OrderService از آن‌ها استفاده می‌کند قرار بگیرند. این mock ها می‌توانند پاسخ‌های مشخص برگردانند، تعداد دفعاتی که فراخوانی شده‌اند را بشمارند یا حتی بعضی اعتبارسنجی‌ها را انجام بدهند، همه کار به جز کار واقعی که object های اصلی انجام می‌دهند. این یعنی mock ها هیچ الگوریتم تجاری را پیاده‌سازی نمی‌کنند یا با منابع خارجی در تعامل نیستند. ما می‌توانیم هر چقدر بخواهیم تست‌هایمان را اجرا کنیم بدون اینکه نگران تغییر وضعیت دیتابیس باشیم.

Mocks و Stubs و Fakes

عبارت Mock به یک اصطلاح عمومی برای انواع مختلف mock هایی که در unit test ها به کار می‌بریم تبدیل شده است. چه زمانی mock یک mock نیست؟ چه زمانی stub یا fake است؟ تفاوت این‌ها چیست؟ تفسیر Martin Fowler:

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

Stubs: یک Stub شی‌ای است که یک نتیجه مشخص را بر اساس یک سری ورودی مشخص برمی‌گرداند. اگر من به stub بگویم که هر وقت شخصی با شناسه 42 را خواستم عبارت John Doe را برگردان، stub همین کار را خواهد کرد. با این حال اگر من از stub بخواهم که شخصی با شناسه 41 را برگرداند، نمی‌داند چه کار باید بکند. بر حسب اینکه از کدام mocking framework استفاده کنم، stub یا exception ایجاد می‌کند یا یک شی null برمی‌گرداند. stub می‌تواند بعضی اطلاعات مربوط به نحوه فراخوانی مثل تعداد فراخوانی یا اینکه با چه داده‌هایی فراخوانی شده است را به یاد داشته باشد.

Mocks: یک Mock یک نسخه پیچیده‌تر از stub است. همچنان مانند stub مقادیر را برمی‌گرداند، اما همچنین می‌تواند طوری برنامه‌ریزی شود که باید چند بار فراخوانی شود، به چه ترتیب یا به چه داده‌هایی.

Spy: یک Spy نوعی mock است که یک شی را می‌گیرد و به جای ایجاد یک شی mock متدهایی که tester می‌خواهد mock کند را جایگزین می‌کند. Spy ها برای کدهای غیر TDD عالی هستند، اما باید خیلی مراقب باشید چرا که فراموش کردن چیزی که می‌بایست mock شود ممکن است نتایج فاجعه‌باری داشته باشد.

Dummy: یک Dummy شی‌ای است که می‌تواند به عنوان جایگزین یک شی دیگر پاس داده شود اما استفاده نمی‌شود. Dummy ها در واقع placeholder محسوب می‌شوند.

Mocking Frameworks

بر اساس تعاریف بالا، بعضی انواع mock ها هستند که خودمان می‌توانیم آن‌ها را ایجاد کنیم مثل Fake ها و Dummy ها. همچنین می‌توان یک stub ساده نوشت، اما زمان انجام این کار بر روی بهره‌وری من تاثیر خواهد داشت. خوشبختانه راه بهتری وجود دارد: استفاده از فریمورک‌های mocking. تعداد زیادی Mocking Framework برای TDD روی دات نت موجود است. برای این سری از نوشته‌ها من از JustMock و JustMock Lite استفاده می‌کنم.

فریمورک‌های mock جز ابزارهای ضروری TDD هستند. این فریمورک‌ها معمولاً یک اینترفیس ساده دارند برای ایجاد stub های ساده که بر اساس ورودی، مقدار خاص یا exception برمی‌گردانند.

ادامه دارد...

به اشتراک گذاری این نوشته در شبکه‌های اجتماعی

رفع خطاهای معمول و تکمیل راه‌اندازی Build Server برای TFS 2013

Build به کمک  TFS

اگر سری نوشته‌های تست جوئل را دنبال کرده باشید، حتماً درباره اهمیت build روزانه خوانده‌اید. برای داشتن یک روال build خوب ابتدا باید یک build serer داشته باشید. خوشبختانه TFS به خصوص در نسخه‌های جدید، کار build را برای پروژه‌های تیمی بسیار ساده کرده است. در این نوشته درباره خطاهایی که پس از نصب سرویس build در TFS ممکن است با آن‌ها برخورد داشته باشید و راه حل آن‌ها صحبت می‌کنیم.

در توسعه نرم‌افزار آرایه، ما به صورت گسترده از TFS 2013 استفاده می‌‌کنیم. از میان ویژگی‌های اصلی TFS در حوزه Source Control پیشتر از نرم‌افزار داخلی TFS و به تازگی از Git بر روی TFS استفاده می‌کنیم. در حوزه برنامه‌ریزی کارها، از نسخه سفارشی شده‌‌ای از فرم‌های TFS برای ایجاد و رهگیری وظایف برنامه‌نویسی استفاده می‌کنیم که به زودی از آن خواهیم نوشت. در حوزه build نیز از امکان سرویس build موجود در TFS بهره می‌گیریم. به کمک این سرویس انجام آزمون‌های واحد را نیز در هر build کنترل می‌کنیم. در شش ماه دوم سال ۹۳ همچنین برنامه گسترده‌ای برای استفاده از قابلیت‌های Test (به جز اجرای اتوماتیک آزمون‌ها در هنگام build) و Microsoft Test Manager داریم.

در این نوشته درباره خطاها و هشدارهایی که پس از نصب سرویس build به آن‌ها برخورد کردیم و روش حل آن‌ها می‌نویسیم. لازم به ذکر است پیش‌فرض این نوشته این است که شما TFS و Build Controller و Build Agent مورد نظر را نصب و تنظیم کرده‌اید. build server ما بر روی ویندوز سرور ۲۰۱۲ ایجاد شده است و بر مبنای TFS 2013 می‌باشد.

رفع خطای WebApplication.Targets

پس از نصب و تنظیم build service نخستین خطایی که به خصوص هنگام build کردن پروژه‌های تحت وب ممکن است به آن برخورد داشته باشید، خطای WebApplication.Targets به شرح زیر است:

error MSB4019: The imported project “C:\Program Files (x86)\MSBuild\Microsoft\VisualStudio\v12.0\WebApplications\Microsoft.WebApplication.targets” was not found. Confirm that the path in the declaration is correct, and that the file exists on disk.

برای رفع این خطا، از روی سیستم برنامه‌نویسی که در آن Visual Studio 2013 نصب شده است پوشه موجود در مسیر زیر را به مسیر مشابه در مسیر build server کپی کنید.

C:\Program Files(x86)\MSBuild\Microsoft\VisualStudio\v12.0
پیشنهاد آرایه: همان‌طور که در ادامه این نوشته می‌آید، پیشنهاد می‌کنیم بر روی build server خود Visual Studio 2013 را نصب کنید.

رفع هشدار نصب دات نت فریمورک ۴.۵

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

warning MSB3644: The reference assemblies for framework “.NETFramework,Version=v4.5″ were not found.

برای رفع این هشدار همانطور که مشخص است باید دات نت فریمورک ۴.۵ را نصب کنید. البته در حقیقت باید  .NET Framework 4.5.1 SDK را نصب نمایید. برای نصب آن به صفحه دانلود Windows Software Development Kit (SDK) for Windows 8 بروید و پس از دانلود فایل و اجرای آن SDK اشاره شده را نصب نمایید. البته این SDK برای ویندوز ۸.۱ را هم می‌توانید از این صفحه دانلود کنید. SDK نصب شده برای ویندوز سرور ۲۰۱۲ نیز معتبر است.

رفع خطای Visual Studio Test Runner

اگر build خود را برای اجرای تست‌ها تنظیم کرده باشید، ممکن است به خطای زیر برخورد کنید.

TF900547: The directory containing the assemblies for the Visual Studio Test Runner is not valid ''

برای رفع این خطا دو راه حل وجود دارد. راه ساده‌تر نصب Visual Studio 2013 بر روی سرور build است. این کار مشکل خطای اول اشاره شده در این نوشته را نیز برطرف می‌کند. راه دیگر تغییر template مربوط به گردش کار build برای استفاده از نسخه قدیمی‌تر مربوط به VS 2012 است.

رفع هشدار عدم شناسایی آزمون‌های NUnit

اگر مثل ما از NUnit برای مبحث آزمون‌ها استفاده می‌کنید، ممکن است علیرغم build موفق با هشدار زیر مواجه شوید.

No test found. Make sure that installed test discoverers & executors, platform & framework version settings are appropriate and try again.

برای اینکه پروژه‌های حاوی آزمون‌ها شناسایی شوند، NUnit Test Adapter for VS2012 and VS2013 را از طریق nuget به پروژه حاوی آزمون‌های نرم‌افزاری اضافه کنید.

رفع خطای Timeout برای drop folder

به دلایل مختلف ممکن است با خطای timeout زیر مواجه شوید. 

Exception Message: The HTTP request timed out after 00:01:40. (type TimeoutException) Exception Stack Trace:    at Microsoft.TeamFoundation.Build.Workflow.Activities.FileContainerDropProvider.EndCopyDirectory(IAsyncResult result)

یک راه خوب برای برطرف کردن آن، تغییر اندازه timeout است. برای این کار به مسیر زیر بروید و فایل tfsbuildservicehost.exe.config را پیدا کنید.

C:\Program Files\Microsoft Team Foundation Server 12.0\Tools

در این فایل کدهای زیر را برای تغییر مقدار زمان timeout اضافه کنید. به عنوان مثال کد زیر زمان ۵ دقیقه را برای این timeout تنظیم می‌کند که زمان مناسبی محسوب می‌شود.




با اجرای دستورالعمل‌های فوق در آرایه موفق شدیم build روزانه و انواع build های مورد نیاز برای پروژه‌ها را با استفاده از TFS ایجاد کنیم. به زودی درباره استفاده از TFS در حوزه برنامه‌‌ریزی کارها و سفارشی‌کردن آن بر اساس نیاز تیم خواهیم نوشت.

به اشتراک گذاری این نوشته در شبکه‌های اجتماعی

توسعه ترس محور یا Fear Driven Development چیست؟

توسعه ترس محور

روز گذشته اسکات هنسلمن نوشته‌ای رو در وبلاگش منتشر کرد و از ترس‌هایی که تبدیل به یک روال توسعه نرم‌افزار می‌شوند گفت. او نام توسعه ترس محور یا Fear Driven Development را برای این موضوع انتخاب کرده. شما هم در نظرات این نوشته از تجربیات خودتان درباره کار به روش ترس محور بگویید

ترس سازمانی

ترس سازمانی باعث می‌شود که برنامه‌نویس‌ها نگران اشتباه کردن، شکستن build یا ایجاد باگ‌های بشوند و سازمان را مشغول تمرکز بیشتر بر تولید کاغذ یا ایجاد بیش از حد پروسه‌ها و روال‌ها و خلاصه ایستادن در راه نوشتن کد.

این «فلج تحلیلی» کل پروژه را کند می‌کند. یک نوشته خوب تحت عنوان «۱۰ راه برای از دست دادن تیم» وجود دارد که بسیاری از این رفتارهای منفی را پوشش داده. مواردی مثل:

  • ممنوع کردن جلسات تک به تک
  • عدم به اشتراک‌گذاری اطلاعات
  • القاء اینکه هر کسی را می‌توان جایگزین کرد
  • مدیریت به سبک Micromanagement

همه این رفتارها باعث افزایش ترس محیطی و ایجاد ابری از اضطراب در سازمان می‌شود

ترس از دست دادن شغل

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

ترس از تغییر کد

یک نوع دیگر از Fear Driven Development وقتی است که بخش توسعه نرم‌افزار سازمان یا کل سازمان از کد می‌ترسند! شاید کد قدیمی باشد (legacy code) اما معمولاً کد قدیمی فقط به خوبی درک نمی‌شود. کد قدیمی تقریباً درست کار می‌کند، اما افراد از تغییرات حتی کوچک در کد به دلیل اینکه ممکن است باعث ایجاد اثرات جانبی بشوند واهمه دارند. ترس از رگرسیون باگ- بازگشت مجدد باگ‌هایی که بسته یا رفع شده‌اند نیز باعث استرس برنامه‌نویسان می‌شود.

شما چه انواع دیگری از توسعه ترس محور را می‌شناسید؟

به اشتراک گذاری این نوشته در شبکه‌های اجتماعی

گزارش آماری از دستمزد برنامه‌نویسان و طراحان وب در ایران

گزارش آماری حقوق و دستمزد سال ۱۳۹۲

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

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

در این طرح آماری ۲۹ هزار نفر شرکت داشته‌اند که ۷۰ درصد آنان را مردان تشکیل می‌دهند. نزدیک به ۳۰ درصد مسلط به زبان انگلیسی بوه‌اند. ۴۵ درصد کارشناس، ۲۸ درصد سرپرست و ۲۷ درصد مدیر بوده‌اند. ۴۱ درصد فارغ‌التحصیل دانشگاه دولتی و ۳۹ درصد فارغ‌التحصیل دانشگاه آزاد و ۲۰ درصد سایر مراکز آموزشی بوده‌اند. ۵۶ درصد مدرک لیسانس و ۳۳ درصد فوق لیسانس و دکترا و سایر موارد نیز ۱۱ درصد شرکت‌کنندگان را تشکیل می‌دهند.

نکات شاخص گزارش آماری دستمزدها در سال ۹۲

  • دریافتی ماهانه در شرکت‌های خارجی فعال در ایران به طور متوسط ۳۳ درصد بالاتر از عرف بازار است و در برخی سمت‌ها متوسط این اختلاف به ۵۰ درصد نیز می‌رسد.
  • دریافتی افراد با تحصیلات فوق لیسانس به طور متوسط ۱۷ درصد بالاتر از افراد با تحصیلات لیسانس است.
  • دریافتی فارغ‌التحصیلان دانشگاه‌های دولتی به طور متوسط ۱۷ درصد بالاتر از فارغ‌التحصیلان دانشگاه‌های آزاد است.
  • متوسط دریافتی خانم‌ها در سمت‌های مشابه نسبت به آقایان ۲۳ درصد کمتر است.

بررسی حقوق و دستمزد شاغلان در حوزه فناوری اطلاعات در سال ۹۲

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

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

جزئیات دستمزد مهندسان کامپیوتر شاغل در حوزه نرم‌افزار و طراحی وب بر حسب سابقه کار به شرح زیر است:

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

به اشتراک گذاری این نوشته در شبکه‌های اجتماعی

۳۰ روز با TDD: روز دهم - بررسی بیشتر Refactoring‌ و NUnit

داستان ۳۰ روز با TDD

سپتامبر سال گذشته آقای James Bender در وبلاگ‌های تلریک یک مجموعه نوشته منتشر کرد به نام ۳۰ روز با TDD. در ترجمه‌ای آزاد در وبلاگ آرایه، با هم در طول یک ماه با Test Driven Development آشنا می‌شویم. لینک سایر نوشته‌های این سری را در صفحه ۳۰ روز با TDD می‌توانید مشاهده کنید.

و اما دهمین روز: بررسی بیشتر Refactoring و NUnit

در نوشته روز نهم، درباره Refactoring صحبت کردیم، نوشته به زبان انگلیسی روز دهم را در این آدرس می‌توانید مطالعه کنید. در روز دهم با امکانات بیشتری در NUnit و همچنین Refactoring آشنا خواهیم شد.

بهترین شمشیرها از هر دو طرف می‌برند

نه تنها مهم است که به صورت دوره‌ای کد business logic خودمان را refactor کنیم، بلکه لازم است به صورت دوره‌ای تست‌ها را نیز بررسی کنیم. به یاد داشته باشید که تست‌ها هم نوعی کد هستند و نیازمند نگهداری مشابه. اجازه بدهید نگاهی به تست‌های جاری‌مان داشته باشیم:

 
using System;
using System.Linq;
using NUnit.Framework;
 
namespace ThirtyDaysOfTDD.UnitTests
{
    [TestFixture]
    public class StringUtilsTest
    {
        [Test]
        public void ShouldBeAbleToCountNumberOfLettersInSimpleSentence()
        {
            var sentenceToScan = "TDD is awesome!";
            var characterToScanFor = "e";
            var expectedResult = 2;
            var stringUtils = new StringUtils();
 
            int result = stringUtils.FindNumberOfOccurences(sentenceToScan, characterToScanFor);
 
            Assert.AreEqual(expectedResult, result);
        }
 
        [Test]
        public void ShouldBeAbleToCountNumberOfLettersInAComplexSentence()
        {
            var sentenceToScan = "Once is unique, twice is a coincidence, three times is a pattern.";
            var characterToScanFor = "n";
            var expectedResult = 5;
            var stringUtils = new StringUtils();
 
            int result = stringUtils.FindNumberOfOccurences(sentenceToScan, characterToScanFor);
 
            Assert.AreEqual(expectedResult, result);
        }
 
        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void ShouldGetAnArgumentExceptionWhenCharacterToScanForIsLargerThanOneCharacter()
        {
            var sentenceToScan = "This test should throw an exception";
            var characterToScanFor = "xx";
            var stringUtils = new StringUtils();
 
            stringUtils.FindNumberOfOccurences(sentenceToScan, characterToScanFor);
        }
    }
}

یک نگاه سریع به این کد، یکی از اهداف مشترک refactoring را آشکار می‌کند: تکرار کد. اگر به خط‌های ۱۶ و ۲۹ و ۴۲ نگاه کنید می‌بینید که من مرتباً وهله‌های (instance) جدیدی از کلاس StringUtils برای هر تست ایجاد کردم. در کل من مایل به رعایت اصل DRY هستم. DRY سرنام عبارت Don't Repeat Yourself است. در این مثال من مشخصاً و زمانی که نیازی ندارم در حال تکرار کدم که وهله‌ای از StringUtils ایجاد می‌کند هستم. خوشبختانه NUnit مکانیزم برای کمک به ما برای DRY شدن کدمان فراهم می‌کند.

اما پیش از اینکه به سراغ تغییر تست‌ها برویم، لازم است سوالی را از خودمان بپرسیم: از کجا باید بدانم که تغییر دادن تست‌ها باعث شکستن آن‌ها نمی‌شود؟ وقتی ما کد business logic برنامه را تغییر می‌دادیم، آزمون‌های واحد (unit test) داشتیم که به ما اطمینان می‌داد نتایج refactoring ما همچنان نیازهای تجاری که بر اساس آزمون‌های واحد تعریف شده‌اند را پوشش می‌دهند. تا زمانی که تست‌ها ما پاس می‌شدند، مطمئن بودیم که business logic همچنان نیازمندی‌های ما را برآورده می‌کند. 
اگر واقعاً TDD را تمرین کرده باشیم، یعنی فقط بر اساس تست‌هایمان کد نوشته باشیم (و اول هم تست نوشته باشیم) آنگاه می‌توانیم از business logic برای اعتبارسنجی تست‌هایمان استفاده کنیم. این همان شمشیر دو لبه است و بدان معنی است که می‌توانیم تست‌هایمان refactor کنیم و تا زمانی که تست‌ها همچنان پاس می‌شوند و با شرط آنکه در همین حین business logic را تغییر نداده باشیم، تست‌های ما همچنان معتبر هستند.

در خصوص refactor تست‌ها، کاری که می‌خواهم انجام بدهم این است که کدی بنویسم که وهله‌ای از StringUtils برای استفاده در همه تست‌ها را ایجاد کند. تاثیر واقعی این کار وقتی در نوشته‌های بعدی درباره mocking صحبت کنیم نشان داده خواهد شد. معمولاً این کار را با ایجاد یک متد قابل استفاده مجدد انجام می‌دهم یا در این مورد خاص با استفاده از DI Framework اما NUnit راه بهتری را ممکن می‌کند.

میان ویژگی‌های مختلف NUnit قابلیت تعریف متدهای SetUp وجود دارد. یک متد setup در NUnit با استفاده از خاصیت SetUp به شکل زیر تعریف می‌شود. وقتی یک متد SetUp در یک test fixture در NUnit تعریف می‌شود قبل از اجرای هر تست در آن کلاس test fixture اجرا خواهد شد:

private StringUtils _stringUtils;
 
        [SetUp]
        public void SetupStringUtilTests()
        {
            _stringUtils = new StringUtils();
        }

من یک متغیر وهله خصوصی (private instance) از نوع StringUtils تعریف کردم و متدی به نام SetupStringUtilsTests ایجاد کردم که در آن وهله جدیدی از کلاس StringUtils‌ را به متغیر خصوصی مربوطه انتساب می‌دهم. قدم بعدی refactor کردن تست‌ها برای استفاده از این متغیر است:

using System;
using System.Linq;
using NUnit.Framework;
 
namespace ThirtyDaysOfTDD.UnitTests
{
    [TestFixture]
    public class StringUtilsTest
    {
        private StringUtils _stringUtils;
 
        [SetUp]
        public void SetupStringUtilTests()
        {
            _stringUtils = new StringUtils();
        }
 
        [Test]
        public void ShouldBeAbleToCountNumberOfLettersInSimpleSentence()
        {
            var sentenceToScan = "TDD is awesome!";
            var characterToScanFor = "e";
            var expectedResult = 2;
 
            int result = _stringUtils.FindNumberOfOccurences(sentenceToScan, characterToScanFor);
 
            Assert.AreEqual(expectedResult, result);
        }
 
        [Test]
        public void ShouldBeAbleToCountNumberOfLettersInAComplexSentence()
        {
            var sentenceToScan = "Once is unique, twice is a coincidence, three times is a pattern.";
            var characterToScanFor = "n";
            var expectedResult = 5;
 
            int result = _stringUtils.FindNumberOfOccurences(sentenceToScan, characterToScanFor);
 
            Assert.AreEqual(expectedResult, result);
        }
 
        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void ShouldGetAnArgumentExceptionWhenCharacterToScanForIsLargerThanOneCharacter()
        {
            var sentenceToScan = "This test should throw an exception";
            var characterToScanFor = "xx";
            
            _stringUtils.FindNumberOfOccurences(sentenceToScan, characterToScanFor);
        }
    }
}

اجرای تست‌ها نشان می‌دهد که آن‌ها بعد از این تغییر همچنان پاس می‌شوند

این کار قطعاً تست‌های ما را خواناتر کرده است. همچنین به ما این قابلیت را داده تا کدی که از StringUtils وهله می‌سازد را یک جا کپسوله‌سازی کنیم. در واقع اگر کد ما تغییری کند، ما فقط یک متد را باید تغییر بدهیم نه n تا تست! استفاده از خاصیت SetUp به ما این قابلیت را می‌دهد تا متدهایی را تعریف کنیم که قبل از هر تست اجرا شوند. در شرایطی که کلاس زیر تست ما وضعیتی دارد که هر بار باید قبل از اجرای هر تست مجدداً ایجاد شود، استفاده از SetUp گزینه خوبی است. اما StringUtils ما چنین وضعیتی ندارد و نیازی نیست هر دفعه دوباره از اول ایجاد شود. اینجاست که از می‌توانیم از خاصیت TestFixtureSetUp برای setup method خودمان استفاده کنیم. این خاصیت مشابه SetUp عمل می‌کند، اما به جای اجرا پیش از هر تست، یک بار برای هر instance از کلاس test fixture اجرا می‌شود. در مثال ما کلاس test fixture‌ سه تست دارد. در حالی که SetUp باعث اجرای سه مرتبه‌ای وهله‌سازی StringUtils می‌شود، TestFixtureSetUp یک بار برای هر سه تست ما اجرا و از یک وهله مشترک از کلاس StringUtils که توسط setup method ایجاد شده استفاده می‌کند.

از آنجایی که ما هر دفعه به یک وهله جدید از StringUtils نیاز نداریم، کد را برای استفاده از TestFixtureSetUp به شکل زیر تغییر می‌دهیم:

private StringUtils _stringUtils;
 
        [TestFixtureSetUp]
        public void SetupStringUtilTests()
        {
            _stringUtils = new StringUtils();
        }

تست‌ها را دوباره اجرا می‌کنیم تا مطمئن شویم refactor اخیر ما چیزی را خراب نکرده باشد.

آخرین نکته درباره SetUp و TestFixtureSetUp‌ این است که NUnit فقط یک وهله از این خاصیت‌ها را در هر test fixture پشتیبانی می‌کند. شما می‌توانید از هر کدام یکی در test fixture خود داشته باشید اما مثلاً امکان مزین کردن دو متد با SetUp وجود ندارد. این کار موقع کامپایل خطایی به شما نمی‌دهد، اما در صورت تخطی، NUnit نمی‌تواند تست‌های شما را اجرا کند.

ادامه دارد...

به اشتراک گذاری این نوشته در شبکه‌های اجتماعی