صادرات نرم‌افزار و خدمات نرم‌افزاری: خوب، بد، زشت

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

صادرات ۴۰۰ میلیون دلاری نرم‌افزاری ایران: واقعیت یا افسانه؟

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

۱- صادرات نرم‌افزار: خوب

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

۲- صادرات نرم‌افزار: بد

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

۳- صادرات نرم‌افزاری: زشت

تا اینجای کار خلاصه صحبت این شده: پتانسیل خوبی برای صادرات نرم‌افزار و خدمات نرم‌افزاری داریم. به جز مبادلات مالی، کمتر دچار دردسرهای محدودیت‌های سیاسی ایجاد شده برای صادرات در حوزه‌هایی نظیر انرژی یا کالاهای تولیدی صنایع هستیم. هر چند در حوزه مبادلات مالی هم لااقل در مبالغ خرد، نگرانی وجود ندارد. به عنوان مثال یکی از سایت‌های ارائه‌دهنده خدمات ارزی اخیراً اعلام کرده بود که از مجموعه Envato‌ (تم فارست و سایت‌های مرتبط با آن) ماهیانه تا ۷۰ هزار دلار از درآمد کاربران را نقد می‌کرده است. در کنار مزایای ذکر شده، با چالش تولید محصولات منطبق بر نیاز مشتریان بین‌المللی مواجه هستیم.
در کنار توضیحات بالا، پاشنه آشیل ما در صنعت نرم‌افزار، ضعف مهارت‌ها و نیاز به توانمند‌سازی نیروی انسانی و اصلاح پروسه‌های تولید نرم‌افزار در شرکت‌هاست.

تجربه آرایه

ما در آرایه تجربه ارائه خدمات نرم‌افزاری برای یک مشتری بین‌المللی را داریم. مشتری ما به کمک بیش از ۷۰۰ سرور در سه دیتاسنتر در نقاط مختلف دنیا و ۲۷۰۰ سرور مجازی و ۲۰ هزار کامپیوتر در قاره‌های مختلف کسب و کارش را مدیریت می‌کند. نرم‌افزاری که ما روی آن کار کردیم مورد استفاده بیش از ۳۵ هزار کارمند بود و در اجرای کار، ما در رقابت با یک شرکت هندی بودیم. نکته جالب این بود که شرکت هندی رقیب، وقتی ما پروتوتایپی از کار را آماده می‌کردیم، پروتوتایپی با جزئیات بیشتر را آماده کرده بود! و کارشان خوب بود. آن‌ها مسلط به زبان انگلیسی بودند، تجربه اجرای موفق کارهای مشابه را داشتند و همه ایام هفته سخت کار می‌کردند (بعضاً روزی ۱۶ ساعت) و مشتریانی از سراسر دنیا داشتند...

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

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

۳۰ روز با TDD: روز شانزدهم- استفاده از پارامترهای مشخص در Stub ها

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

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

و اما شانزدمین روز: استفاده از پارامترهای مشخص در Stub ها

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

برای ارائه اطلاعات مشتری (اعم از نام و آدرس) CustomerService می‌بایست تغییر کند.

using System;
namespace TddStore.Core
{
    public class Customer
    {
        public Guid Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public Address ShippingAddress { get; private set; }




        public Customer()
        {
            ShippingAddress = new Address();
        }
    }




    public class Address
    {
        public string StreetAddressOne { get; set; }
        public string StreetAddressTwo { get; set; }
        public string City { get; set; }
        public string State { get; set; }
        public string Zip { get; set; }
    }
}

سپس به یک Interface برای Customer Service نیاز داریم

using System;




namespace TddStore.Core
{
    public interface ICustomerService
    {
        Customer GetCustomer(Guid customerId);
    }
}

هم تعریف Entity و هم Interface مربوط به Customer Service را به پروژه TddStore.Core اضافه می‌کنیم.

