Я пробовал подебажить одну библиотеку собранную вебпаком. Скажу это то еще приключение. Когда модуль бывает состоит из одной строчки кода, а внутри вызывает другой модуль в итоге мы получаем незабываемое путешествие по измерениям. И там такой мэппинг, что Алисе даже и не снилось в ее стране чудес. А когда находим нужное место, от которого якобы что-то зависит, оказывается, что это не то место и путешествие начинается заново. Через час другой такой отладки, отпадает всякое желание работать с таким кодом.
И ситуация становится еще хуже. Теперь, вместо того, чтобы просто лазить по простыне if-elseов в одном месте, я буду лазить по 8-ми кускам кода, к которым отсылает новый god-component.
Честно говоря, мне кажется, что я уже использую SOLID подход, но мы как-то не то обсуждаем. Например chekbox() в checkMode или input() в inputMode это такие же компоненты, как и droplist(), он их использует внутри себя по своему усмотрению. И в этом есть смысл: повторное использование, дочерний элемент ничего не знает о родителе, ну и так далее. Но в статье это как-то на столько извращено и перековеркано, что рациональное зерно утеряно. Остались только радостные возгласы о том, как стало легче жить и светлое будущее не за горами.
«это некий «God Component»,» Прямо в точку. Это именно то, что и предполагалось сделать. Эдакое параметрическое программирование: вводишь конфигурацию — получаешь нужный компонент.
Повторюсь у меня нет проблем с отладкой, тестированием (тесты отсутствуют), развитием и поддержкой. Меня смущают макароны из if-else конструкций, которые выглядят не эстетично. Хотелось что-то более феншуйское.
Все принципы SOLID похожи на библейские заповеди, как хочешь так и трактуй. В итоге начинаются холивары, вроде, как надо: element.render() или render(element)?
То есть с появлением нового режима, мне нужно городить droplist2(opts)? Лишь бы не трогать старый? Какой-то оверкилл. И почему сейчас «Можно сделать droplist(opts)», а раньше (в статье) это было нельзя?
Но проблема то никуда не денется. Ну будет у нас вместо одного droplist(opts), восемь конфигураций типа droplistCheck(), droplistMS(), droplistInput() и так далее, всего 8 компонентов.
Пусть инпут будет droplist, multiSelect — множественный выбор с отображением выбранного свреху над дроплистом, checkMode — чекбокс напротив каждого пункта дроплиста, inputMode — в поле дроплиста можно вводить своей значение, а из пунктов находится наиболее подходящий. Пусть кейсов даже будет немного меньше. Все равно легче не становится.
.
Дальше у него возникает необходимость убрать оверлей:
var formHTML = '\
<form>\
<inputs></inputs>\
<controls></controls>\
</form>';
var fullHTML = overlay ?
'<container>' + formHTML + '</container>' :
formHTML;
И так далее. То есть изначально у разработчика есть один большой блок, затем он дробится по мере разработки, когда возникает необходимость добавить новых фич. То есть влезание в код часто используемого компонента — это неизбежность. А как его иначе улучшить? Или как его разбить на меньшие компоненты?
Тем более ветвление никуда не девается. Ну было оно раньше внутри компонента, а стало межкомпонентное. И что мы выиграли?
На самом деле у меня действительно есть проблема, когда в форму вваливатеся куча параметров и их все нужно обработать, при чем каждый влияет на остальные особым образом. И от этого if-else ада я пока не нашел способа избавиться. Думал SOLID поможет, но он как-то не об этом.
Я использую пункт 3. Но тогда рушится вся концепция SOLID. Ведь форма начинает знать о свойствах и методах инпутов.
И раз уж в этом подходе «одна из самых сложных тем», где я проблемы даже не встретил, то я просто создал отдельный базовый класс Input, от которого отнаследовал остальные инпуты, откастомизировав их, а сама Form использовала их прототипные методы вроде getValue(), getHTML(), blink() и т.д. Хочешь добавить свой метод, например, onBlur(), не вопрос, передавай его в параметр инпута, типа new Form([{droplist:{onBlur: blurHandler}}], handler, opts). Я считаю в этом как раз наоборот вся красота и простота подхода, а не его недостаток. Да и собственно в статье эти недостатки описаны как-то пространно, вроде «это „попахивает“», «грозит появлением регрессий». Я даже не понимаю о чем речь. Как будто меня пугают привидениями.
Допустим. Но пока выгоды не вижу. Раз форма о них ничего не знает, что делать в ситуации, когда при сабмите инпуты проходят валидацию и надо мигнуть, если поле пустое.
Погодите меня штрафовать за нарушения. Я пока в целом не понял, чем я так провинился и чем ваш подход лучше. В итоге, так и не ясно от куда взялось this.state.showCloseButton. Кто и через что этот state туда засунул? В этом же ключевой момент. И для чистоты эксперимента давайте может чистый js и html использовать (не считая jquery). А то я может какой-то ключевой момент упускаю.
Так об обертках то и речь. Именно их Вы забраковали, а не внутреннюю реализацию. Моя внутренняя реализация выглядит практически так же.
var formHTML = showControls ?
'<form><controls></controls></form>' :
'<form></form>'
$('#form').html(formHTML);
То есть в моем случае я просто добавляю кейс на уровне if или switch. Вы же городите новый модуль. При чем он городится точно так же по мере возникновения необходимости, а не заранее, ведь изначально неизвестно нужно ли будет его скрывать или нет.
В итоге мы имеем:
«Это описано в секции статьи „Как делать не надо“». Но я так сделал. накатал 3к строк кода и ничего, по необходимости навешиваю всё новые свойства, когда надо. Поэтому я и не понял, почему рабочий метод забраковался и вместо него предлагается некая сомнительная конструкция. Давайте просто сравним подходы в контексте приложения. Надо решить упомянутую проблему с кнопками.
До:
new Form(inputs, function(results){
send(results);
});
После:
new Form(inputs, function(results){
send(results);
}, {showControls: false});
Например, понадобилось, чтобы форма была встраиваемая в основной контент. Просто в конструктор передаешь третьим параметром: {parent: selector}, то есть родительскую ноду, в которую надо встроить форму и затем рендеришь в нее, а не в popup. Как-то так. Если нужно убрать кнопки, оставив крестик добавляешь что-то типа {parent: selector, controls: false}. Если нужна какая-то особая кнопка то используешь инпут типа html — просто контейнер для гипертекста и в него вставляешь нужные кнопки, размещая их как надо при помощи стилей. Если нужна кастомная стилизация, то добавляешь {parent: selector, controls: false, class: 'myCustomClass'}, затем добавляешь этот класс к форме $form.addClass(class). Думаю смысл понятен.
Сам недавно писал такое окно на js. Пол года где-то писал. Реализовал все возможные инпуты и поведения формы. Как-то никаких проблем не заметил. есть конструктор Form, задаются параметры, где Form([массив инпутов], функция-обработчик, {объект — свойства формы}). Всё! Придумывай сколько угодно инпутов по единому базовому шаблону с неограниченной возможностью кастомизации параметров и вешай сколько угодно свойств и методов на саму форму. При чем вся моя философия повторного использования кода сводилась к следующему: видишь кусок кода повторяющийся больше двух раз — выноси в функцию. Я не пытаюсь что-то опровергнуть, но я не вижу большой пользы от всей этой конструкции под названием SOLID. По крайней мере статья этого не раскрывает.
Честно говоря, мне кажется, что я уже использую SOLID подход, но мы как-то не то обсуждаем. Например chekbox() в checkMode или input() в inputMode это такие же компоненты, как и droplist(), он их использует внутри себя по своему усмотрению. И в этом есть смысл: повторное использование, дочерний элемент ничего не знает о родителе, ну и так далее. Но в статье это как-то на столько извращено и перековеркано, что рациональное зерно утеряно. Остались только радостные возгласы о том, как стало легче жить и светлое будущее не за горами.
Повторюсь у меня нет проблем с отладкой, тестированием (тесты отсутствуют), развитием и поддержкой. Меня смущают макароны из if-else конструкций, которые выглядят не эстетично. Хотелось что-то более феншуйское.
Все принципы SOLID похожи на библейские заповеди, как хочешь так и трактуй. В итоге начинаются холивары, вроде, как надо: element.render() или render(element)?
Конструктор
Внутренняя реализация:
Можно ли кадринально изменить этот код с помощью SOLID?
Дальше у него возникает необходимость убрать оверлей:
И так далее. То есть изначально у разработчика есть один большой блок, затем он дробится по мере разработки, когда возникает необходимость добавить новых фич. То есть влезание в код часто используемого компонента — это неизбежность. А как его иначе улучшить? Или как его разбить на меньшие компоненты?
Тем более ветвление никуда не девается. Ну было оно раньше внутри компонента, а стало межкомпонентное. И что мы выиграли?
На самом деле у меня действительно есть проблема, когда в форму вваливатеся куча параметров и их все нужно обработать, при чем каждый влияет на остальные особым образом. И от этого if-else ада я пока не нашел способа избавиться. Думал SOLID поможет, но он как-то не об этом.
И раз уж в этом подходе «одна из самых сложных тем», где я проблемы даже не встретил, то я просто создал отдельный базовый класс Input, от которого отнаследовал остальные инпуты, откастомизировав их, а сама Form использовала их прототипные методы вроде getValue(), getHTML(), blink() и т.д. Хочешь добавить свой метод, например, onBlur(), не вопрос, передавай его в параметр инпута, типа new Form([{droplist:{onBlur: blurHandler}}], handler, opts). Я считаю в этом как раз наоборот вся красота и простота подхода, а не его недостаток. Да и собственно в статье эти недостатки описаны как-то пространно, вроде «это „попахивает“», «грозит появлением регрессий». Я даже не понимаю о чем речь. Как будто меня пугают привидениями.
То есть в моем случае я просто добавляю кейс на уровне if или switch. Вы же городите новый модуль. При чем он городится точно так же по мере возникновения необходимости, а не заранее, ведь изначально неизвестно нужно ли будет его скрывать или нет.
В итоге мы имеем:
До:
После:
Напишите свой пример До и После.