مطالب
Functional Programming یا برنامه نویسی تابعی - قسمت دوم – مثال‌ها
در قسمت قبلی این مقاله، با مفاهیم تئوری برنامه نویسی تابعی آشنا شدیم. در این مطلب قصد دارم بیشتر وارد کد نویسی شویم و الگوها و ایده‌های پیاده سازی برنامه نویسی تابعی را در #C مورد بررسی قرار دهیم.


Immutable Types

هنگام ایجاد یک Type جدید باید سعی کنیم دیتای داخلی Type را تا حد ممکن Immutable کنیم. حتی اگر نیاز داریم یک شیء را برگردانیم، بهتر است که یک instance جدید را برگردانیم، نه اینکه همان شیء موجود را تغییر دهیم. نتیحه این کار نهایتا به شفافیت بیشتر و Thread-Safe بودن منجر خواهد شد.
مثال:
public class Rectangle
{
    public int Length { get; set; }
    public int Height { get; set; }

    public void Grow(int length, int height)
    {
        Length += length;
        Height += height;
    }
}

Rectangle r = new Rectangle();
r.Length = 5;
r.Height = 10;
r.Grow(10, 10);// r.Length is 15, r.Height is 20, same instance of r
در این مثال، Property های کلاس، از بیرون قابل Set شدن می‌باشند و کسی که این کلاس را فراخوانی میکند، هیچ ایده‌ای را درباره‌ی مقادیر قابل قبول آن‌ها ندارد. بعد از تغییر بهتر است وظیفه‌ی ایجاد آبجکت خروجی به عهده تابع باشد، تا از شرایط ناخواسته جلوگیری شود:
// After
public class ImmutableRectangle
{
    int Length { get; }
    int Height { get; }

    public ImmutableRectangle(int length, int height)
    {
        Length = length;
        Height = height;
    }

    public ImmutableRectangle Grow(int length, int height) =>
          new ImmutableRectangle(Length + length, Height + height);
}

ImmutableRectangle r = new ImmutableRectangle(5, 10);
r = r.Grow(10, 10);// r.Length is 15, r.Height is 20, is a new instance of r
با این تغییر در ساختار کد، کسی که یک شیء از کلاس ImmutableRectangle را ایجاد میکند، باید مقادیر را وارد کند و مقادیر Property ها به صورت فقط خواندنی از بیرون کلاس در دسترس هستند. همچنین در متد Grow، یک شیء جدید از کلاس برگردانده می‌شود که هیچ ارتباطی با کلاس فعلی ندارد.


استفاده از Expression بجای Statement

یکی از موارد با اهمیت در سبک کد نویسی تابعی را در مثال زیر ببینید:
public static void Main()
{
    Console.WriteLine(GetSalutation(DateTime.Now.Hour));
}

// imparitive, mutates state to produce a result
/*public static string GetSalutation(int hour)
{
    string salutation; // placeholder value

    if (hour < 12)
        salutation = "Good Morning";
    else
        salutation = "Good Afternoon";

    return salutation; // return mutated variable
}*/

public static string GetSalutation(int hour) => hour < 12 ? "Good Morning" : "Good Afternoon";
به خط‌های کامنت شده دقت کنید؛ می‌بینیم که یک متغیر، تعریف شده که نگه دارنده‌ای برای خروجی خواهد بود. در واقع به اصطلاح آن را mutate می‌کند؛ در صورتیکه نیازی به آن نیست. ما می‌توانیم این کد را به صورت یک عبارت (Expression) در آوریم که خوانایی بیشتری دارد و کوتاه‌تر است.


استفاده از High-Order Function ها برای ایجاد کارایی بیشتر

