Ведущий разработчик
0,0
рейтинг
1 марта 2014 в 16:45

Разработка → AngularJS vs IML из песочницы

image

disclaimer: сравнение не подразумевает поднятие “холивара”, а делает обзор задач, решаемых одним инструментом в сравнении с другим. Я не являюсь знатоком всех тонкостей angularJs, но прочитав 10 статьей обзора этого инструмента, привожу альтернативный пример решения тех же самых задач на IML.


Что будем сравнивать ?


  • Controller
  • Inheritance
    примечание: отсутствует в IML
  • Accessing server
  • Push data
  • Submit form
  • Template
  • Promises
    примечание: отсутствует в IML и может быть полезным только при работе со сторонними сервисами, а так решается все с помощью продуманного выбора данных для возврата.


Я выбрал те возможности, которые имеют смысл, потому что в рамках asp.net mvc пользу в перемененных, константах, а также в поддержке локализации не вижу.
примечание: далее часто будет учитываться то, что разработка проходит в рамках asp.net mvc

Как будем сравнивать ?


Методика очень простая, привожу листинг AngularJS ( View и Js ) и IML ( только View ) варианта, далее аргументирую чем же IML лучше. Я буду выделять только плюсы, но буду рад увидеть и отрицательные стороны IML в комментариях, поэтому все свои замечания можно высказать.

Controller

Angular JS View

<div ng-controller="angularController">
<button ng-click="sayHello()">Say</button>
</div>

Angular JS

app.controller('angualrController', function ($scope) {
  $scope.sayHello = function(){
      alert('Hello')  
  } 
});

IML

@(Html.When(JqueryBind.Click)
      .Do()
      .Direct()
      .OnSuccess(dsl => dsl.Utilities.Window.Alert("Hello"))
      .AsHtmlAttributes()
      .ToButton("Say"))


Чем лучше :

  • Поведение и разметка вместе
    примечание: многим данный момент покажется спорным, из-за того, что логика усложняет работу верстальщикам страниц, но в рамках asp.net mvc, C# код во View ( cshtml ) неотъемлемая часть и поэтому те преимущества, которые можно получить полностью перекрываю довольно таки абстрактную модель разработки логики отдельно от разметки.
  • Поддержка Initilesence
    примечание: атрибуты AngularJs не являются стандартом html, поэтому подсветки синтаксиса или авто-дополнения не будет, а IML это C# библиотека.
  • События представляют флаги
    примечание: упрощает группировку, когда надо продублировать действия для другого события When(JqueryBind.Click | JqueryBind.Focus)
  • Управлением поведением события ( Prevent Default, Stop Propagation)
    примечание: AngularJS позволяет управлять этим в рамках метода контроллера, но IML включает это как часть общей схемы


Accessing Server

Серверный код

public ActionResult Get(GetProductByCodeQuery query)
{
 List  vms = dispatcher.Query(query);
 return IncJson(vms); // for AngularJs need use Json with AllowGet
}

примечание: серверная часть одинакова, как для AngularJS, так и для IML
Angular Html

<div ng-conroller="productController">
 @Html.TextBoxFor(r => r.Code)
 <label>{{model.Name}}</label>
 <button>Get name</button>
</div>

Angular Js

kitchen.controller('productController', function ($scope, $http) {
  $scope.get = function(){
    $http.get({
                url:'product/get',
                params:{Code:$('[Name="Code"]').val()}
              })
          .success(function(data) { 
              $scope.Name = data.Name
           });
 }
});

IML

