Монстрирование в разработке

Как это бывает в ЖабаСкрипте

Некоторое время тому назад, когда стал вопрос в разработке стандартизированного JS инструментария для модулей системы (читай проектов), я задумался на тему выбора одной из готовых библиотек. В процессе тщательного отбора был отсеян большой список библиотек. Фактически остались только две: jQuery и Prototype.

В конечном итоге был сделан неутешительный вывод: эти монстры не нужны. Зачем нам использовать кучи чужого кода, когда 90% нужд покрываются простенькой библиотекой типа:

function $(e){if(typeof e=='string')e=document.getElementById(e);return e};
function $a(e,c){return $(e).appendChild(document.createElement(c))};

function each(a,f){var n=[];for(var i=0;i<a.length;i++){var v=f(a[i]);if(v!=null)n.push(v)}return n};

var _a = {

	ajax: {

		x: function(){try{return new ActiveXObject('Msxml2.XMLHTTP')}catch(e){try{return new ActiveXObject('Microsoft.XMLHTTP')}catch(e){return new XMLHttpRequest()}}},

		serialize: function(f){var g=function(n){return f.getElementsByTagName(n)};var nv=function(e){if(e.name)return encodeURIComponent(e.name)+'='+encodeURIComponent(e.value);else return ''};var i=each(g('input'),function(i){if((i.type!='radio'&&i.type!='checkbox')||i.checked)return nv(i)});var s=each(g('select'),nv);var t=each(g('textarea'),nv);return i.concat(s).concat(t).join('&');},

		send: function(u,f,m,a){var x=this.x();x.open(m,u,true);x.onreadystatechange=function(){if(x.readyState==4)f(x.responseText)};if(m=='POST')x.setRequestHeader('Content-type','application/x-www-form-urlencoded');x.send(a)},

		get: function(url,func){this.send(url,func,'GET')},

		gets: function(url){var x=this.x();x.open('GET',url,false);x.send(null);return x.responseText},

		post: function(url,func,args){this.send(url,func,'POST',args)},

		update: function(url,elm){var e=$(elm);var f=function(r){e.innerHTML=r};this.get(url,f)},

		submit: function(url,elm,frm){var e=$(elm);var f=function(r){e.innerHTML=r};this.post(url,f,this.serialize(frm))}

	},

	addEvent: function(o, e, f, s) {
	    var r = o[r = "_" + (e = "on" + e)] = o[r] || (o[e] ? [[o[e], o]] : []), a, c, d;
	    r[r.length] = [f, s || o], o[e] = function(e){
	        try{
	            (e = e || event).preventDefault || (e.preventDefault = function(){e.returnValue = false;});
	            e.stopPropagation || (e.stopPropagation = function(){e.cancelBubble = true;});
	            e.target || (e.target = e.srcElement || null);
	            e.key = (e.which + 1 || e.keyCode + 1) - 1 || 0;
	        }catch(f){}
	        for(d = 1, f = r.length; f; r[--f] && (a = r[f][0], o = r[f][1], a.call ? c = a.call(o, e) : (o._ = a, c = o._(e), o._ = null), d &= c !== false));
	        return e = null, !!d;
	    }
	},

	removeEvent: function(o, e, f, s){
	    for(var i = (e = o["_on" + e] || []).length; i;)
	        if(e[--i] && e[i][0] == f && (s || o) == e[i][1])
	            return delete e[i];
	    return false;
	}

}

Ajax, listener-ы и шорткаты на элемент-по-ид и добавление элемента. Что может быть нужно более?

Некоторое время ничего более и не надо было. В принципе, это базиса хватало и на “обаяксивание” форм, и на “тултипы” и на прочие мелочи… … которых, через месяц накопилось на много килобайт кода. Модули уже стабильно работали на этом коде и ничто не предвещало беды, пока не понадобилась главная фича jQuery — умный “СSS/XPATH-like” селектор элементов.

Поскольку добавление к существующей куче JS файлов еще и всего jQuery было бы совсем не в тему, пришлось руками дергать нужные участки (тянувшие за собой другие участки, использующие, в свою очередь еще одни участки) кода библиотеки. Переписывать начисто самому было некогда. Писать начерно полуфабрикаты уже не хотелось.