در قسمت قبلی درباره توابع HOF صحبت کردیم. به طور خلاصه توابعی که یک تابع را به عنوان ورودی میگیرند و یک تابع را به عنوان خروجی برمی‌گردانند. به مثال زیر توجه کنید:
public static int Count<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
    int count = 0;

    foreach (TSource element in source)
    {
        checked
        {
            if (predicate(element))
            {
                count++;
            }
        }
    }

    return count;
}
این قطعه کد، مربوط به متد Count کتابخانه‌ی Linq می‌باشد. در واقع این متد تعدادی از چیز‌ها را تحت شرایط خاصی می‌شمارد. ما دو راهکار داریم، برای هر شرایط خاص، پیاده سازی نحوه‌ی شمردن را انجام دهیم و یا یک تابع بنویسیم که شرط شمردن را به عنوان ورودی دریافت کند و تعدادی را برگرداند.


ترکیب توابع

ترکیب توابع به عمل پیوند دادن چند تابع ساده، برای ایجاد توابعی پیچیده گفته می‌شود. دقیقا مانند عملی که در ریاضیات انجام می‌شود. خروجی هر تابع به عنوان ورودی تابع بعدی مورد استفاده قرار میگیرد و در آخر ما خروجی آخرین فراخوانی را به عنوان نتیجه دریافت میکنیم. ما میتوانیم در #C به روش برنامه نویسی تابعی، توابع را با یکدیگر ترکیب کنیم. به مثال زیر توجه کنید:
public static class Extensions
{
    public static Func<T, TReturn2> Compose<T, TReturn1, TReturn2>(this Func<TReturn1, TReturn2> func1, Func<T, TReturn1> func2)
    {
        return x => func1(func2(x));
    }
}

public class Program
{
    public static void Main(string[] args)
    {
        Func<int, int> square = (x) => x * x;
        Func<int, int> negate = x => x * -1;
        Func<int, string> toString = s => s.ToString();
        Func<int, string> squareNegateThenToString = toString.Compose(negate).Compose(square);
        Console.WriteLine(squareNegateThenToString(2));
    }
}
در مثال بالا ما سه تابع جدا داریم که میخواهیم نتیجه‌ی آن‌ها را به صورت پشت سر هم داشته باشیم. ما میتوانستیم هر کدام از این توابع را به صورت تو در تو بنویسیم؛ ولی خوانایی آن به شدت کاهش خواهد یافت. بنابراین ما از یک Extension Method استفاده کردیم.


Chaining / Pipe-Lining و اکستنشن‌ها

یکی از روش‌های مهم در سبک برنامه نویسی تابعی، فراخوانی متد‌ها به صورت زنجیره‌ای و پاس دادن خروجی یک متد به متد بعدی، به عنوان ورودی است. به عنوان مثال کلاس String Builder یک مثال خوب از این نوع پیاده سازی است. کلاس StringBuilder از پترن Fluent Builder استفاده می‌کند. ما می‌توانیم با اکستنشن متد هم به همین نتیجه برسیم. نکته مهم در مورد کلاس StringBuilder این است که این کلاس، شیء string را mutate نمیکند؛ به این معنا که هر متد، تغییری در object ورودی نمی‌دهد و یک خروجی جدید را بر می‌گرداند.
string str = new StringBuilder()
  .Append("Hello ")
  .Append("World ")
  .ToString()
  .TrimEnd()
  .ToUpper();
در این مثال  ما کلاس StringBuilder را توسط یک اکستنشن متد توسعه داده‌ایم:
public static class Extensions
{
    public static StringBuilder AppendWhen(this StringBuilder sb, string value, bool predicate) => predicate ? sb.Append(value) : sb;
}

public class Program
{
    public static void Main(string[] args)
    {
        // Extends the StringBuilder class to accept a predicate
        string htmlButton = new StringBuilder().Append("<button").AppendWhen(" disabled", false).Append(">Click me</button>").ToString();
    }
}


نوع‌های اضافی درست نکنید ، به جای آن از کلمه‌ی کلیدی yield استفاده کنید!

گاهی ما نیاز داریم لیستی از آیتم‌ها را به عنوان خروجی یک متد برگردانیم. اولین انتخاب معمولا ایجاد یک شیء از جنس List یا به طور کلی‌تر Collection و سپس استفاده از آن به عنوان نوع خروجی است:
public static void Main()
{
    int[] a = { 1, 2, 3, 4, 5 };

    foreach (int n in GreaterThan(a, 3))
    {
        Console.WriteLine(n);
    }
}