در این قسمت باید از اولین تست کیس مربوط به تعامل با OrderFulfillment Service صحبت کنم که جالب است بدانید هیچ ارتباطی با خود OrderFulfillment ندارد! در این مورد می‌خواهم مطمئن شوم که OrderService به درستی از CustomerService استفاده می‌کند.

صورت مساله تست: وقتی یک مشتری معتبر سفارشی را ثبت می‌کند (که اعتبارسنجی آن انجام شده) این سفارش ثبت شده و یک شناسه سفارش برگردانده می‌شود

به یک تست جدید نیاز دارم:


[Test]
        public void WhenAValidCustomerPlacesAValidOrderAnOrderShouldBePlaced()
        {
            //Arrange
            var shoppingCart = new ShoppingCart();
            shoppingCart.Items.Add(new ShoppingCartItem { ItemId = Guid.NewGuid(), Quantity = 1 });
            var customerId = Guid.NewGuid();
            
            //Act
            _orderService.PlaceOrder(customerId, shoppingCart);
        }

بلی! این شبیه شروع تست WhenUserPlacesACorrectOrderThenAnOrderNumberShouldBeReturned  به نظر می‌رسد و خیر! نباید WhenUserPlacesACorrectOrderThenAnOrderNumberShouldBeReturned را تغییر دهیم که در کنار تست اصلی، تعامل با CustomService را نیز تست کند.

هدف تست اصلی این است که تعامل با OrderDataSevice به درستی کار می‌کند. جزئیات این تعامل بسته به اینکه متد چطور با CustomerService کار می‌کند ممکن است متفاوت باشد. با تکامل این تست‌ها، نیاز به mock‌های بیشتر OrderDataService حس می‌شود. این باعث می‌شود که هر دو تعامل (از OrderService به OrderDataService و از OrderService به CustomerService) تقریباً مستقل از هم تغییر کنند که باعث تولید تست‌های شکننده کمتری می‌شود. همچنین با استفاده از این روش، چنانچه تستی fail شود دقیقاً خواهم دانست که آیا ارتباط بین OrderDataService و CustomerService باعث این fail شده یا خیر.