В конечном итоге, из исходного приведенного выше кода, у меня получился свой монстр, который владеет массой функциональных возможностей, практически сопоставимый с тем же jQuery. Но имеющий один большой и жирный недостаток: без самого jQuery он не имеет возможности использовать написанные под jQuery плагины (которых великое множество). Эмулировать jQ глупо, поэтому весь функционал дописывается руками. Поскольку “монстр был нам не нужен” — нативных функций для расширения (как в Prototype или jQ) не предусмотрено было изначально. В общем бардак полный. Выкинуть весь этот мусор уже просто нельзя, а переписывать геморно.

В своем последнем проекте, я все таки решил использовать jQ. Но у меня зависимостей там таких нет.

Это я все к чему..
Поскольку вопрос “монстрируемости” кода в последнее время становится все актуальнее, хотелось бы узнать кто как решает подобные вопросы.

Как не сделать из абстрактного куска кода монстра?
Как избежать ситуации, когда разработка стихийно перевращается в написание костылей, а дальнейшие действия сводятся к разработке новых костылей для поддержания работы старых костылей?
Насколько универсальным надо проектировать этот кусок кода, если универсальность всегда способствует расширяемости, что само по-себе форсирует выведение монстра?
Какова максимальная степень универсализации кода, когда GENERIC еще НЕ ОЗНАЧАЕТ LOW PERFORMANCE?

Есть ли в принципе ответы на эти вопросы? Ведь если приведенный пример с жабаскриптом, который по своей сути просто ошибка проектирования, изначально мог быть решен путем использования уже существующей чужой, но бесплатной библиотеки, то с приложениями ситуация гораздо сложнее..

Ту би будет…

RSS feed | Trackback URI

9 Комментариев »

Comment от Oleg Marchuk
2007-04-12 07:45:03

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

Comment от Eugene Bond
2007-04-12 08:45:49

Теоретически — да.
Фактически есть несколько моментов, которые могут препятствовать.

1. Как выбрать подходящий момент? Начать рефакторить рано — разработка сведется к “рефакторингу ради рефакторинга”. Опаздать — проще переписать, чем отрефакторить.
2. Для одного постоянно и стабильно развивающегося проекта, с четкой структурой и требованиями это единственный верный путь. Легкость поддержки совместимости версий, удобство обновлений. Про серверную часть я позже скажу отдельно, а в вот случае с вышеупомянутым жабаскриптом: обновить несколько десятков сайтов одновременно практически нереально, а обновлять надо одновременно, потому что ядро системы одно и модули, использующие JS, прийдется так или иначе обновлять. При этом на большинстве сайтов, SVN, к сожалению, после рефакторинга либо потянет за собой конфликты, либо форсированно убъет сайт-депендент кастомайзы.

Comment от Oleg Marchuk
2007-11-18 17:15:54

Добавляя новую функциональность - принимать решение о необходимости рефакторинга. Если есть необходимость - делаем рефакторинг, но только в том обьеме, чтобы добавить новую функциональность, не больше.

(Comments wont nest below this level)
Comment от Eugene Bond
2007-11-19 08:49:45

В основном так и стараемся, но стихийность вносимых изменений сеет хаос.
Тем более, специфика такова, что для большинства продуктов первый заказчик — сама контора, и функциональность вытачивается под нужды шефа. Зато когда появляются первые 3-4 клиента на готовый продукт, выясняется, что мировозрение шефа очень сильно отличается от ожиданий клиента :-/

 
 
 
 
Comment от Maxim Derkachev
2007-04-12 11:15:25

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

Поэтому тулкиты использовать надо. У них два преимущества. Первое преимущество - они пишутся, тестируются и критически обозреваются большим количеством народа, а это покупается только за огромное время и большие деньги. Обычно этот коллективный разум и находит баланс между удобством и производительностью. Второе - ты можешь писать используя довольно высокоуровневые конструкции, что экономит кучу времени и места на диске. И два недостатка - количество загружаемого кода и потеря производительности. Первый недостаток - временный, т.к. скорость сети растет очень быстро, к тому же это без учета сжатия. Второй, как правило, несущественный, да к тому же и тоже временный - через год JavaScript будет работать гораздо быстрее чем сейчас.