/*public static IEnumerable<int> GreaterThan(int[] arr, int gt)
{
    List<int> temp = new List<int>();
    foreach (int n in arr)
    {
        if (n > gt) temp.Add(n);
    }
    return temp;
}*/

public static IEnumerable<int> GreaterThan(int[] arr, int gt)
{
    foreach (int n in arr)
    {
        if (n > gt) yield return n;
    }
}
همانطور که مشاهده میکنید در مثال اول، ما از یک لیست موقت استفاده کرد‌ه‌ایم تا آیتم‌ها را نگه دارد. اما میتوانیم از این مورد با استفاده از کلمه کلیدی yield اجتناب کنیم. این الگوی iterate بر روی آبجکت‌ها در برنامه نویسی تابعی، خیلی به چشم میخورد.


برنامه نویسی declarative به جای imperative با استفاده از Linq

در قسمت قبلی به طور کلی درباره برنامه نویسی Imperative صحبت کردیم. در مثال زیر یک نمونه از تبدیل یک متد که با استایل Imperative نوشته شده به declarative را می‌بینید. شما میتوانید ببینید که چقدر کوتاه‌تر و خواناتر شده:
List<int> collection = new List<int> { 1, 2, 3, 4, 5 };

// Imparative style of programming is verbose
List<int> results = new List<int>();

foreach(var num in collection)
{
  if (num % 2 != 0) results.Add(num);
}

// Declarative is terse and beautiful
var results = collection.Where(num => num % 2 != 0);


Immutable Collection

در مورد اهمیت immutable قبلا صحبت کردیم؛ Immutable Collection ها، کالکشن‌هایی هستند که به جز زمانیکه ایجاد می‌شنود، اعضای آن‌ها نمی‌توانند تغییر کنند. زمانیکه یک آیتم به آن اضافه یا کم شود، یک لیست جدید، برگردانده خواهد شد. شما می‌توانید انواع این کالکشن‌ها را در این لینک ببینید.
به نظر میرسد که ایجاد یک کالکشن جدید میتواند سربار اضافی بر روی استفاده از حافظه داشته باشد، اما همیشه الزاما به این صورت نیست. به طور مثال اگر شما f(x)=y را داشته باشید، مقادیر x و y به احتمال زیاد یکسان هستند. در این صورت متغیر x و y، حافظه را به صورت مشترک استفاده می‌کنند. به این دلیل که هیچ کدام از آن‌ها Mutable نیستند. اگر به دنبال جزییات بیشتری هستید این مقاله به صورت خیلی جزیی‌تر در مورد نحوه پیاده سازی این نوع کالکشن‌ها صحبت میکند. اریک لپرت یک سری مقاله در مورد Immutable ها در #C دارد که میتوانید آن هار در اینجا پیدا کنید.

 

Thread-Safe Collections

اگر ما در حال نوشتن یک برنامه‌ی Concurrent / async باشیم، یکی از مشکلاتی که ممکن است گریبانگیر ما شود، race condition است. این حالت زمانی اتفاق می‌افتد که دو ترد به صورت همزمان تلاش میکنند از یک resource استفاده کنند و یا آن را تغییر دهند. برای حل این مشکل میتوانیم آبجکت‌هایی را که با آن‌ها سر و کار داریم، به صورت immutable تعریف کنیم. از دات نت فریمورک نسخه 4 به بعد  Concurrent Collection‌ها معرفی شدند. برخی از نوع‌های کاربردی آن‌ها را در لیست پایین می‌بینیم:
Collection
توضیحات
 ConcurrentDictionary 
  پیاده سازی thread safe از دیکشنری key-value 
 ConcurrentQueue 
  پیاده سازی thread safe از صف (اولین ورودی ، اولین خروجی) 
 ConcurrentStack 
  پیاده سازی thread safe از پشته (آخرین ورودی ، اولین خروجی) 
 ConcurrentBag 
  پیاده سازی thread safe از لیست نامرتب 

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