قبل از اینکه جلوتر برویم، لازم است وهله (instance) از mock مربوط به CustomerService را در کلاس OrderServiceTests معرفی کنم. همچنین باید از SetupTestFixture نیز استفاده کنم.

    [TestFixture]
    class OrderServiceTests
    {
        private OrderService _orderService;
        private IOrderDataService _orderDataService;
        private ICustomerService _customerService;

        [TestFixtureSetUp]
        public void SetupTestFixture()
        {
            _orderDataService = Mock.Create();
            _customerService = Mock.Create();
            _orderService = new OrderService(_orderDataService, _customerService);
        }

می‌دانم که برای نیازمندی مطرح شده در OrderFultillment باید مشتری را از CustomerService بازیابی (retrieve) کنم. در حال حاضر mock مربوط به CustomerService را تعریف کرده‌ام، پس حالا باید arrange انجام شود. در این مورد می‌خواهم stub من یک مشتری مشخص را وقتی که GetCustomer با پارامتر خاصی فراخوانی می‌شود برگرداند.

           [Test]
        public void WhenAValidCustomerPlacesAValidOrderAnOrderShouldBePlaced()
        {
            //Arrange
            var shoppingCart = new ShoppingCart();
            shoppingCart.Items.Add(new ShoppingCartItem { ItemId = Guid.NewGuid(), Quantity = 1 });
            var customerId = Guid.NewGuid();
            var customerToReturn = new Customer { Id = customerId, FirstName = "Fred", LastName = "Flinstone" };

            //Act
            _orderService.PlaceOrder(customerId, shoppingCart);
        }

در ایجاد شی customerToReturn من شی Customer را با Id و نام و نام خانوادگی پر کردم. از نظر فنی در حال حاضر نیازی به نام و نام خانوادگی در این شی ندارم، اما می‌خواهم تا جای ممکن فیلدهای بیشتری را برای تست پر کنم. حالا که ورودی و خروجی تعریف شده‌اند، می‌توانم stub را arrange کنم. در این مورد فقط می‌خوام تا stub مربوط به CustomerService مقدار cutsomterToReturn را وقتی که GetCustomer با پارامتر CustomerId فراخوانی می‌شود برگرداند. همچنین انتظار دارم این متد تنها یک بار فراخوانی شود

        [Test]
        public void WhenAValidCustomerPlacesAValidOrderAnOrderShouldBePlaced()
        {
            //Arrange
            var shoppingCart = new ShoppingCart();
            shoppingCart.Items.Add(new ShoppingCartItem { ItemId = Guid.NewGuid(), Quantity = 1 });
            var customerId = Guid.NewGuid();
            var expectedOrderId = Guid.NewGuid();
            var customerToReturn = new Customer { Id = customerId, FirstName = "Fred", LastName = "Flinstone" };


            Mock.Arrange(() => _orderDataService.Save(Arg.IsAny()))
                .Returns(expectedOrderId)
                .OccursOnce();


            Mock.Arrange(() => _customerService.GetCustomer(customerId))
                .Returns(customerToReturn)
                .OccursOnce();


          //Act
            var result = _orderService.PlaceOrder(customerId, shoppingCart);


            //Assert
            Assert.AreEqual(expectedOrderId, result);
            Mock.Assert(_orderDataService);
        }

در پایان لازم است فراخوانی صحیح mock جدید را با assert چک کنم. این کار را با فراخوانی Mock.Assert و پاس دادن mock مربوط به CustomerService می‌توانم انجام بدهم.

        [Test]
        public void WhenAValidCustomerPlacesAValidOrderAnOrderShouldBePlaced()
        {
            //Arrange
            var shoppingCart = new ShoppingCart();
            shoppingCart.Items.Add(new ShoppingCartItem { ItemId = Guid.NewGuid(), Quantity = 1 });
            var customerId = Guid.NewGuid();
            var customerToReturn = new Customer { Id = customerId, FirstName = "Fred", LastName = "Flinstone" };

            Mock.Arrange(() => _customerService.GetCustomer(customerId))
                .Returns(customerToReturn)
                .OccursOnce();

            //Act
            _orderService.PlaceOrder(customerId, shoppingCart);


            //Assert
            Mock.Assert(_customerService);
        }

همانطور که انتظار داریم تست هنگام اجرا fail می‌شود

کد stub‌ مربوط به CustomerService من فراخوانی نشده. باید به متد PlaceOrder در کلاس OrderService بروم و منطق فراخوانی CustomerService را پیاده سازی کنم.

        public Guid PlaceOrder(Guid customerId, ShoppingCart shoppingCart)
        {
            foreach (var item in shoppingCart.Items)
            {
                if (item.Quantity == 0)
                {
                    throw new InvalidOrderException();
                }
            }
            var customer = _customerService.GetCustomer(customerId);
            var order = new Order();
            return _orderDataService.Save(order);
        }

در این قسمت نمی‌توانم کدم را اجرا کنم چون کامپایل نمی‌شود. ارجاع (reference) به CustomerService در کلاس OrderService ندارم. پس گام بعدی تغییر OrderService برای پذیرش ICustomerService به عنوان یک وابستگی است که از طریق سازنده (constructor) آن را تزریق می‌کنم (برای این تغییر کد راحت‌تر باشد متد PlaceOrder را از نمونه کد زیر برداشتم)

 using System;
using TddStore.Core.Exceptions;


namespace TddStore.Core
{
    public class OrderService
    {
        private IOrderDataService _orderDataService;
        private ICustomerService _customerService;

        public OrderService(IOrderDataService orderDataService, ICustomerService customerService)
        {
            _orderDataService = orderDataService;
            _customerService = customerService;
        }


        public Guid PlaceOrder(Guid customerId, ShoppingCart shoppingCart)
        {
            foreach (var item in shoppingCart.Items)
            {
                if (item.Quantity == 0)
                {
                    throw new InvalidOrderException();
                }
            }

            var order = new Order();
            return _orderDataService.Save(order);
        }
    }
}

اجرای مجدد تست‌ها نشان می‌دهد که کد همچنان کامپایل نمی‌شود. دلیلش این است که در متد SetupTestFixture کلاس OrderServiceTests تلاش می‌کنیم وهله (instance) از OrderService بدون پاس دادن ICustomerService به سازنده (constrcutor) کلاس بسازیم. برای این کار متد را برای تامین mock در سازنده OrderService تغییر دادم (برای مشاهده راحت‌تر تغییر کد، using ها و متدهای تست را از کلاس برداشتم)

using System;
using System.Linq;
using NUnit.Framework;
using TddStore.Core;
using TddStore.Core.Exceptions;
using Telerik.JustMock;

namespace TddStore.UnitTests
{
    [TestFixture]
    class OrderServiceTests
    {
        private OrderService _orderService;
        private IOrderDataService _orderDataService;
        private ICustomerService _customerService;

        [TestFixtureSetUp]
        public void SetupTestFixture()
        {
            _orderDataService = Mock.Create();
            _customerService = Mock.Create();
            _orderService = new OrderService(_orderDataService, _customerService);
        }


        [Test]
        public void WhenUserPlacesACorrectOrderThenAnOrderNumberShouldBeReturned()
        {
            //Arrange
            var shoppingCart = new ShoppingCart();
            shoppingCart.Items.Add(new ShoppingCartItem { ItemId = Guid.NewGuid(), Quantity = 0 });
            var customerId = Guid.NewGuid();
            var expectedOrderId = Guid.NewGuid();


            Mock.Arrange(() => _orderDataService.Save(Arg.IsAny()))
                .Returns(expectedOrderId)
                .OccursOnce();
            
            //Act
            var result = _orderService.PlaceOrder(customerId, shoppingCart);


            //Assert
            Assert.AreEqual(expectedOrderId, result);
            Mock.Assert(_orderDataService);
        }


        [Test]
        public void WhenAUserAttemptsToOrderAnItemWithAQuantityOfZeroThrowInvalidOrderException()
        {
            //Arrange
            var shoppingCart = new ShoppingCart();
            shoppingCart.Items.Add(new ShoppingCartItem { ItemId = Guid.NewGuid(), Quantity = 0 });
            var customerId = Guid.NewGuid();
            var expectedOrderId = Guid.NewGuid();
            
            Mock.Arrange(() => _orderDataService.Save(Arg.IsAny()))
                .Returns(expectedOrderId)
                .OccursNever();


            //Act
            try
            {
                _orderService.PlaceOrder(customerId, shoppingCart);
            }
            catch(InvalidOrderException ex)
            {
                //Assert
                Mock.Assert(_orderDataService);
                Assert.Pass();
            }



            //Assert
            Assert.Fail();
        }
    }
}

حالا تست آماده اجراست و همانطور که در تصویر زیر مشخص است، pass می‌شود.

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

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

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

چطور (تقریباً) هر چیزی را در git به حالت قبلی برگردانیم؟ قسمت اول

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

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

در آرایه از Git بر روی TFS به عنوان Source Control استفاده می‌کنیم، کدهای backup‌ گرفته شده روی اینترنت نیز از Git به عنوان سورس کنترل استفاده می‌کنند.

این نوشته ترجمه خلاصه شده‌ای است از How to undo (almost) anything with Git که در وبلاگ گیت‌هاب انتشار یافته است و از سهیل رشیدی برای معرفی آن در خبرنامه iDevCenter تشکر می‌کنیم.

undo کردن تغییر عمومی (Public)

سناریو: شما از دستور git push  استفاده کردید و تغییرات را به گیت‌هاب فرستادید و حالا متوجه شدید که یکی از commit ها مشکلی دارد، می‌خواهید آن commit را undo کنید.

دستور Undo: برای سناریو بالا از دستور زیر استفاده کنید:

git revert 
تعمیر توضیح آخرین commit

سناریو: در آخرین commit اشتباه تایپی دارید، دستور شما مثلاً  git commit -m "Fxies bug #42" بوده است اما قبل از git push متوجه شدید که Fixes اشتباه تایپ شده است.

دستور Undo: برای سناریو بالا از دستور زیر استفاده کنید:

git commit --amend or git commit --amend -m "Fixes bug #42"
Undo کردن تغییرات محلی (local changes)

سناریو: گربه‌ای روی کیبورد راه رفته و تغییرات ایجاد شده هم به شکلی ذخیره شده‌اند.، بعد ادیتور هم crash کرده است. شما این تغییرات را commit نکرده‌اید و می‌خواهید فایل را به حالت قبلی‌اش (آخرین commit) برگردانید.

دستور Undo: برای سناریو بالا از دستور زیر استفاده کنید

git checkout --

به یاد داشته باشید هر تغییری که به این شیوه Undo می‌کنید واقعاً از بین خواهد رفت. در واقع تغییرات در این حالت هیچ وقت commit‌ نمی‌شوند و لذا git در بازیابی ‌آن‌ها به ما کمکی نخواهد کرد. بنابراین پیش از استفاده از این دستور، مطمئن شوید می‌دانید چه چیزهایی را دور می‌ریزید. از git diff استفاده کنید تا مطمئن شوید کارتان برای undo کردن درست است

پی‌نوشت: به خاطر طولانی بودن مطلب اصلی، ترجمه آن در قالب چند نوشته مجزا منتشر خواهد شد


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

۱۰ اصل برای داشتن یک رابط کاربری خوب

یک قول قدیمی

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

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


اصل اول: شفافیت وضعیت سیستم

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

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

اصل دوم: هماهنگی بین سیستم و دنیای واقعی

سیستم باید به زبان کاربران صحبت کند،‌ با کلمات و عبارات و ایده‌های نزدیک به ذهن کاربران به جای استفاده از عبارات سیستم محور. استفاده از کنوانسیون‌های دنیای واقعی، باعث می‌شود اطلاعات به صورت طبیعی و منظم ارائه شوند.

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

اصل سوم: کنترل و آزادی کاربر

بعضی اوقات کاربران، در انتخاب کاری که با سیستم می‌خواهند انجام دهند اشتباه می‌کنند و نیاز به یک خروجی اضطراری مشخص دارند تا بدون دیالوگ اضافی با سیستم، بتوانند از وضعیت ناخواسته فعلی خارج شوند. لغو کار قبلی (undo) و انجام مجدد آن (redo) را پشتیبانی کنید.

اصل چهارم: ثبات و استانداردها

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

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

اصل پنجم: جلوگیری از خطا

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

اصل ششم: شناسایی بهتر از به خاطر آوردن

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

اصل هفتم: انعطاف پذیری و کارآمدی در استفاده

هر نرم‌افزاری ممکن است توسط کاربران مبتدی یا کاربران حرفه‌ای مورد استفاده قرار گیرد. به کاربران اجازه بدهید که کارهای تکراری را ساده‌تر کنند.

اصل هشتم: طراحی زیبا و مینیمال

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

اصل نهم: به کاربران کمک کنید تا خطاها را بشناسند، تشخیص بدهند و ترمیم کنند

پیغام‌های خطا باید به زبان طبیعی انسانی بیان شوند و نه با کد. این پیغام‌ها باید به طور مشخص، مشکل را بیان کنند و به شکل سازنده، راه حلی برایش ارائه کنند.

در توضیح این اصل، شاید بتوان به انواع و اقسام کدهای خطا که با دید developer ایجاد می‌شوند اشاره کرد. مثلاً خطای 404‌ را در نظر بگیرید. درست است که توسعه‌دهندگان وب می‌دانند کد خطای 404‌ مربوط به چه چیزی است، اما کاربر باید دقیقاً متوجه منظور از 404 شده و همچنین به وی راهی (مثل قرار دادن لینک به صفحه نخست سایت یا بخش جستجو و ...) برای خروج از این خطا پیشنهاد شود.

اصل دهم: راهنما و مستندات 

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

شما چه ایده‌ای برای بهتر شدن تعامل بین کاربران و نرم‌افزارها و ایجاد نرم‌افزارهای بهتر دارید؟

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

آگاهی امنیتی : چگونگی بدست آوردن کلمه عبور Application Pool های IIS

این نوشته را در دسته‌بندی برنامه‌نویسی شیرپوینت قرار دادم چرا که بیشترین زمانی که با Application Pool ها سر و کار داشتم زمان نصب و تنظیم شیرپوینت بوده است.

کد اصلی مربوط به نوشته آقای Sahil Malik است. در شیرپوینت ۲۰۰۷ می‌توانستیم با استفاده از SPApplicationPool.Password کلمه عبور Application Pool را بدست آوریم که در نسخه‌های بعدی دیگر استفاده نمی‌شود. برنامه‌ای به نام appcmd در آدرس c:\windows\system32\inetsrv وجود دارد که با استفاده از دستور زیر کلمه عبور Application Pool را به شما نمایش می‌دهد. کافی است به جای Your_ApplicationPool_Name نام ApplicationPool‌ مورد نظر را قرار دهید.

appcmd.exe list apppool "Your_ApplicationPool_Name" /text:ProcessModel.Password

پی نوشت: دستور بالا کلمه عبور را به صورت plain text نمایش می‌دهد. مایکروسافت جهت تنظیم Application Pool ‌های شیرپوینت راهنماهایی دارد. کاری که عموماً به مظور تسریع در نصب و راه‌اندازی در سرورهای توسعه (development) انجام می‌دهیم استفاده از کاربرانی با حداکثر سطح دسترسی در اکتیو دایرکتوری (بعضاً domain admin) است. این کار به هیچ وجه برای محیط‌ مشتری توصیه نمی‌شود.

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

(تقریباً) همه چیزی که درباره Windows Azure باید بدانید

ویندوز آژور و آرایه

سال گذشته و پس از طی مراحل مشکلی (البته مشکل به خاطر ایرانی بودن) این امکان را یافتیم تا خدمات Azure مایکروسافت را آزمایش کنیم. این نوشته که به صورت پرسش و پاسخ است، نگاهی دارد به امکانات Azure.
این نوشته با پرسش‌های شما تکمیل خواهد شد. می‌توانید در بخش نظرات پرسش‌های خود را در خصوص Azure مطرح کنید. در نگارش این مطلب، از نوشته اسکات هنسلمن که به مبحث قیمت‌های آژور می‌پردازد نیز استفاده شده است.

 

Azure چیست؟

تعریف ویکی‌پدیا: ویندوز اَژور (به انگلیسی: Windows Azure) یک پلاتفرم رایانش ابری مایکروسافت است که برای ایجاد، توسعه و مدیریت اپلیکیشن‌ها از طریق یک شبکه جهانی از مراکز داده تحت مدیریت مایکروسافت می‌باشد. ویندوز اَژور این قابلیت را دارد که اپلیکیشن‌ها را توسط زبان‌ها، ابزارها و چهارچوب‌های مختلفی ایجاد کرده و به توسعه دهندگان امکان ادغام اپلیکیشن‌های عمومی خود را در محیط فناوری اطلاعات موجود می‌دهد.

بسیار خب، حالا آژور واقعاً چی داره؟

وقتی در آژور ثبت‌نام کنید، کنترل پنلی شبیه تصویر زیر را خواهید داشت:

به کمک این کنترل پنل می‌توانید این کارها را انجام دهید:

  • ایجاد وب سایت
  • ایجاد Virtual Machine
  • ایجاد سرویس‌های Mobile
  • ایجاد سرویس‌های Cloud
  • ایجاد دیتابیس
  • ایجاد فضای ذخیره‌سازی
  • ایجاد فضای backup/restore
  • ایجاد کلاستر
  • ایجاد CDN
  • ایجاد سرور Active Directory
  • ایجاد سرور برای ذخیره Media
  • ایجاد Virtual Network
  • ...

آیا وب‌سایت‌ها و سرورهای ایجاد شده در آژور، همگی ویندوزی هستند؟

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

در Virtual Machine ها هم می‌توانید از سیستم عامل‌های ویندوز سرور یا انواع توزیع‌های لینوکس داشته باشید تا VM های تخصصی مثل شیرپوینت یا اوراکل. همچنین اگر VM مد نظر شما در لیست نبود می‌توانید با استفاده از فایل VM ای که معرفی می‌کنید یک سرور مجازی داشته باشید.

همچنین وب سایت‌های آژور از تکنولوژی‌های مختلفی پشتیبانی می‌کنند و شما علاوه بر نسخه‌های مختلف دات نت، امکان استفاده از php، جاوا و python را هم دارید

آژور بر روی چه تعداد سرور اجرا شده است؟

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

وب سایت من پربازدید است، آیا می‌توانم آن را در آژور قرار بدهم؟

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

آژور چه امکاناتی به برنامه‌نویسان می‌دهد؟

یکی از جذاب‌ترین امکانات آزور امکاناتی است که در خصوص یکپارچگی با سورس کنترل‌ها دارد. همانطور که می‌دانید سرویس سایت VisualStudio.com برای تیم‌های ۵ نفر رایگان است و به صورت رایگان مخازن کد خصوصی ارائه می‌دهد. سورس کنترل این مخازن می‌تواند مایکروسافتی (TFS Source Control) یا git‌ باشد (که در هر حال بر بستر TFS Online کار می‌کند)

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

آیا آژور سرویس رایگان دارد؟

هم بلی و هم خیر! مایکروسافت امکان یک دوره آزمایشی ۳۰ روزه از تمام امکانات آژور را فراهم کرده است که پیش از آن باید ثبت‌نام کنید (درباره روال ثبت‌نام در ادامه خواهم گفت) علاوه بر این دوره آزمایشی، مایکروسافت به هر اکانت در هر دیتاسنتر، ۱۰ وب سایت رایگان می‌دهد. البته زیاد ذوق زده نشوید، این وب سایت‌ها فقط به درد محتوای استاتیک می‌خورند. و به جز یک سرویس رایگان دیتابیس که آن هم محدودیت دارد برای سایر وب سایت‌ها امکان استفاده از دیتابیس ندارید. بر اساس آزمایش ما دیتابیس‌های ساده‌تر همراه خود پروژه‌های دات نتی هم در این فضا کار نمی‌کنند.

البته این سرویس رایگان به درد آزمایش و کارهای developer ها در معرفی پروژه‌های اپن سورس (به خصوص کتابخانه‌های جاوا اسکریپت) و سایت‌های پشتیبانی هاست‌ اصلی می‌خورد. البته باید توجه داشت در سرویس رایگان امکان استفاده از دامنه اختصاصی نیست و دامنه وب سایت شما یک زیردامنه از سایت اصلی Azure Web Site است.

قیمت خدمات آژور چقدر است؟

مهمترین تفاوت آژور با هاست‌های سنتی در همین مبحث قیمت خدمات است. در آژور شما به اندازه‌ آشی که می‌خورید پول پرداخت می‌کنید. در واقع اگر وب سایت شما منابع کمی از سرور را اشغال می‌کند به اندازه همان CPU‌ و RAM استفاده شده پول پرداخت می‌کنید. لذا مبلغ دقیقی برای خدمات آژور متصور نیست و باید بر حسب نیاز خود از بین سرویس‌ها انتخاب کنید.

آژور یک مدل پرداخت pay as you go دارد که بر اساس حجم خدمات استفاده شده صورتحساب شما را محاسبه و از حساب شما کسر می‌کند. ماشین حساب آژور به شما کمک می‌کند بر حسب نیاز خود، هزینه خدمات را محاسبه کنید.

من یک سایت روی هاست اشتراکی فلان شرکت دارم، آیا می‌توانم سایتم را به آژور انتقال بدهم؟

مشکلی در انتقال نیست، اما سوال اینجاست که آیا این انتقال با صرفه است؟ صرفنظر از پلن رایگان که ۱۰ وب سایت ارائه می‌دهد، اگر بخواهید از دامنه اختصاصی استفاده کنید باید از پلن shared استفاده کنید که حدود ۱۰ دلار در ماه قیمت دارد. 

روی پلن shared می‌توانید تا ۱۰۰ وب سایت داشته باشید، همه این وب سایت‌ها خدمات برنامه‌نویسی که اشاره شد را خواهند داشت. همچنین می‌توانید ۶ instance از وب سایت خود روی سرورهای دیگر را داشته باشید. هر instance در واقع یک کپی از کد شما بر روی سرور دیگری است که محدودیت RAM و CPU اش با سرور اصلی شما تداخل ندارد. اگر بیشتر از ۶ instance نیاز دارید به صرفه است که به پلن Standard مهاجرت کنید.

آیا استفاده از خدمات VM به صرفه‌تر نیست؟

البته خدمات VM در آژور خیلی خوبند اما باید به این نکته توجه کنید که پس از گرفتن VM تنظیمات آن با شماست. مثلاً در VM های ویندوزی باید IIS را تنظیم کنید یا سیستم عامل را خودتان به روز نگه دارید و ...

با قیمت حدود ۱۵ دلار می‌توانید VM در مقیاس خیلی کوچک بگیرید که ۷۶۸ مگابایت RAM دارد و احتمالاً برای سرورهایی نظیر سرور MySql‌ یا سرور لینوکسی مناسب است.

چه موقع از Web Site و چه موقع از VM استفاده کنیم؟

این کاملاً سلیقه‌ای است. اگر از Web Site ها استفاده کنید با یک محیط مدیریت شده طرف هستید. لازم نیست نگران تنظیمات باشید و به راحتی می‌توانید از امکانات متنوع برای استقرار برنامه تحت وب خود استفاده کنید. اما در VM‌ها همه تنظیمات و به روز نگه داشتن سیستم عامل و ... به عهده شماست.

نکته مهم اینکه در پلن Standard و پلن‌ Premium که به تازگی معرفی شده، سایت‌های شما روی VM هستند اما این VM مدیریت شده است. یعنی لازم نیست نگران نرم‌افزارهای مخرب یا به روز نگه داشتن VM باشید. از طرفی می‌توانید به راحتی سایت‌های خود را که روی یک VM‌ میزبانی می‌شوند مدیریت کنید. اگر تعداد وب‌سایت‌های شما زیاد است به جای استفاده از پلن Shared که برای ۸ سایت باید حدود ۷۷ دلار در ماه بپردازید استفاده از یک VM در پلن Standard (در سطوح مختلف منابع CPU و RAM بر حسب نیاز) با حدود ۷۴ دلار در ماه به صرفه تر است.

چطور منابع مورد استفاده سایت را بیشتر کنیم؟

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

آیا آژور برای ایران هم در دسترس است؟

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

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

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