@{ var labelId = Guid.NewGuid().ToString(); }
@Html.TextBoxFor(r=>r.Code)
@(Html.When(JqueryBind.Click)
  .Do()
  .AjaxGet(Url.Action("Product","Get",new {
                       Code = Html.Selector().Name(r=>r.Code)
                      })
  .OnSuccess(dsl => dsl.WithId(labelId).Core().Insert.For(r=>r.Name).Text())
  .AsHtmlAttributes()
  .ToButton("Get name"))

примечание: при построение url, можно использовать в качестве Routes не только анонимный объект, но и типизированный вариант Url.Action(“Product”,”Get”,new GetProductQuery() { Code = Html.Selector().Name(r=>r.Code) })

Чем лучше:

  • Типизация на всех этапах
    • Url – адрес в AngularJs строится без серверной части, что не позволяет учитывать route и отсутствие возможности перейти ( переименовать ) в Action из кода.
      примечание: по скольку руководство по AngularJs рекомендует выносить JavaScript код во внешний файл, то по этой причине не получится использовать серверные переменные в рамках js кода.
    • Query – AngularJs не связан с серверной моделью и не позволяет получить схему модели, что как и в случае с Url не позволяет использовать инструменты для переименования и go to declaration
      примечание: в случаи с IML, если мы переименуем поле Name или Code в GetProductQuery, то изменения отразятся и на клиентскую часть, но для AngularJs придется дополнительно заменить {{model.Name}} и $(‘[Name=«code»]‘) на новые значения.
    • Selector – для указания параметров запроса в рамках IML можно использовать мощный инструмент для получения значений из Dom ( hash, cookies, js variable and etc ) объектов

  • MVD

В Incoding Framework можно обойтись без написания дополнительных Controller и Action если в качестве url применить MVD
Url.Dispatcher().Query(new GetProductQuery() {Code = Html.Selector().Name(r=>r.Code)}).AsJson()


Push data

Серверный код

public ActionResult Add(AddCommand input)
{ 
dispatcher.Push(input);
return IncJson(); // for AngularJS need use Json()
}

примечание: серверная часть одинакова, как для AngularJS, так и для IML

Angular View

<div ng-controller="productController">
  @Html.TextBoxFor(r => r.Name) 
  @Html.CheckboxFor(r => r.IsGood)
  <button ng-click="add"> Add </button>
</div>

Angular JS

kitchen.controller('productController', function ($scope, $http) {
 $scope.add = function(){ 
   $http({
       url: 'product/Add',
       method: "POST",
       data: { 
             Name : $('[name="Name"]').val(),
             IsGood : $('name="IsGood"]').is(':checked')
             }
         })
      .success(function(data) { alert('success') });
});

IML

@Html.TextBoxFor(r=>r.Name)
@Html.CheckboxFor(r=>r.IsGood)
@(Html.When(JqueryBind.Click)
      .Do()
      .AjaxPost(Url.Action("Product","Add",new {
                                                 Name = Html.Selector().Name(r=>r.Name),
                                                 IsGood = Html.Selector().Name(r=>r.IsGood)
                                               }))
      .OnSuccess(dsl => dsl.Utilities.Window.Alert("Success"))
      .AsHtmlAttributes()
      .ToButton("Add"))


Чем лучше:

  • MVD
    как и в предыдущем примере когда мы делали Query, в Incoding Framework можно выполнять push без написания Action
    Url.Disaptcher().Push( new {
                                       Name = Html.Selector().Name(r=>r.Name),
                                       IsGood = Html.Selector().Name(r=>r.IsGood)
                                })
    

  • Selector абстрагирует от способа получения значения
    примечание: на примере видно, что для получения значения из checkbox нужно использовать is(‘:checked’), но в IML этот момент не требуется указывать


Submit Form

Angular View

<div ng-controller="productController"> 
  <form name="AddForm">
    @Html.TextBoxFor(r => r.Name)
    @Html.CheckboxFor(r => r.IsGood) 
    <input type="submit" value="save"  ng-submit="submit" />
  </form>
</div>

Angular JS

controller('productController', function ($scope, $http) {
 $scope.submit = function(){ 
   $http({
       url: 'product/Add',
       method: "POST",
       data: angular.toJson($scope.addForm)
        }).success(function(data) { alert('success') });
});

IML

@using(Html.When(JqueryBind.Submit)
           .DoWithPreventDefault()
           .Submit()
           .OnSuccess(dsl => dsl.Utilities.Window.Alert("Success"))
           .AsHtmlAttributes()
           .ToBeginForm(Url.Action("Product","Add")))
 {
    @Html.TextBoxFor(r=>r.Name)
    @Html.CheckboxFor(r=>r.IsGood)
    <input type="submit" value="add">
 }

Чем лучше:

  • Отправка формы в одну строку
    примечание: angularJs работает с формой точно так же, как и с обычным ajax запросом, что требует указания параметров Url, Type, Data

Template


Серверный код

public ActionResult Fetch()
{
   var vms = new List()
     {
      new PersonVm(){ Last= "Vasy", First = "Smith", Middle = "Junior"},
      new PersonVm(){ Last= "Vlad", First = "Smith", Middle = "Mr"},
     };
  return IncJson(vms); // for angular need use Json with AllowGet
}

примечание: серверная часть одинакова, как для AngularJS, так и для IML
Angular Template

<script id="person.html" type="text/ng-template">
{{person.last}}, {{person.first}} {{person.middle}}
</script>

Angular View

<div ng-controller="productAddForm">
  <div ng-repear="person in persons" ng-template="person.html">   
  </div>
</div>

Angular JS

app.controller('personController', function ($scope,$http) {
   $scope.refresh= function(){
      $http.get('person/fetch', function(data){ 
                          $scope.Persons= data 
      });
   } 
});

IML Template

@{
    var tmplId = Guid.NewGuid().ToString();
    using (var template = Html.Incoding().Template(tmplId))
    {
      using (var each = template.ForEach())
      {  @each.For(r=>r.First),@each.For(r=>r.Middle),@each.For(r=>r.Last) }
    }
}

IML View

@(Html.When(JqueryBind.InitIncoding)
 .Do()
 .AjaxGet(Url.Action("Personal","Fetch"))
 .OnSuccess(dsl => dsl.Self().Core().Insert.WithTemplate(tmplId.ToId()).Html())
 .AsHtmlAttributes()
 .ToDiv())

Чем лучше :


  • Опять типизация
    примечание: Incoding template требует больше кода для реализации типизированного синтаксиса, но это окупается при дальнейшей поддержке
  • Один template для одного или многих объектов
  • Замена template engine
  • Поиск template по Selector, что имеет больше возможностей ( ajax, cookies and etc )
  • Cache
    AngularJs имеет механизм работы с Cache, но с очень важными отличиями
    • Требует настройки для каждого template отдельно
      myApp.run(function($templateCache) {
        $templateCache.put('templateId.html', 'This is the content of the template');
      });
      

    • Не хранится между сессиями
      примечание: Incoding Framework сохраняет пре-компилированную версию template в local storage, что позволяет после первого прохода пользователем все последующие обращения к template брать сразу из local storage.



В чем же общие преимущество:

  • Да, да и снова это типизация – это достигается за счет использования C# на всех этапах ( template, client scenario and etc ) разработки
  • Один язык для backend и frontend — разработчик знающий C# может без проблем освоить IML и далее вызывать свои Command и Query на клиенте


Вывод: AngularJs разворачивает mvc архитектуру на клиенте, что с одной стороны позволяет структурировать код, но так же добавляет дополнительные проблемы в поддержке. Разработчик asp.net mvc имеет серверную реализацию mvc, где применяя более мощные и подходящие языки, можно избежать усложнения.
Влад Копачинский @vkopachinsky
карма
5,0
рейтинг 0,0
Ведущий разработчик
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (68)

  • +2
    IML, MVD — что это?
    Очередная реклама какого-то велосипеда.
  • 0
    IML, MVD — что это?

    IMLincoding meta language
    MVD — Model View Dispatcher, позволяет вызывать Command и Query без написания Controller на asp.net mvc.
  • +4
    Я так и не понял что вы пытаетесь сравнить. Некую кодогенерирующую штуку с полноценным js фреймворком…
    У меня сложилось впечатление, что вы просто не умеете готовить Angular, ну или с# вам не даёт, или что там…
    <div ng-controller="productController"> 
      <form name="AddForm">
        @Html.TextBoxFor(r => r.Name)
        @Html.CheckboxFor(r => r.IsGood) 
        <input type="submit" value="save"  ng-submit="submit" />
      </form>
    </div>
    

    зачем этот код? напишите нормальную html страницу и используйте c# как rest.

    И вывод у вас не полный и сравнивать эти вещи не корректно. Но если очень хочется, то напишите хотя бы TO DO List приложение на IML, а потом сравните.
    • +1
      >У меня сложилось впечатление, что вы просто не умеете готовить Angular, ну или с# вам не даёт, или что там…

      Автор сам дает ответ на этот вопрос: «Я не являюсь знатоком всех тонкостей angularJs, но прочитав 10 статьей обзора этого инструмента».

      Т.е. он не только не умеет его готовить, он его в «руках не держал».
  • +2
    Простите, но код ваш на ng ужасен, особенно когда вы пытаетесь криво за счет jquery передать параметры в ajax запрос. По поводу интелисенс — есть webstorm, netbeans 8, vs+resharper(plugin for ng). Еще в древние времена когда вместо ASP.MVC были ASP web forms мне казалось это ужасно. Все что вы пытались так высветить в высшем свете на ng решается очень просто и лаконично красиво. Может по поводу шаблнов не очень, но никто не мешает использовать в директиве рендеринг в элемент за счет того же ReactJS, когда у вас очень много данных на странице…
    • –5
      Простите, но код ваш на ng ужасен

      Я не работаю с AngularJs, но взял в качестве примера то, что нашел первым в google lostechies.com/gabrielschenker/2013/12/17/angularjspart-5-pushing-data-to-the-server/

      • +6
        Вы не работаете с AngularJs, но позволяете себе сравнивать его с чем-то, и, вдобавок, критиковать, основываясь только на поверхностном прочтении непонятных материалов. Зачем?
        • –7
          Вы не работаете с AngularJs

          Мы решаем задачи другим способом и хотели об этом рассказать.

          но позволяете себе сравнивать его

          Я должен спросить разрешение?

          вдобавок, критиковать, основываясь только на поверхностном прочтении непонятных материалов.

          Что именно я критиковал? Материал был взят из очень известного блога и автор тоже популярный.

          Зачем?

          Затем, что бы на примере продемонстрировать возможности нашего инструмента, разве это было не очевидно?
          • 0
            Исчерпывающе.
      • +3
        А зачем вы вообще тогда решили написать эту статью, если не разбираетесь, простите?
        • –5
          А зачем вы вообще тогда решили написать эту статью, если не разбираетесь, простите?

          А с чего Вы взяли, что я не разбираюсь? Или мне надо сделать десятки проектов на нем ( AngularJs ), что бы потом можно было его сравнивать?
          • +2
            Да, вы не разбираетесь и об этом вам выше сказал xGromMx. Ваш код и подход ужасны.
            • –1
              Ваш код и подход ужасны

              Изучал по статьям из блога ( lostechies.com/gabrielschenker/2014/02/26/angular-js-blog-series-table-of-content/ ). Я виноват, что google выдает этот курс, как самый популярный? Я привел рабочие примеры кода на AngularjS, причем некоторые прямо из официальной документации.

  • –1
    Некую кодогенерирующую штуку с полноценным js фреймворком…

    кодогенерации нету!

    Но если очень хочется, то напишите хотя бы TO DO List приложение на IM

    А как Вам browsio, он открыт на open source.
    Так же на open source Inc Music Store ( аналог asp.net mvc music store )

    По поводу «хотя бы», на Incoding Framework выполнены сотни проектов, например
    • 0
      И все что вы показали ужасно что по перформенс что по подходу организации UI =)
      • 0
        что по перформенс

        Все проекты расположены на тестовом сервере. Вот пример на live сервере www.pazar3.mk/mk/Listing/Classified/Ads

        что по подходу организации UI =)

        Это не имеет ни какого отношения к IML или framework.
    • +1
      @(Html.When(JqueryBind.InitIncoding)
       .Do()
       .AjaxGet(Url.Action("Personal","Fetch"))
       .OnSuccess(dsl => dsl.Self().Core().Insert.WithTemplate(tmplId.ToId()).Html())
       .AsHtmlAttributes()
       .ToDiv())
      

      Простите, а это по-вашему не генерация HTML/JS из того инструмента?

      Мне всё равно на browserio и любой другой продукт. Если вы делаете сравнение, оно должно быть адекватным. Вы должны всесторонне изучить оба инструмента, написать хотя бы приблизительно похожие по функционалу приложения, чтобы потом сравнить реализации идентичной функциональности и архитектуру в целом.
      • –1
        Простите, а это по-вашему не генерация HTML/JS из того инструмента?

        Нет. Вот, статья про то, как работает IML. Там целый раздел про «Ни кто ни чего не генерирует»

        Мне всё равно на browserio и любой другой продукт

        Я Вам не продукт показываю, а демонстрирую возможности IML.

        написать хотя бы приблизительно похожие по функционалу приложения

        То есть, вы считаете TO DO LIST это очень сложное приложение?
        • 0
          Объективная мысль:
          Вопрос не в сложности, вопрос в том, что сравнивать нужно не маленькие кусочки кода, а сколько-нибудь рабочие корректно реализованные на обоих технологиях приложения.

          Субъективная мысль:
          Хорошо, пусть это не кодогенератор, хотя вопрос очень спорный (статью как работает ИМЛ читал, вопросы к пунктам 2, 5, 6, 7), это всё равно некая ненужная прослойка между сервером и клиентом.
          • –2
            Вопрос не в сложности, вопрос в том, что сравнивать нужно не маленькие кусочки кода, а сколько-нибудь рабочие корректно реализованные на обоих технологиях приложения.

            Из всех статьей где сравнивают один инструмент с другим, то выделяют общий функционал и проводится аналогия. Согласитесь, объем текста, для реализации такой статьи будет большим.

            Хорошо, пусть это не кодогенератор, хотя вопрос очень спорный (статью как работает ИМЛ читал, вопросы к пунктам 2, 5, 6, 7), это всё равно некая ненужная прослойка между сервером и клиентом.

            2. — это нормальная практика для asp.net mvc ( TextBox, DropDown и т.д. )
            5, 6, 7 — разве Angular не запускает свой parser?

            Могу сказать один веский аргумент в сторону IML, кол-во JavaScript файлов уменьшается до 0 ( кроме файла framework 12Kb и jquery, а так же сторонних плагинов и template enginte, которые так же надо подключать для Angular ), потому что не надо реализовывать логику, надо просто её описать ( декларативность имеет свои плюсы )
            • +1
              п. 2 — нельзя же смотреть на мир только со своей колокольни. С точки зрения стандартизации веба (HTML/JS/CSS) это не совсем то, чего добиваются спецификации.
              п. 5, 6, 7 — в Ангуляре парсер для обработки и создания шаблона(читайте как view в c#), причём написан на Js со всеми вытекающими. А как с отладкой кода в IML?

              Из всех статьей где сравнивают один инструмент с другим, то выделяют общий функционал и проводится аналогия. Согласитесь, объем текста, для реализации такой статьи будет большим.

              Сайт, на который я дал ссылку, проводит отличное сравнение технологий . Конечно, статья с таким подходом будет больше, но она будет ценнее для любого специалиста.

              Я рассматриваю ситуацию со следующей точки зрения:
              Завтра ко мне приходит новый проект и говорят, выбирай технологию — IML или Angular. И так как я не шалтай-болтай, мне нужно доказать, почему я её выбрал, и не просто потому, что Js я знаю лучше чем IML. Провести анализ технологии, коммьюнити, поддержки и многих прочих факторов. Я открываю эту статью, чтобы она помогла мне провести анализ с технической точки зрения, трачу пару часов на то, чтобы вникнуть в неё и понимаю, что последние пару часов я провёл зря.
              • 0
                Сайт, на который я дал ссылку, проводит отличное сравнение технологий
                .
                там 176 человек делает коммиты, а я занимаюсь в свободное от работы время, тем что продвигаю инструмент, так что пока могу только так. Если будет интерес, могу реализовать To Do MVC.

                Провести анализ технологии, коммьюнити, поддержки и многих прочих факторов.

                Конечно сравнивать Angular ( миллионы пользователей, десятки разработчиков и т.д. ) и нас крайне сложно, но с другой стороны если ничего не делать, то так все и останется.

              • 0
                п. 2 — нельзя же смотреть на мир только со своей колокольни. С точки зрения стандартизации веба (HTML/JS/CSS) это не совсем то, чего добиваются спецификации.

                Разрабатываю я приложения на asp.net mvc и для заказчиков, а не для стандартов веба.

                п. 5, 6, 7 — в Ангуляре парсер для обработки и создания шаблона(читайте как view в c#), причём написан на Js со всеми вытекающими.

                И в IML написан на JS

                А как с отладкой кода в IML?

                Отладчик в разработке. Вопрос на самом деле каверзный, но мы работает над этим. В рамках компании, хватает того, что разработчик framework все о нем знает и всегда поможет, если что не работает, но конечно планируем покрыть этот момент.

                Я понимаю, что серьёзная фирма сразу не решится использовать наш инструмент для сложного проекта, но кто то может решит попробовать в мелких.

                P.S. Мы выполняем проекты любой сложности на incoding framework.
                • 0
                  Я верю, что вы делаете качественные приложения для своих заказчиков.

                  Но вы опубликовали статью в блогах C#, Js, .Net, а не в блоге «Я пиарюсь», отсюда и получаете обратную связь на статью. У меня ведь нет задачи завалить вас, но у меня чувство того, что AngularJs выставлен в плохом свете.

                  там 176 человек делает коммиты, а я занимаюсь в свободное от работы время, тем что продвигаю инструмент, так что пока могу только так. Если будет интерес, могу реализовать To Do MVC.

                  вам решать делать или нет, но мне кажется, что это вывело бы статью на более качественный уровень
                  • 0
                    Но вы опубликовали статью в блогах C#, Js, .Net, а не в блоге «Я пиарюсь», отсюда и получаете обратную связь на статью.

                    Я думал в какой лучше, но склонился к этим, может это не правильно. Я на хабре не давно.

                    У меня ведь нет задачи завалить вас, но у меня чувство того, что AngularJs выставлен в плохом свете.

                    Я указал те моменты, в которых я считаю, что мы лучше, если есть контр-аргументы то давайте обсудим. Пока в обсуждениях чаще идет упор на «КАК ОН ПОСМЕЛ УПОМИНАТЬ AngularJs».

                    вам решать делать или нет, но мне кажется, что это вывело бы статью на более качественный уровень

                    Ок, спасибо Вам за совет.
                  • 0
                    вам решать делать или нет, но мне кажется, что это вывело бы статью на более качественный уровень

                    решил сделать, подробности тут
                    • 0
                      Вы молодец. Теперь, когда у вас есть эталонные реализации TODO на обоих технологиях, этот пост мог бы быть написан намного объективнее. Жаль что так вышло не с самого начала.
  • 0
    Меня дико удивлют попытки перенести фронтенд и фронтенд логику в бекенд. Это что типа такая мода теперь? JS очень гибкий и мощный, имеет огромное колличество модулей, фреймворков и прочего. Не нравится JS есть надмножество типа Typescript или же такие диалекты как Coffeescript и ему подобные. C# прекрасный язык, но для бекенда, всему своя задача.
    • 0
      Меня дико удивлют попытки перенести фронтенд и фронтенд логику в бекенд.

      Конечно, куда лучше 2 программиста, один пишет Command на C#, другой вызывает её с JavaScript

      Не нравится JS есть надмножество типа Typescript или же такие диалекты как Coffeescript и ему подобные

      IML это декларативный язык, он в отличии от тех, что Вы привели выше имеет функциональную часть, которую можно быстро оценить на видео уделив 10 минут
  • –1
    Мне кажется, вы сравниваете совершенно разные вещи и при этом код для AngularJS не слишком хорош (уже расписали выше). По поводу кода IML не могу ничего сказать.

    Конечно, куда лучше 2 программиста, один пишет Command на C#, другой вызывает её с JavaScript

    С финансовой точки зрения — хуже, конечно. Но для качества кода вариант с двумя программистами куда лучше, ведь каждый из них пользуется инструментом для своей части разработки и не трогает чужого.
    • +1
      Но для качества кода вариант с двумя программистами куда лучше, ведь каждый из них пользуется инструментом для своей части разработки и не трогает чужого.

      Когда работают 2 человека, то появляются проблемы:
      1. Кто то, работает быстрее.
      2. Не понятно, кто ошибся, потому что каждый считает, что его код рабочий.

      Разве плохо, когда один отвечает за проделанную работу?
      • –1
        Зависит от размера проекта.
        Я не буду спорить на эту тему. В обоих случаях есть и плюсы и минусы. В сети достаточно материала :)
  • 0
    Сравниваете язык шаблонов с ванильным HTML, пусть и в связке с Angular?
    Знаете ле вы, что с Angular можно использовать и языки шаблонов, например Jade?
    • 0
      Знаете ле вы, что с Angular можно использовать и языки шаблонов, например Jade?

      IML поддерживает любой движок для template ( подробней ) и позволяет их менять. Cache работает на основе local storage, что позволяет хранить его между сессиями. А вот может ли AngularJs For(r=>r.PropertyFromMyServerModel)?
  • +2
    Во блин флейма развели, это же дотнет, у них всегда свои велосипеды через попу реализованы и они их считают самыми лучшими. Вы что думаете, тут будет какое-то исключение?
    • 0
      Какая разница, на чем server-side?
      • +1
        Да никакой, причем тут серверная сторона?
        Тут же просто очередной велосипед с квадратными колесами.
  • 0
    Устал, что из статьи в статью носится jquery стиль работы с моделями, хотя там мощная работа с ресурсами, с кешированием и прочими свистелками.
    docs.angularjs.org/tutorial/step_11
    docs.angularjs.org/api/ngResource/service/$resource

    Статья интересная в разрезе про IML, примеры с angural поясняют магию, но никак не являются аналогами и сравнивать их не стоит, они слишком разные. Молотком и микроскопом можно вбить гвоздь, но каждый из них лучше применять в своей сфере.
    • 0
      Статья интересная в разрезе про IML, примеры с angural поясняют магию

      Это основная цель, я же не руководство по AngularJs делаю.

      сравнивать их не стоит, они слишком разные

      Angular получает Json через Ajax, что бы потом переделать его в Html и IML делает тоже самое. Это мое мнение, но если взять любое веб приложение, то задачи одинаковые.

      Молотком и микроскопом можно вбить гвоздь, но каждый из них лучше применять в своей сфере.

      Мне кажется любой framework направлен на увлечение продуктивности труда ( только после его изучения ), так что сфера у нас одна.

      • 0
        json это далеко не ресурс, который поддерживает rest $save, $delete и т.д., умеет работать с кешем, знает о DI, легко тестируется, легко расширяется.

        точно так же вы привели пример с шаблонами, где явно в цикле прогоняете данные и вставляете в шаблон, а в ангуляре же используется биндинг и данные сами обновляются при изменени во всех шаблонах. Разница огромная. То что вы будете делать руками, ангуляр сделает сам и вам не нужно следить за целостностью и синхронизацией шаблонов.
  • +2
    Ужасно не профессиональное сравнение, убогий материал, убогие примеры на обоих языках.
    Не профессионализм автора на лицо!
    Если вы специались по IML, велкам, расскажите нам о IML. Не надо придумывать абстрактных сравнений которые кроме вашего низкого профессионального уровня ничего не могут подтверить. Ибо для сравненияя надо гратно определить критерии, а тут это сделано в корне не правильно.
    Для сравнения надо было написать тогда уж приложение взятое из реальной жизни, причем на ангуляре должен писать специалист по ангулару а на IML специалист по IML.
    Имхо также сравнение этих инструменитов не корректно по сути, ибо js разработчики врятли найдут хоть 1 аргумент за то чтобы начать писать на IML, также имхо специалисту по C# может оказаться проще работать на IML.
    Другое дело сравнивать Backbone и Angular — две равные технологии где разработчики легко могут сменить одну на другую.

  • 0
    Если вы специались по IML, велкам, расскажите нам о IML.

    Уже рассказывал habrahabr.ru/post/209734/

    на IML специалист по IML.

    Я автор Incoding framework

    Не надо придумывать абстрактных сравнений которые кроме вашего низкого профессионального уровня ничего не могут подтверить

    Я оцениваю профессионализм программиста по качеству кода (вот мой github.com/IncodingSoftware/Incoding-Framework ) а Вы как?

    Идея поста, показать как можно решать с помощью IML, тоже самое что и на AnularJs ( все примеры я взял из документации и блога на lostechies.com, пока в комментариях не привели альтернативного варианта написания. )

    P.S. Понятно, что статья провалилась, но я постараюсь исправится реализовав To Do MVC на IML и описав этот процесс в следующих статьях.

    • 0
      > Я автор Incoding framework
      Это все объясняет, но AngularJS это детище Google.

      >(вот мой github.com/IncodingSoftware/Incoding-Framework ) а Вы как?

      Клевый фреймворк из 20 коммитов, 10 из которых «Update (Create) README.md»,
    • 0
      Я оцениваю профессионализм программиста по качеству кода (вот мой github.com/IncodingSoftware/Incoding-Framework ) а Вы как?

      И мы тоже.

      Тесты вида «When_default_dispatcher_push_throw_with_mute_event_by_attributes» очень много говорят о профессионализме программиста.
      • 0
        А чем плохо название?
        • 0
          Тем, что из него не понятно, что тестируется. Ни базовые условия (Arrange), ни действие (Act), ни проверка (Assert).
          • 0
            Это BDD (почитайте про MSpec), если Вам не понятно, то это ничего не значит.
            • 0
              Во-первых, это не BDD, а поведенческое тестирование. Во-вторых, если человеку, который читает тест, не понятно, что тест делает, это плохо говорит о тестах (потому что одна из задач тестов — фиксация и демонстрация поведения).

              Для MSpec читаемость достигается правильным именованием It (should_<описание проверки>; should_be_push — это не понятно, что такое (возможно, вы просто плохо знаете английский), и читаемым контекстом (зафиксированным в названии теста, When_<контекст>),

              Из чтения теста
              [Subject("Authentication")]
              public class When_authenticating_an_admin_user
              {
                  Establish context = () => {Subject = new SecurityService(foo, bar);};
              
                  Because of = () => Token = Subject.Authenticate("username", "password");
              
                  It should_indicate_the_users_role = () => Token.Role.ShouldEqual(Roles.Admin);
                  It should_have_a_unique_session_id = () => Token.SessionId.ShouldNotBeNull();
              }
              

              понятно, что при аутентификации администратора у него должна быть роль и id сессии.

              При чтении теста
                  [Subject(typeof(MessageBase<>))]
                  public class When_message_base_push
                  {
                      #region Fake classes
              
                      class FakeCommand : CommandBase
                      {
                          public override void Execute()
                          {
                              throw new NotImplementedException();
                          }
                      }
              
                      class FakeMessage : MessageBase<string>
                      {
                          public override void Execute()
                          {
                              Dispatcher.Push(new FakeCommand(), setting => setting.Delay = delaySetting);
                          }
                      }
              
                      #endregion
              
                      #region Establish value
              
                      static FakeMessage message;
              
                      static Mock<IDispatcher> dispatcher;
              
                      static MessageDelaySetting delaySetting;
              
                      #endregion
              
                      Establish establish = () =>
                                                {
                                                    delaySetting = Pleasure.Generator.Invent<MessageDelaySetting>();
                                                    var unitOfWork = Pleasure.MockAsObject<IUnitOfWork>(mock => mock.Setup(r => r.IsOpen()).Returns(true));
                                                    message = Pleasure.Generator.Invent<FakeMessage>(dsl => dsl.GenerateTo(r => r.Setting, inventFactoryDsl => inventFactoryDsl.Tuning(r => r.UnitOfWork, unitOfWork)));
                                                    dispatcher = Pleasure.Mock<IDispatcher>();
                                                    IoCFactory.Instance.StubTryResolve(dispatcher.Object);
                                                };
              
                      Because of = () => message.Execute();
              
                      It should_be_push = () => dispatcher.ShouldBePush(new FakeCommand(), new MessageExecuteSetting
                                                                                               {
                                                                                                       UnitOfWork = message.Setting.UnitOfWork, 
                                                                                                       Delay = delaySetting
                                                                                               });
                  }
              

              не понятно, что имеется в виду.
              • 0
                Во-первых, это не BDD, а поведенческое тестирование. Во-вторых, если человеку, который читает тест, не понятно, что тест делает, это плохо говорит о тестах (потому что одна из задач тестов — фиксация и демонстрация поведения).

                Вы бы в качестве своего примера, показали тест на калькулятор, там ещё меньше кода будет.

                Для MSpec читаемость достигается правильным именованием It (should_<описание проверки>; should_be_push — это не понятно, что такое (возможно, вы просто плохо знаете английский), и читаемым контекстом (зафиксированным в названии теста, When_<контекст>),


                Should be push — проверяет то, что будет выполнен Push, что не так то?

                Потом стоит отметить, что мы говорим о тестах функций ядра, к примеру давайте посмотрим на тест бизнес кода

                [
                    public class When_add_genre
                    {
                        static MockMessage<AddGenreCommand, object> mock;
                
                        Establish establish = () =>
                                                  {
                                                      var command = Pleasure.Generator.Invent<AddGenreCommand>();
                
                                                      mockCommand = MockCommand<AddGenreCommand>
                                                              .When(command);
                                                  };
                
                        Because of = () => mock.Original.Execute();
                
                       It should_be_save = () => mock.ShouldBeSave<Genre>(genre => genre.ShouldEqualWeak(mock.Original));
                    }
                


                У Вас есть какие то проекты на github?
                • 0
                  Вы бы в качестве своего примера, показали тест на калькулятор, там ещё меньше кода будет.

                  Тест должен быть читаемым. Если в нем много кода — значит, выносите код в именованные операции. У Мезароса все описано.

                  Should be push — проверяет то, что будет выполнен Push, что не так то?

                  Все не так. Проверка на то, что выполнен push — это BePushed, WasPushed или PushCalled.

                  У Вас есть какие то проекты на github?

                  "Сперва добейся"?
                  • 0
                    Тест должен быть читаемым. Если в нем много кода — значит, выносите код в именованные операции. У Мезароса все описано.

                    Код теста должен быть полный (убрали половину строк) и равный по сложности. Покажите Ваш вариант для теста AddGenreCommand с учетом всех Ваших слоев и сравним тогда объективно.

                    «Сперва добейся»?

                    Ну Вы же критикуете, так давайте уравняем шансы, что бы я тоже составил о Вас мнение.
                    • 0
                      Код теста должен быть полный (убрали половину строк) и равный по сложности. Покажите Ваш вариант для теста AddGenreCommand с учетом всех Ваших слоев и сравним тогда объективно.

                      А при чем тут слои? А пример читаемого кода — вот (только надо отметить, что (а) и ваш вариант был вполне читаемым и (б) я не правлю ваши архитектурные проблемы):

                      public class When_add_genre
                          {
                              static Fixture Fixture;
                              static Genre ExpectedGenre;
                              static Mock<IRepository<Genre>> Repository;
                              static AddGenreCommand Target;
                      
                              Establish context = () =>
                                                        {
                                                            Fixture = new Fixture();
                                                            ExpectedGenre = Fixture.Create<Genre>();
                                                            Repository = new Mock<IRepository<Genre>>();
                                                            Target = AddGenreCommand(Repository.Object){Genre = ExpectedGenre};
                                                        };
                      
                              Because of = () => Target.Execute();
                      
                              It should_be_added_to_repository = () => Repository.Verify(r => r.Add(It.Is<Genre>(actual => actual.ShouldBeEquivalent(ExpectedGenre))));
                          }
                      


                      Ну Вы же критикуете, так давайте уравняем шансы, что бы я тоже составил о Вас мнение.

                      Обсуждать надо приводимые аргументы, а не личность оппонента.
                      • 0
                        Обсуждать надо приводимые аргументы, а не личность оппонента.

                        Ни в коем случаи я не перехожу на личности, я хочу мнение о коде.

                        When_add_genre

                        Давайте пройдем по Вашему варианту:
                        1. Смысл в обобщенном Repository
                        примечание: уже проходили такое, в сто раз меньше кода при использовании обобщенных МЕТОДОВ Repository
                        2.Ваш вариант AddGenreCommand принимает Genre, что крайне избыточно, потому что где то есть код, который заполняет AddGenreCommand, но зачем? Чем плох вариант составить Genre из полей Command (удобно для asp.net mvc binding)?
                        3. В it Вы проверяете, что Ваш Genre, который Вы создали сохранился, Вам не кажется что смысла в этом нет? То есть тест покрывает просто факт вызова метода Add?
                        примечание: мой пример, сравнивает поля AddGenreCommand с новым Genre, тем самым проверяем правильность преобразования
                        4. Разве у Вас есть много Command, где НЕ используется IRepository? Зачем копировать одни и те же строки.
                        5. Fixture = new Fixture(); зачем усложнять, если можно обращается сразу к Fixture.Instance?
                        6. Где Unit of Work? Скорей всего он во внешнем слое, который в этом тесте не показан, что говорит о наличии ещё одного теста, но зачем не понятно.

                        P.S. Вы показали мне пример, того как я писал раньше, потому что мы так же использовали слои, но теперь я пишу в разы быстрее из-за меньшего количества кода нужного для решения задачи.

                        • 0
                          Ни в коем случаи я не перехожу на личности, я хочу мнение о коде.

                          Чтобы обсуждать мои аргументы касательно вашего кода, не нужно знать, какой код пишу я.

                          Смысл в обобщенном Repository

                          Вопрос не имеет отношения к тесту.

                          Ваш вариант AddGenreCommand принимает Genre, что крайне избыточно, потому что где то есть код, который заполняет AddGenreCommand, но зачем?

                          Это один из вариантов. Можно написать иначе, просто тогда инициализация теста будет многословнее.

                          В it Вы проверяете, что Ваш Genre, который Вы создали сохранился, Вам не кажется что смысла в этом нет?

                          Нет, не кажется. Это и есть задача теста.

                          То есть тест покрывает просто факт вызова метода Add?

                          Нет, он покрывает факт вызова метода Add с правильными параметрами.

                          Разве у Вас есть много Command, где НЕ используется IRepository?

                          Понятия не имею. Я показываю тест конкретной команды.

                          Fixture = new Fixture(); зачем усложнять, если можно обращается сразу к Fixture.Instance?/blockquote>
                          У Fixture нет Instance.

                          Где Unit of Work?

                          Это не важно. Операция Add репозитория атомарна.
                          • 0
                            Вопрос не имеет отношения к тесту.

                            Задам его отдельно, почему Repository<Genre>.Add вместо Repository.Add<Genre>(). На своем опыте скажу, что писать IGenreRepository, крайне утомительно, когда у Вас сотни entity.

                            Нет, не кажется. Это и есть задача теста.

                            Но она же бредовая, Вы плодите кучу кода, зачем усложнять, почему нельзя просто сделать Post COmmand, которую превратить в Genre (может в несколько entity).

                            Это не важно. Операция Add репозитория атомарна.

                            Атомарно должна быть задача Add Genre, а не метод из Вашего ядра инфраструктуру, его то зачем проверять, каждый раз? Идея проверить правильность формирования Genre, а не то что Вы не забыли вызвать Add (хотя и это будет проверенно)

                            Нет, он покрывает факт вызова метода Add с правильными параметрами.

                            Вы создали объект и передали его в Command и потом проверили, что это объект сохранился, а Выше тест будет проверять, что Вы передали в Controller поля, который превратились в Genre, разве не проще зараз все проверить?

                            Это один из вариантов. Можно написать иначе, просто тогда инициализация теста будет многословнее.

                            А разве плохо увидеть всю картину сразу?
                            • 0
                              Задам его отдельно, почему Repository<Genre>.Add вместо Repository.Add<Genre>()

                              Не Repository, а IRepository, класс при этом может быть и один. Удобно это тогда, когда разные аггрегаты лежат в разных хранилищах.

                              Но она же бредовая, Вы плодите кучу кода, зачем усложнять, почему нельзя просто сделать Post COmmand, которую превратить в Genre (может в несколько entity).

                              Не понимаю, о чем вы говорите. Задача теста в том, чтобы протестировать, что команда корректно выполняется (мы сейчас не рассматриваем тот факт, что делать это дожен обработчик). Выполнение команды — это создание соответствующего аггрегата в репозитории. Это и тестируется.

                              Идея проверить правильность формирования Genre, а не то что Вы не забыли вызвать Add (хотя и это будет проверенно)

                              Проверяется и то, и другое.

                              тест будет проверять, что Вы передали в Controller поля, который превратились в Genre, разве не проще зараз все проверить?

                              Тестирование контроллера, равно как и сквозное тестирование — это отдельная задача. Здесь тест покрывает конкретную команду (кстати, именно поэтому поведенческое тестирование там лишнее, обычный юнит-тест справился бы ничем не хуже).

                              А разве плохо увидеть всю картину сразу?

                              Если в ней слишком много деталей — да плохо. Человек не способен все осознать за один прием.
                              • 0
                                Если в ней слишком много деталей — да плохо.

                                Приведу пример AddStoreCommand
                                public override void Execute()
                                        {
                                     var store = Repository.GetById<Store>(StoreId);
                                     var product = new Product
                                                              {
                                                      Name = Name, 
                                                      Description = Description, 
                                                      Price = Price, 
                                                      Asin = Asin, 
                                                      Author = Author, 
                                                      Image = Image.ReturnOrDefault(r => new HttpMemoryPostedFile(r).ContentAsBytes, new byte[0])
                                                              };
                                      store.AddProduct(product);
                                        }
                                

                                Если делать, как Вы, то код создания Product выносится в слой выше, тем самым скрываете, то как строится объект.

                                Человек не способен все осознать за один прием

                                Конечно, куда проще бегать по слоям, что бы понять, как это работает.

                                P.S. Ваш подход построен на рутином написании слоев и тестов к ним, хотя все это можно агрегировать в одну Command.
                                На вопрос о том, что делать когда код разрастётся, то для этих целей есть Composite, который может разделять сложные задачи на части и потом в рамках ОДНОЙ транзакции выполнять.
                                dispatcher.Push(composite =>
                                                        {
                                                            composite.Quote(step1);
                                                            composite.Quote(step2);
                                                            composite.Quote(step3);
                                                        });
                                


                                Вы хотели аргументов, тогда посчитайте кол-во действий и классов нужных для реализации Add Genre, к примеру у меня:
                                1. Add Genre Command Class ( и тест )
                                2. Url.Disaptcher().Push(new AddGenreCommand())
                                И все…

                                • 0
                                  Если делать, как Вы, то код создания Product выносится в слой выше, тем самым скрываете, то как строится объект.

                                  Я уже говорил, что это только один из возможных вариантов. Можно ведь и модел-биндером собирать сущность сразу, тогда этого кода не будет вообще.

                                  Конечно, куда проще бегать по слоям, что бы понять, как это работает.

                                  А зачем? При правильной декомпозиции задачи вся существенная информация находится в одном месте.

                                  Вы хотели аргументов, тогда посчитайте кол-во действий и классов нужных для реализации Add Genre, к примеру у меня:
                                  1. Add Genre Command Class ( и тест )
                                  2. Url.Disaptcher().Push(new AddGenreCommand())
                                  И все…

                                  Эти аргументы не имеют никакого отношения к читаемости теста, который мы обсуждаем в этой ветке.
                      • 0
                        Мои wrapper, позволяют описывать тест с помощью языка.
                        Скажем у Вас в коде Command/Query есть Repository.GetById(ArtistId), то в тесте mockQuery.StubGetById(command.ArtistId, artist).

                        P.S. Имея единый стандарт для кода, можно построить под него и тесты (я к примеру использую R# live template для формирования разметки под тест)

                        • 0
                          Это означает, что ваш код содержит очень много повторяющихся паттернов, на которые вы пишете повторяющиеся тесты. Избыточно.
                          • 0
                            очень много повторяющихся паттернов, на которые вы пишете повторяющиеся тесты

                            Вы редко GetById используйте?
                            Вы редко Save используйте?
                            Вы редко любой другой метод из Repository?

                            Весь код очень похож, поэтому мы укоротили конструкции обернув их в Wrapper, а так же выделили общую инфраструктуру в incoding framework и теперь используем для всех проектов. В рамках Incoding Framework вся уникальная бизнес логика сконцентрирована в Command/Query, а Repository и Disaptcher это периферия, которая одинакова для всех

                            • 0
                              Вы редко Save используйте?

                              Я его редко тестирую. Я не вижу смысла писать враппер для конструкции, которая тестируется один раз.
                              • 0
                                Я его редко тестирую.

                                Вы редко используете Save? или Вы тестируете не все?
                                • 0
                                  Поскольку это типовая операция над аггрегатом, она тестируется один раз, и проверяется, что аггрегат корректно ходит в/из хранилище. А при тестировании бизнеса проверяется, что корректно изменяется состояние аггрегата.
                                  • 0
                                    Хорошо, вот пример
                                    Repository.Save(new Genre(){ Name = Name, IsNew = StartDt > DateTime.Now }) 
                                    

                                    Вы будете его тестировать?
                                    • 0
                                      Это пример чего? Конкретной строчки кода? Тестируется обычно сценарий.

                                      А вообще, зависит от конкретной реализации. Обычно выделяется одна точка, где перехватывается обращение в БД, и из нее достается аггрегат, состояние которого нужно проверять. Не видя структуры вашего репозитория, я не могу сказать, какая это точка.
              • 0
                Кстати о Вашем примере, а зачем вы убрали, то как настраивается foo, bar и объявления переменной Subject?
                Мой код примера Вы выложили полностью же.

Только зарегистрированные пользователи могут оставлять комментарии. Войдите, пожалуйста.