در این قسمت از مقاله سعی شد با روش‌های خیلی ساده، با مفاهیم اولیه برنامه نویسی تابعی درگیر شویم. در ادامه مثال‌های بیشتری از الگوهایی که میتوانند به ما کمک کنند، خواهیم داشت.   
اشتراک‌ها
۱۸ ویژگی گیت‌لب متن باز می‌شود

I spent some time reviewing GitLab features and determined that, by our Buyer-Based Open Core model, eighteen features that appear in seven different stages of the DevOps lifecycle ought to be open source

۱۸ ویژگی گیت‌لب متن باز می‌شود
اشتراک‌ها
مصاحبه‌ای با Linus Torvalds در مورد استفاده از Rust در هسته‌ی لینوکس

Linus Torvalds talks AI, Rust adoption, and why the Linux kernel is 'the only thing that matters'

Switching to a more modern topic, the introduction of the Rust language into Linux, Torvalds is disappointed that its adoption isn't going faster. "I was expecting updates to be faster, but part of the problem is that old-time kernel developers are used to C and don't know Rust. They're not exactly excited about having to learn a new language that is, in some respects, very different. So there's been some pushback on Rust."

مصاحبه‌ای با Linus Torvalds در مورد استفاده از Rust در هسته‌ی لینوکس
مطالب
Lazy Loading در AngularJS
وقتی پروژه انگیولاری‌تان کمی گسترش پیدا کند، تعداد زیادی فایل شامل کنترلرها، سرویس‌ها، دایرکتیوها و ... خواهید داشت. واضح است که همه این اجزا همراه با هم مورد نیاز نیستند و برای افزایش سرعت بارگذاری سایت و صرفه جویی در مصرف پهنای باند بهتر است هرکدام از آن‌ها را در هنگام نیاز بارگذاری کنیم. این یعنی همان lazy loading خودمان!
در AngularJS امکانی برای lazy loading فایل‌ها پیشبینی نشده است، پس باید از ابزارهای دیگری که این امکان را فراهم می‌کنند استفاده کرد. من در ادامه از Script.js برای این کار استفاده خواهم کرد، ولی شما می‌توانید از هر کتابخانه دیگری استفاده کنید.
اما مسئله دیگری که پیش از lazy loading  فایل‌ها باید تکلیفش را معلوم کنیم، این است که چطور می‌توانیم اجزایی را به ماژولی که قبلا راه‌اندازی (bootstrap) شده اضافه کنیم. اگر بخواهیم برای مثال کنترلری را در یک فایل مجزا تعریف کنیم، باید آن را به شکلی در ماژول برنامه‌مان ثبت کنیم. فرض کنید این کار را به این ترتیب انجام دهیم: 
angular.module('app').controller('SomeLazyController', function($scope)
{
    $scope.key = '...';
});
در این صورت اگر این کنترلر را در قسمتی از برنامه به صورت ng-controller='SomeLazyController' استفاده کنیم با این خطا مواجه خواهیم شد:
Error: Argument ‘SomeLazyController’ is not a function, got undefined
برای این کار (افزودن اجزایی به ماژولی که قبلا راه اندازی شده) می‌توانیم بجای استفاده از API‌های ماژول، از provider های AngularJS استفاده کنیم. به این ترتیب برای ثبت یک کنترلر باید از  controllerProvider$، برای ثبت یک directive از  compileProvider$، برای ثبت فیلترها از filterProvider$ و برای ثبت سایر اجزا در ماژول از provide$ استفاده کنیم:
// Registering a controller after app bootstrap
$controllerProvider.register('SomeLazyController', function($scope)
{
   $scope.key = '...'; 
});
 
// Registering a directive after app bootstrap
$compileProvider.directive('SomeLazyDirective', function()
{
    return {
        restrict: 'A',
        templateUrl: 'templates/some-lazy-directive.html'
    }
})
 
