?

Log in

No account? Create an account
   Journal    Friends    Archive    Profile    Memories
 

Программерский дыбр - morfizm


Mar. 28th, 2013 11:20 pm Программерский дыбр

boto это Python-овская библиотека для AWS (Amazon Cloud).
В ней большинство вещей продублировано в двух стилях:
  item = db.get_item();
  item.save();

и
  item = db.get_item();
  db.save_item(item);


Ну и первый вариант это лишь иллюстрирующий пример принципа, там бывают огромные матрёшки: достаёшь сундук из дуба, зайца из сундука, утку из зайца, яйцо из утки, иглу из яйца, а там, глядишь, уже и смерть на конце иглы...
А можно сразу сказать: ec2.дай_мне_смерть_на_конце_иглы(дуб, сундук, заяц, утка, яйцо), и передать весь необходимый контекст в параметрах.

Мне такой вариант в разы больше нравится, потому что нужно всего один раз посмотреть исходник документацию API, чтобы понять, что там происходит. Первый вариант становится вообще невыносим, когда промежуточные объекты передаются куда-то в библиотеки из соседних пакетов, и там уже просто нет всего контекста, чтобы вызвать одним куском, или понять, из чего оно было собрано.

Интересно, кому вообще пришло в голову делать первым вариантом? Это какой-нибудь новый модный дизайн паттерн? OOP-intoxication? Зачем?!?

Current Mood: contemplativecontemplative

14 comments - Leave a commentPrevious Entry Share Next Entry

Comments:

From:ermouth
Date:March 29th, 2013 08:00 pm (UTC)
(Link)
Если учесть, что jQuery есть чуть не на половине сайтов инета, это не то слово какой модный паттерн. Это позволяет легко создавать видимость расширения функционала экземпляра и использовать потом эти расширения. Это такой декоратор, но похитрей. Типичный пример – применение плагинов в jQuery.

var $input = jQuery("#someDomInput").datepicker({ /*some params*/ }).css({color:"#fff"}).show();
$input.animate({color:"#000"}).datepicker("setDate","2013-05-10");


Первый вызов datepicker здесь – инициализация плагина, это влечёт изменение внешнего вида, поведения и доступных управляющих функций для контрола. Остальные методы за ним – нативные для jQuery.
Второй вызов datepicker – это уже настройка проинициализированного экземпляра.
Плагин можно применить и через вызов jQuery.fn.datepicker(jQuery("#someDomInput"), { /*some params*/ }) – но это просто избыточней.

В этом примере надо абсолютно чётко понимать, что в первом случае плагин возвращает экземпляр, поверх которого он был вызван. Возожно, изменяя этот экземпляр. Но, таки, его-же. И так действуют все элементы цепочки, пока мы не натыкаемся на метод, который должен вернуть объект другого типа – строку, например.

Это настолько далеко от ООП имхо, что даже вспоминать его тут нечего. Такая техника письма как раз любителей ООП вымораживает и бесит невероятно )

Я не уверен, что это соотносится с boto, но паттерн такой есть, и он в клиентском вебе абсолютно повсеместен.

Как раз недавно про это писал тебе при обсуждении запретов – такой подход считался какой-то кривотой и гадостью ещё лет 5 назад. Теперь он повсеместен – потому что это удобно, просто расширяется и отлично читается.


Edited at 2013-03-29 08:00 pm (UTC)
From:rezkiy
Date:March 30th, 2013 07:45 pm (UTC)
(Link)
Мне кажется, что приведенный тобой пример -- это первый стиль, а не второй.
From:ermouth
Date:March 30th, 2013 07:55 pm (UTC)
(Link)
А мы вроде и говорим про первый?
From:rezkiy
Date:April 1st, 2013 10:12 pm (UTC)
(Link)
а ведь и правда. В общем я этот ваш первый сильно предпочитаю динозаврам с 15 параметрами.
From:morfizm
Date:April 2nd, 2013 05:09 am (UTC)
(Link)
Почему предпочитаешь?
Не влом потом мейтейнить этот код?
From:rezkiy
Date:April 2nd, 2013 06:04 am (UTC)
(Link)
Добавлять шестнадцатый параметр хуже.
From:morfizm
Date:April 2nd, 2013 06:09 am (UTC)
(Link)
А если они все именные?
fn(param1=value1, param2=value2, ...)?
(Аналог на C++ - скажем, заполнение структуры, передаваемой в конструктор)
From:rezkiy
Date:April 2nd, 2013 05:42 pm (UTC)
(Link)
аналог уже лучше, но это та же матрешка, вид сбоку.
From:rezkiy
Date:April 2nd, 2013 05:43 pm (UTC)
(Link)
та же матрешка что и первый стиль, то есть.
From:morfizm
Date:March 31st, 2013 12:31 am (UTC)
(Link)
Я считаю, что это плохой паттерн, но он оправдан для JavaScript, в котором надо экономить на объёме кода.