Мой пример. Я давно использую YUI. При этом все равно возникает куча своего кода, который часто бесит. При этом для YUI (как и для JQ и Prototype) есть офигенная надстройка - Ext. Объем занрузки его поначалу отталкивает. Однако сейчас я уже крепко сомневаюсь в том, что мой код поверх YUI занимает меньше места и более хороший, чем был бы код, написанный поверх Ext, вместе с самим Ext.

В любом случае, все зависит от того, для чего тебе это нужно. Для пары эффектов на одном сайте с выплывающими фиговинами и т.п. я брал Prototype Lite, и писал анимацию сам. На другом, где куча диалогов, драгдропа, автокомплита и прочего аджакса, загружается почти полностью YUI и куча моих надстроек. Без Prototype Lite в первом случае я бы прожил легко. Без YUI во втором мне бы пришлось написать что-то свое типа YUI. По объему, наверно, оно было бы меньше, но по качеству - сомневаюсь.

P.S. Женя, убери этот ужас с листингом, поставь себе http://www.softwaremaniacs.org/soft/highlight/ :)

Comment от Oleg Marchuk
2007-04-12 11:47:06

К П.С. Что с заголовками писем? У меня сабжекты на китайском :=/

Comment от Eugene Bond
2007-04-12 19:42:15

Фигня какая-то..
Смена кодировок никак не влияет на результат..
Прийдется, на досуге, напильником работать..

(Comments wont nest below this level)
 
 
Comment от Eugene Bond
2007-04-12 19:15:29

Макс, главная проблема была в том, что все прекрасно понимали, что код не уникальный. И начинали с поиска тулкитов. Но Яхувский моментально спугнул, а остальные (полтора года назад) находились или в зачаточном или в нераскрученном состоянии. На тот момент удалось обойтись самописной 3-4кб библиотекой для UI, что устраивало больше, чем кусков компиляция кода из разных источников. JQ активно развернулся с пол-года назад, Prototype чуть раньше, эфекты типа moo.fx не нужны были как тогда, так и сейчас..

И конечно, как показала практика, не надо было бояться Яхи..
Но появляются мысли вот какие: ты пишешь “Без Prototype Lite в первом случае я бы прожил легко”. Но, представь себе ситуацию, что проект надо развивать и необходимо добавить еще фунционал. Если ты не используешь PrototypeLight тебя два пути: переписать все под какой-либо тулкит или дописать функционал самому. Причем последний вариант чреват вероятным повторением ситуации. Если ты уже используешь ProrotypeLight, то скорее всего тебе достаточно будет преключиться на полную версию и скачать пару плагинов..
Отсюда напрашивается ошибочный сомнительный вывод — всегда и везде сразу же надо юзать могучие универсальные библиотеки. Я до конца не уверен сомнительно или ошибочно ли использовать могучие тулкиты для всего, но такова общая тенденция и это как минимум настораживает. Примеры того, что люди отвыкают мыслить просто, даже приводить нет смысла — они кругом.. :(
И в то же время постояно появляются примеры того, что “сложномыслие” оправдало себя в последствии.

И это только одна сторона проблемы. Сама проблема глубже и шире. Яха спугнула монстрообразностью. Этой тенденции подвержены и серверные (да и десктопные) приложения. Наращивание функционала увеличивает не только размер, но и усложняет API для разработчика, и, зачастую, UI для пользователя. Последнее представляется мне наиболее опасным с точки зрения “торговца готовым продуктом”. Я еще хочу написать об этом позже, когда дойду до софта.

PS: поставил этот плагин — все равно рвет ленту..

 
 
Comment от Maxim Derkachev
2007-04-13 11:02:05

Но появляются мысли вот какие: ты пишешь “Без Prototype Lite в первом случае я бы прожил легко”. Но, представь себе ситуацию, что проект надо развивать и необходимо добавить еще фунционал.

Если бы была такая ситуация, я бы заюзал “большой” тулкит не задумываясь. Просто там пара функций с эффектами, ради этого не стоило.

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

Про плагин - у тебя есть файрбаг, посмотри как у людей :)
Hint: не хватает overflow:auto

 
Имя (обязательно)
E-mail (required - never shown publicly)
URI
Ваш комментарий (smaller size | larger size)
You may use <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> in your comment.