// etc
اما نکته‌ای که درباره providerها وجود دارد این است که آن‌ها تنها در روال config یک ماژول در دسترس هستند. بنا بر این برای دسترسی به آن‌ها پس از اجرای این روال، ارجاعی به آنها را باید نگهداری کنیم: 
(function () {
    app = angular.module("app", []);

    app.config([
        '$controllerProvider',
        '$compileProvider',
        '$filterProvider',
        '$provide',

    function ($controllerProvider, $compileProvider, $filterProvider, $provide) {
        //برای رجیستر کردن غیر همروند اجزای انگیولاری در آینده
        app.lazy =
        {
            controller: $controllerProvider.register,
            directive: $compileProvider.directive,
            filter: $filterProvider.register,
            factory: $provide.factory,
            service: $provide.service
        };
    }]);
})();
اکنون SomeLazyController  را به این ترتیب می‌توانیم ثبت کنیم: 
angular.module('app').lazy.controller('SomeLazyController', function($scope)
{
    $scope.key = '...';
});
نکته دیگر این است که کجا باید lazy loadign را انجام دهیم. به نظر می‌رسد مناسب‌ترین محل برای انجام این کار خصوصیت resolve مسیریابی است. در  این مطلب و این مطلب resolve در route$ و UI-Router معرفی شده است:
$stateProvider
            .state('state1', {
                url: '/state1',
                template: '<div>{{st1Ctrl.msg}}</div>',
                controller: 'state1Controller as st1Ctrl',
                resolve: {
                    fileDeps: ['$q', '$rootScope', function ($q, $rootScope) {
                        var deferred = $q.defer();
                        var deps = [
                            'app/messageService.js',
                            'app/state1Controller.js'];
                        $script(deps, function () {
                            $rootScope.$apply(function () {
                                deferred.resolve();
                            });
                        });
                        return deferred.promise;
                    }]
                }
            })
            .state('state2', {
                url: '/state2',
                template: '<div>{{st2Ctrl.msg}}</div>',
                controller: 'state2Controller as st2Ctrl',
                resolve: {
                    fileDeps: ['$q', '$rootScope', function ($q, $rootScope) {
                        var deferred = $q.defer();
                        var deps = [
                            'app/messageService.js',
                            'app/state2Controller.js'];
                        $script(deps, function () {
                            $rootScope.$apply(function () {
                                deferred.resolve();
                            });
                        });
                        return deferred.promise;
                    }]
                }
            });
    }]);
کنترلر state1Controller که در فایلی با همین نام پیاده‌سازی شده است تنها در مسیر state1/ مورد نیاز است، و state2Controller تنها در مسیر state2/ لازم است بارگذاری شود. هردوی این کنترلرها به messageService وابستگی دارند که در messageService.js پیاده سازی شده است (همانطور که در این مطلب   اشاره شده می‌توانیم یک حالت انتزاعی به عنوان پدر دو حالت موجود تعریف کرده و وابستگی مشترک را به آن منتقل کنیم).
 برای بارگذاری فایل‌های مورد نیاز در ابتدای کار و راه اندازی اولیه برنامه هم می‌توان به این ترتیب عمل کرد:  
<script type="text/javascript">
        // ----Script.js----
        !function (a, b, c) { function t(a, c) { var e = b.createElement("script"), f = j; e.onload = e.onerror = e[o] = function () { e[m] && !/^c|loade/.test(e[m]) || f || (e.onload = e[o] = null, f = 1, c()) }, e.async = 1, e.src = a, d.insertBefore(e, d.firstChild) } function q(a, b) { p(a, function (a) { return !b(a) }) } var d = b.getElementsByTagName("head")[0], e = {}, f = {}, g = {}, h = {}, i = "string", j = !1, k = "push", l = "DOMContentLoaded", m = "readyState", n = "addEventListener", o = "onreadystatechange", p = function (a, b) { for (var c = 0, d = a.length; c < d; ++c) if (!b(a[c])) return j; return 1 }; !b[m] && b[n] && (b[n](l, function r() { b.removeEventListener(l, r, j), b[m] = "complete" }, j), b[m] = "loading"); var s = function (a, b, d) { function o() { if (!--m) { e[l] = 1, j && j(); for (var a in g) p(a.split("|"), n) && !q(g[a], n) && (g[a] = []) } } function n(a) { return a.call ? a() : e[a] } a = a[k] ? a : [a]; var i = b && b.call, j = i ? b : d, l = i ? a.join("") : b, m = a.length; c(function () { q(a, function (a) { h[a] ? (l && (f[l] = 1), o()) : (h[a] = 1, l && (f[l] = 1), t(s.path ? s.path + a + ".js" : a, o)) }) }, 0); return s }; s.get = t, s.ready = function (a, b, c) { a = a[k] ? a : [a]; var d = []; !q(a, function (a) { e[a] || d[k](a) }) && p(a, function (a) { return e[a] }) ? b() : !function (a) { g[a] = g[a] || [], g[a][k](b), c && c(d) }(a.join("|")); return s }; var u = a.$script; s.noConflict = function () { a.$script = u; return this }, typeof module != "undefined" && module.exports ? module.exports = s : a.$script = s }(this, document, setTimeout)

        $script('Scripts/angular.js', function () {
            $script('Scripts/angular-ui-router.js', function () {
                $script('app/app.js', function () {
                    angular.bootstrap(document, ['app']);
                });
            });
        });
    </script>