Минусы в читаемости возникают, когда код огромен, и code owners - разные люди, а между ними шныряют какие-то объекты, которые не понятно, кем и как созданы. Их надо изучать и знать изнутри. В случае создания какого объекта через "fully qualified path" (вызов API, с параметрами возвращающий сразу всё, что нужно), тебе не нужно знать поднаготную этого конечного объекта, достаточно знать ровно то, что требуется для задачи. Легче запомнить набор методов-factories из одного класса, чем из целой кучи мелких классов, умеющих порождать ещё более мелкие.

Ещё - первый вариант несколько "оправдан" в UI, потому что там разбивка на классы более-менее визуальна, и это естественно (не требует значительной когнитивной нагрузки), что объект-контейнер может порождать агрегируемые объекты. Даже это, кстати, совсем не обязательно так делать. Можно сделать менеджер окна, умеющий класть объекты в контейнеры, и также порождать как один, так и другие, может, так будет проще.

Короче, моё мнение основано только на реальном опыте - сложности в сопровождении.

Мой вопрос в посте был про историю паттерна, и ... имеет ли он какое-то название?
То, что это повсеместно используется в jQuery, немножко проясняет, но не сильно.

Опять же, иерархия DOM это ближе к UI, что делает более оправданной/естественной такую модель (я ещё помню MFC в Windows). boto - это сетевая библиотека, к UI не имеющая никакого отношения. Никакой логики, что утка именно в зайце, а яйцо именно в утке, там нет - это выглядит как произвольный выбор программиста, наваявшего boto.
From:ermouth
Date:March 31st, 2013 01:58 am (UTC)
(Link)
Дима, в примере, что я привёл, jQuery("#someDomInput") и есть это самое создание объекта через fully qualified path. Заметим, что вовсю практикуется передача параметров "конструктору" по схеме fn ({param1:123, param5:678, param10:"abc"}). Он и вернёт всё, что нужно.

Плюс обычно fn – это мультиметод и ведёт себя по разному в зависимости от типа(ов) аргумента.

Такой подход и некоторые соглашения в оформлении плагинов дал невероятный буст этой экосистеме. Плагины не конфликтуют практически никогда ни в каких сочетаниях – вне зависимости от источника кода. Я бы сказал, что как раз тут полное отсутствие сложностей.

И конечно этот подход стал рапространяться в соседние языки, видимо. Логики там и вправду на первый взгляд маловато. А вот на второй взгляд понимаешь, что оно попроще запоминается.

А в этой бото .save() вернёт promise какой-то или что? То-есть, конструкции типа item.save().error(callback1).done(callback2) вообще бывают там у вас? И понятно ли сразу из записи, что эта конструкция могла бы делать в js? И если понятно, то чем оно плохо?
From:morfizm
Date:March 31st, 2013 02:11 am (UTC)
(Link)
item.save() в данном случае синхронный и не вернёт ничего интересного (если там и есть какие-то колбеки, то они должны быть в параметрах у save).

В твоём примере - оно отлично понятно именно так как ты написал. Но оно становится не очень понятно, когда возникают такие вещи:

def my_super_duper_function(...):
   saving_state = item.save()
   a_lot_of_other_shit = get_shit()
   return (saving_state, a_lot_of_other_shit)

def prepare_management_object(...):
   (shit1, shit2) = my_super_duper_function()
   // compute shit3, shit4 and shit5
   mgt = ManagementObject(shit1, shit2, shit3, shit4, shit5)
   return mgt

def workflow():
   ...
   send_management_object(prepare_management_object())

def send_management_object(mgt):
   manage(mgt)

def get_manage_after_save_callback(mgt):
   def manage_callback(item):
      mgt.notify_next_step()
   return manage_callback

def manage(m):
   m.shit.done(get_manage_after_save_callback(m))
   ...


Теперь представь себе, гипотетически, что всё это разные модули, ты даже не знаешь где они, тебе нужно в глобальном поиске по проэкту поиском по имени каждого shit'а добираться до него.

Ещё, для разминки, представь себе, что твоя задача передать mgt object в другой компонент. А этот callback сработает только если в item'е есть какой-то активный connection object. Соответственно, всю эту хрень (mgt) невозможно сериализовать - пропадёт. Надо всё рефакторить, переделывать.

А это обязательно произойдёт, т.к. дизайн подсказывает, что "это нормально". Т.е. если дать возможность разделить один вызов на три, то кто-нибудь обязательно вызовет тремя, причём совсем не обязательно подряд.

Это разговор из той же серии, что и наш предыдущий - ты считаешь, что надо давать больше гибкости - типа, можно будет элегантнее делать более крутые вещи. Я считаю, что надо давать меньше гибкости, чтобы люди меньше стреляли себе в ногу, и фиг с ним, что некоторые крутые вещи будут не очень элегантными.


Edited at 2013-03-31 02:11 am (UTC)
From:ermouth
Date:March 31st, 2013 02:24 am (UTC)
(Link)
Ахахаха, конечно же либ с названием boto просто обязан давать тебе стрелять себе в ногу )))
From:morfizm
Date:March 31st, 2013 02:26 am (UTC)
(Link)
:)))