توجه داشته باشید که لازم نیست بارگذاری فایل‌ها حتما یکی پس از دیگری باشد. ترتیب بارگذاری فایل‌ها تنها در آن‌هایی که وابستگی به هم دارند باید رعایت شود. همچنین، می‌توانید همه فایل‌های مورد نیاز در این مرحله را Bundle کنید. 
از اینجا می‌توانید پروژه بسیار ساده‌ای که در آن lazy loading پیاده شده است را دانلود کرده و مطالب توضیح داده شده را مشاهده کنید. 
نظرات مطالب
ساختار پروژه های Angular
ضمن تشکر فراوان از جناب آقای پاکدل عزیز، در این مقاله به خوبی درباره lazy loading در angularjs بحث شده. نکته مهم اینکه حتما پروژه‌ی قابل اجرایی که در انتهای مقاله لینک شده را ملاحظه کنید. نکاتی در این پروژه هست از جمله اینکه برای دسترسی به providerها برای lazy loading آنها به این ترتیب به app افزوده شده اند:
app.config([
        '$stateProvider',
        '$urlRouterProvider',
        '$locationProvider',
        '$controllerProvider',
        '$compileProvider',
        '$filterProvider',
        '$provide',


        function ($stateProvider, $urlRouterProvider, $locationProvider, $controllerProvider, $compileProvider, $filterProvider, $provide) {
            //برای رجیستر کردن غیر همروند اجزای انگیولاری در آینده
            app.lazy =
            {
                controller: $controllerProvider.register,
                directive:  $compileProvider.directive,
                filter:     $filterProvider.register,
                factory:    $provide.factory,
                service:    $provide.service
            };
.
.
.
])
(البته این کد از پروژه خودمان است و بعضی وابستگی‌های دیگر هم تزریق شده‌اند).
استفاده از app.lazy باعث سهولت بیشتر در استفاده و خواناتر شدن کد می‌شود. در ادامه به این ترتیب می‌توانید از app.lazy استفاده کنید:
angular.module('app').lazy.controller('myController',
        ['$scope',  function($scope){
...
}]);
به این ترتیب کد نوشته شده به دلیل نام گذاری ارجاع controllerProvider  با  controller  به حالت عادی شبیه است، و از طرفی lazy پیش از آن به فهم ماجرا کمک خواهد کرد.
این نقطه شروع یکی از پروژه‌های ماست که به عنوان نمونه بد نیست ملاحظه کنید:
<script type="text/javascript">
// --- Scriptjs ---
!function (a, b, c) { function t(a, c) { var e = b.createElement("script"), f = j; e.onload = e.onerror = e[o] = function () { e[m] && !/^c|loade/.test(e[m]) || f || (e.onload = e[o] = null, f = 1, c()) }, e.async = 1, e.src = a, d.insertBefore(e, d.firstChild) } function q(a, b) { p(a, function (a) { return !b(a) }) } var d = b.getElementsByTagName("head")[0], e = {}, f = {}, g = {}, h = {}, i = "string", j = !1, k = "push", l = "DOMContentLoaded", m = "readyState", n = "addEventListener", o = "onreadystatechange", p = function (a, b) { for (var c = 0, d = a.length; c < d; ++c) if (!b(a[c])) return j; return 1 }; !b[m] && b[n] && (b[n](l, function r() { b.removeEventListener(l, r, j), b[m] = "complete" }, j), b[m] = "loading"); var s = function (a, b, d) { function o() { if (!--m) { e[l] = 1, j && j(); for (var a in g) p(a.split("|"), n) && !q(g[a], n) && (g[a] = []) } } function n(a) { return a.call ? a() : e[a] } a = a[k] ? a : [a]; var i = b && b.call, j = i ? b : d, l = i ? a.join("") : b, m = a.length; c(function () { q(a, function (a) { h[a] ? (l && (f[l] = 1), o()) : (h[a] = 1, l && (f[l] = 1), t(s.path ? s.path + a + ".js" : a, o)) }) }, 0); return s }; s.get = t, s.ready = function (a, b, c) { a = a[k] ? a : [a]; var d = []; !q(a, function (a) { e[a] || d[k](a) }) && p(a, function (a) { return e[a] }) ? b() : !function (a) { g[a] = g[a] || [], g[a][k](b), c && c(d) }(a.join("|")); return s }; var u = a.$script; s.noConflict = function () { a.$script = u; return this }, typeof module != "undefined" && module.exports ? module.exports = s : a.$script = s }(this, document, setTimeout)

$script(['/Scripts/Lib/jquery/jquery-1.10.2.min.js'], function () {
    $script(['/Scripts/Lib/angular/angular.js'], function () {
        $script(['/Scripts/Lib/angular/angular-ui-router.min.js',
                    '/Scripts/Lib/angular/angular-resource.min.js',
                    '/Scripts/Lib/angular/angular-cache.min.js',
                    '/Scripts/Lib/angular/angular-sanitize.min.js',
                    '/Scripts/Lib/angular/angular-animate.min.js',
                    '/Scripts/Lib/angular/angular-cookie.min.js',
                    '/APP/Common/directives.js'
                ], function () {
                    $script('/app/app.js', function () {
                        angular.bootstrap(document, ['app']);
                    });
                });
            })
        });
</script>

این تگ script در صفحه شروع پروژه آمده است.
کد minify شده scriptjs در ابتدا قرار دارد، پس از آن فایل‌های js مورد نیاز با رعایت وابستگی‌های احتمالی به ترتیب بارگذاری شده‌اند.
این قسمت resolve یکی از بخش‌های مسیریابی است: 
resolve: {
                        fileDeps: ['$q', '$rootScope', function ($q, $rootScope) {
                            var deferred = $q.defer();
                            var deps = ['/app/HotStories/dataContextService.js',
                                        '/app/HotStories/hotStController.js'];
                            $script(deps, function () {
                                $rootScope.$apply(function () {
                                    deferred.resolve();
                                });
                            });

                            return deferred.promise;
                        }]
                    }
این نحوه تعریف سرویسی که فایل آن در وابستگی‌ها آمده و قرار است lazy load شود:
angular.module('app').lazy.service('dataContextService',
        ['$rootScope', '$resource', '$angularCacheFactory', '$q', function($rootScope, $resource, $cacheFactory, $q){
...
}]);
و این هم نحوه تعریف کنترلری که فایل آن در وابستگی‌ها آمده و قرار است lazy load شود: 
angular.module('app').lazy.controller('hotStController',
        ['$scope', 'ipCookie', 'dataContextService', function($scope, ipCookie, dataContextService){
...
}]);


اشتراک‌ها
قسمت اول از بررسی #Immutable Objects in C

در ادامه موضوعات C# in a nutshell اینسری نگاهی انداختیم به اینکه چطور میتونیم یه آبجکت غیر قابل تغییر بسازیم و اینکه رکورد‌ها چه کارایی برای ما دارند. 

قسمت اول از بررسی #Immutable Objects in C