Programming
Perfect code
Comments 68
+10
Справедливо, я сам уже 100 раз пожалел что начал переписывать c 0 нашу внутреннюю систему а не изменять текущую:(
+26
А у меня противоположный опыт: я несколько раз участвовал в переписывании разных вещей с нуля и почти всегда получалось лучше, чем было.

Я думаю тут очень важен эффект масштаба. Когда человек переписывает что-то, то он может глубоко вникнуть в то, что он делает и, как правило, сделать лучше. Он может понять зачем нужна LoadLibrary и осознать что Windows 9.x больше никому не нужна.

А вот крупномасштабные проекты — зачастую ведут в описанный в статье провал. Потому что если вы не можете осознать и понять происходящее в старой программе, то вы обязательно наделаете ляпов и нужно будет всё довольно долго чинить.

Я не знаю где лежит граница (чем меньше кусок кода, который вы решили переписать тем чаще достигается успех), но она, условно говоря, в понимании. То есть не «я даже не знаю зачем здесь половина этих API-вызовов», а «я знаю нафига тут добавили эти API-вызовы и я знаю, что они больше не актуальны». Да, это сложно, да, это тяжело, но если вы не понимаете что делает старая программа, то как вы сможете кого-то (в первую очередь себя) убедить, что новая версия будет не хуже?
0
выкинуть LoadLibrary, но оставить остальное, это как раз и есть тот рефакторинг, про который говорит Джоэл
+1
Это уже вопрос семантики. Если вы посмотрели на код, увидели что там 100'000 строк бессмысленных индирекций и кучка функционального кода вкраплённая там и сям в этот безумный фреймворк, то как назвать замену этого всего на 10'000 строк кода, который реализует нужный алгоритм, но при этом вообще ни одной строки из исходного кода не содержит? Это ещё рефакторинг или уже переписывание? Пример вполне себе из жизни, если что.
0
переписывание, да еще со сменой языка, как я понял.

но сразу возникает вопрос. ведь эти 100 тыс. не сразу появились? для него никто не делал рефакторинг. а потом уже стало поздно что-либо менять.
0
Насчет спора надо переписывать с нуля или нет хорошо высказался еще товарищ Ленин: " конкретный анализ конкретной ситуации — это то, в чем самая суть, в чем живая душа марксизма". www.bibliotekar.ru/encSlov/10/138.htm
В одних ситуациях надо, в других — не надо — все зависит от каждого конкретного случая, тут нет генерализированного подхода
+4
Спасибо! Хорошая статья. И перевод получился вполне адекватный, по-моему.
+10
Я хотел еще добавить тег «теги никто не читает», но решил не добавлять, и как видно не зря! Их таки читают!
-3
Диванное исследование: чем больше в комментариях обнаружилось читателей тегов — тем скучнее была статья.
0
Теги нужны не для того чтобы их читать, а для того чтобы потом по ним искать.
+2
Статья добавляет мотивации в работе с тем что есть. Это здорово. Всегда есть место улучшениям.
Хороший перевод.
+1
Надо будет на работе выпросить еще один монитор. На первых двух работа с проектом, а на третьем — держать открытой эту статью.
+3
Проще распечатать статью да наклеить на стену над мониторами.
0
Ну, статья еще побуждает не торопиться и при написании кода иметь ввиду, что его потом придется поддерживать. Если это иметь в голове при проектировании и разработке — потом реально будет легче.
0
Netscape 4.0 работал, его не трогали, спокойно 3 года сидели пилили с нуля.
+3
Спасибо за перевод! Хорошая статья, она действительно не теряет актуальности со временем.
0
Я не разработчик, но всё-таки спрошу: а что делать, если появилась необходимость переписать проект на другом языке программирования?
Например, для введения возможности поддержки новых технологий.
И, естественно, оставить некоторые фичи, другие убрать, а третьи, новые, добавить?
0
Портирование проекта на другой язык — задача хотя и сложная, но все же отличающаяся от переписывания с нуля.
0
А по-моему (как разработчику) — не сильно отличающаяся. Обычно возникает то же желание — «раз уж переходим, надо переписать».
+2
Это желание быстро заканчивается, стоит лишь глянуть на объем работ…
0
Зависит от степени близости языков.
Никому из нас (Dart analyzer team) и в страшном сне не приснится переписывать analyzer с нуля на Dart.

Поэтому написан java2dart translator.
Используется уже больше года, Java код сто раз менялся (отказаться от него пока не можем) и все эти изменения переводятся на Dart.
+1
Этот комментарий написан когда гугла в России уже по сути нет и дарт, кажется, не выжил.
0
Про Гугл в России не знаю, не интересуюсь.
А Dart живой вполне.
Вот Flutter 1.0 вышел на днях, написан на Dart.
Кажется людям сильно нравится, куча звёздочек на GitHub.
+4
Можно нужный кусок написать на этом новом языке программирования (или для новой платформы) и тем или иным способом подлинковать (в т.ч. через вызов, IPC или сеть) к старому коду (или наоборот, старый код использовать из нового сервиса). Но в любом случае надо смотреть по задаче: имеет ли это смысл.
0
Поддеоживать старый, паралелльно разрабатывая новый. Да человеко-часов больше надо будет, но страховка, которую вы себе этим создаете, поможет избежать стратегической ошибки, если что-то пойдет не так (а оно на 90% пойдет именно не так как задумываешь)
+6
Забыт еще один аспект — когда решают поменять саму платформу (язык, библиотеки гуи, десктоп на веб, целевую ос и т.д.) В современном мир именно этот аспект в общем-то и является одним из основных поводов переписывать все.
-3
Мне показалась статья не особо интересной. Крупные проекты, как мне кажется, очень редко переписывают с нуля. Чтоб так взять, обо всем забыть и делать с нуля. Обычно оборачивают во врапперы и адептеры и переписывают потихоньку.
+3
В статье как раз и упоминаются примеры, когда проекты были крупными. Например MS Word
+8
В конце концов, из переписки Netscape вьіросла Mozilla/Firefox. А IE6 не переписьівался годами, и стал медленно, но верно сдавать позиции.
+3
А это уже другая история: если бы в Microsoft не привязали выпуски версий MS IE к выходу версий Windows, если бы не затеяли после этого своё собственное переписывание всего с нуля, если бы не решили, в свою очередь, «под шумок» всё переделать с нуля и в web'е и перейти с HTML на XAML, то фиг бы у Mozilla/Firefox появился бы шанс.

Собственно пример Mozilla/Firefox показывает ровно одно: ошибка описанная в статье не является смертельной если одна из сторон её делает, а другая — не делает, если такую ошибку совершают все (а тяга всё выкинуть и переписать велика у всех разработчиков) — у вас есть шанс.
UFO landed and left these words here
+3
У меня одна раскладка на укр/рус (http://zhouck.livejournal.com/13266.html). Изредка Firefox начинает перехватывать AltGr, и я не могу ввести ы, открывается пункт меню. Лечится перегрузкой FF.
+2
А я при встрече с этой идеей вспомнил об инструментах рефакторинга в современных IDE. Интересно, были ли такие 14 лет назад, когда писалась статья?
+2
Не было. Но даже сейчас «чужой» код приходится в основном рефакторить или вручную, или макросами, поскольку IDE рефакторит точечно и только запланированные случаи.
+1
Для Delphi был очень неплохой ModelMaker и встраиваемый CodeExplorer от них же, с поддержкой UML, рефакторингами, кодогенерацией в обе стороны.
0
Так же очень помогает меню Refactor / Rename в любимом IDE :)
UPD как уже упомянули, пока я писал коммент…
0
А вот IE не переписывает свой код с нуля, поэтому эпичные баги там переходят из версии в версию. Например, с Object.create():

// a generic «class»
function OhComeOn() {}

var a = Object.create(OhComeOn.prototype);
a[1] = 1;
a.hasOwnProperty(1); // false
a.propertyIsEnumerable(1); // false

Подробнее о баге: webreflection.blogspot.ru/2014/04/all-ie-objects-are-broken.html
+3
«Не переписывать с нуля» — не равнозначно «не фиксить баги вообще». Фиксить конечно надо. В этом и суть: фиксить, не выкорчевывая
0
Майкрософт их как-то очень избирательно фиксит, так что самые плохие почему-то остаются. Тот баг, что я привёл, работает на всех версиях IE. Эта какая же должна была быть шляпа, чтобы его пропустить? Для IE8 вообще была собрана новая команда, но наследие старой (той что состояла из индусов) осталось…
+1
меня от переписывания нового спасает лень. как подумаю сколько работы, так сразу желание пропадает
+13
Первая часть саги. Вторая называется — «пишите тесты». Если бы каждая из выстраданных строчек и трудноотловленных багов сопровождалась тестом, то переписывание было бы простым — «надо пройти тесты». И каждая из историй с поиском багов была бы удовлетворена автоматически.

Впрочем, статья очень старая. Тогда с автоматическим тестированием и CI было никак (для сравнения — сейчас плохо).
+4
И да и нет.
Найденые баги хорошо и полезно покрывать тестами. Но сами тесты требуют код с хорошей тестируемостью.

Покрыть тестами двух страничную функцию со множеством API вызовов? Если идти в «лоб», то на выходе будет бардачный код с хрупкими, ломкими и нестабильными тестами. Которые еще будут требовать специфичные стенды для запуска. В итоге их отключат сначала разработчики, а потом и при сборке. Я молчу о том, что уйма времени уйдет на написание теста. Тесты, CI это багаж который может и помочь и за собой утянуть.

Нужно сделать много телодвижений, чтобы все это зажило нормально:
— любой высокоуровневый тест (интеграционный, ui/api, компонентный)
— аккуратный рефакторинг (лучше-автоматический), чтобы разделить и перегруппировать код при этом НЕ похерив результаты оптимизаций (любая низкоуровневая оптимизация/инструкции компилятору запутывают оригинальную логику)
— расширение базы тестов (юнит-тесты, интеграционные) для критичного функционала
— глубокий рефакторинг
— тесты для частных случаев, баги и пр. — специальные тесты
— игра с дизайном (модули, компоненты)
— игра с архитектурой (замена компонент, сервисов)

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

Ваш дали хороший совет, но чертовски легкомысленно.

0
Я как раз рядом со всем этим CI'ем обитаюсь. И я ни разу не видел его хорошо работающим. Особенно, подальше от well-defined протоколов и поближе к RL.

Но, на самом деле иметь стенд с специфичной конфигурацией (нет IE и разрешение экрана 2560х480) не так уж сложно. Получается тяжеловатый артефактный блобик по имени «снапшот», но зато это можно проверить.

Проблема в инструментарии проверки. Насколько я знаю, есть конторы, занимающиеся rich desktop, которые эту проблему таки решили. Я подробности не выслушивал, но по тому, что успел услышать — они записывают весь поток команд в контексте gdi и могут их воспроизводить в отсутствии приложения. Плюс компаратор, позволяющий отловить изменения. Плюс стопятьсот виртуалок-стендов.
0
Я люблю сравнивать софтверные продукты с кораблями. Ну так, по-наркомански.
С развитие виртуализации и клауда работа с такими стендами действительно не большая проблема (я про browserstack, как частный случай).
Но это по силу средним/большим проектам и решается не на уровне выше разработчика (но в праве выставить условия). Не каждая компания готова заплатить за админов, СМов, виртуалки и проч. дребедень.

На этом стоп-машина, речь в статье была про другое.
+8
К сожалению, на ум сразу приходит история с Оперой.
Перенести старый UI на новый движок рендеринга? Не наш путь, мы лучше перепишем всё с нуля…
+2
Есть и другой опыт. Сделали один продукт, отправили в производство. Когда потребовалось делать улучшенную версию — взяли и сделали ее практически с нуля. И получилось сильно лучше, чем в первый раз — т.к. учли недостатки первого раза. Потом последовала еще одна версия — за основу взяли вторую, но большую часть снова переписали — и получилось еще лучше. И наоборот, когда из-за поджимания сроков заказчик не дал выбросить прототип, а сказал его допилить, было все очень плохо, пока потихоньку проблемные места не были выброшены и переписаны «как надо».
+1
Переписывание «с нуля» — важная часть развития проекта.
Проект в процессе эволюции обрастает огромным количеством кода, который не лечит баги, а тупо обеспечивает обратную совместимость.
Код проектов поддерживающих обратную совместимость становятся очень страшным.
Я сам писал редактор 3Д сцен, который поддерживал 60 версий форматов файлов вплоть до самой первой. И это было оправданно. И мало поддерживать загрузку 60 версий. Еще надо поддерживать работу разных алгоритмов. Если первые сцены делали с учетом хабагованного алгоритма, то значит при работе с первыми версиями нужно чтобы алгоритм работал с теми же багами! Ведь нужно воспроизвести сцену так как ее создавали. А новые версии файлов нужно воспроизводить уже корректно.
И таким образом код превращается в страшную ересь.
И можно только переписать все заново, потому что корректно убрать все костыли практически невозможно.
И ладно просто страшный код. Его практически невозможно расширять так, чтобы ничего не сломать.
Поэтому редактор переписывается с нуля. Хотя это и не ноль. Ведь многие куски кода не содержат костылей и вполне могут корректно использоваться в новой версии. Загрузка текстур, например. Работа со звуком и т.п.
Плюс пишется отдельный конвертер, который 60 версий файлов конвертирует в новый формат с учетом всех нюансов.
Конвертер пишется один раз и поддержка его не нужна в будущем. Поэтому какие в нем костыли и код — совершенно не важно.
А новый редактор чистый и красивый. Да, через 5 лет он тоже превратится в монстра. Но эти 5 лет он будет развиваться, потому что ему больше не мешают костыли.
А через 5 лет — новая итерация. Еще один конвертер старых файлов…
Конечно, надо останавливаться себя от переписывания, когда это не актуально. Но часто это более чем актуально.
0
Не очень понятен вывод. Если появилась новая технология, то почему же не переписать, используя её. Много в MSO 2013 осталось кода от WinWord6? Что-то мне подсказывает, что не особо. Многие компоненты ядра Linux переписаны по много раз с 1991 года. Графические тулкиты были переписаны без обратной совместимости (GTK2 -> GTK3). Попытки написать новый интерпретатор питона (с нуля) вылились в новые проекты типа PyPy, Jython и тп. Xwindow system хотят заменить на Wayland или Mir, написанные тоже с нуля, так как требования к системам изменились.
+1
Вопрос не в том, сколько кода из WinWord6 дожило до MSO 2013, а в том, сколько его дожило до MS Office 95, сколько кода из MS Office 95 дожило дл MSO 97 и т.д. и т.п. То же самое с ядром Linux'а, GTK и прочим.

Что касается Python'а: вы вот сами сейчас чем пользуетесь? PyPy, Jython'ом или всё-таки CPython'ом? А какой версии? 2 или 3?

А Wayland с Mir'ом — это вообще клиника: есть немалый шанс, что X Windows System будут-таки заменены. Но не на Wayland или Mir, а вовсе даже на SurfaceFlinger.

Нет, иногда переписывание всего с нуля приводит к успеху (хорошим примером является, к примеру, то же ядро NT из которого выросли со временем и Windows XP и Windows 8.x). Но только в том случае если у вас сколько-нибудь заметных конкурентов нету. Если есть — они вас за время пока вы всё будете переписывать съедят заживо. Что и произошло в случае с Netscape'ом, собственно.
0
GTK2 -> GTK3 был фазовый переход первого рода и таких примеров навалом.

Что касается Python'а: вы вот сами сейчас чем пользуетесь? PyPy, Jython'ом или всё-таки CPython'ом? А какой версии? 2 или 3?

Я сейчас пользуюсь python3, интерпретатор CPython. Как только запилят поддержку numpy.linalg в pypy3 перейду на него. Он же быстрее и без GIL, не вижу смысла оставаться на CPython.

А Wayland с Mir'ом — это вообще клиника: есть немалый шанс, что X Windows System будут-таки заменены. Но не на Wayland или Mir, а вовсе даже на SurfaceFlinger.

Мммм, что-то я не слышал ни про один дистрибутив, который это использует. В чем клинка Wayland?

Если есть — они вас за время пока вы всё будете переписывать съедят заживо. Что и произошло в случае с Netscape'ом, собственно.


MS всегда тянула обратную совместимость и костыли в виде «пользователь вытащил дискету» и «тааак, тут был баг в win95». А вот Apple и Google написали с нуля операционные системы для смартфонов, в то самое время когда на рынке властвовала Windows Mobile. И где сейчас эта Windows Mobile?

Тут есть оптимум. Если переписывать дешевле, чем поддерживать тонны костылей, то надо переписывать.
0
Мммм, что-то я не слышал ни про один дистрибутив, который это использует.
Вы не слышали про самую популярную OS в мире? Не верю.

В чем клинка Wayland?
Клиника в том, что они затеяли долгий и болезненный переход на новую инфраструктуру в тот момент, когда решается вопрос: быть этой платформе в принципе или умереть.

У традиционных Linux'овых дистрибутивов есть ещё три-четыре года (ну хорошо, может быть пять — от силы), чтобы доказать что они вообще кому-то и для чего-то нужны на десктопе. Просто потому что примерно столько времени уйдёт на то, чтобы Android смог работать на десктопе и сам себя хостить.

Это — в общем-то не так и много времени. А из-за перехода на Wayland большую часть этого времени Linux не сможет иметь осмысленного, устойчивого API.

А вот Apple и Google написали с нуля операционные системы для смартфонов, в то самое время когда на рынке властвовала Windows Mobile. И где сейчас эта Windows Mobile?
Ровно там где и может быть система, которую какой-то кретин в 7-8й версиях решил вдруг «полностью переписать». Кстати Windows Mobile никогда не «властвовала на рынке». В лучшие годы она имела В Америке рынок был под Blackberry, в остльных странах — Symbian. И обе были полностью переписаны (RIM завяз со своей BB10, Nokia — с Maemo/Meego). Как и следовало ожидать: переписывание с нуля привело к пи#$ецу. Ровно об этом статья, которую мы тут обсуждаем, не так ли?
+2
Считаю нужным добавить, что два года спустя Джоэл все-же признал, что переписывание кода с нуля в некоторых случаях бывает оправдано:
… Наконец, с .NET поставляются замечательные библиотеки классов. Было переработано все — от доступа к данным и веб-разработки до GUI, поэтому создалось редкостное единообразие, сверху до низу. <...> Да, я согласен: .NET нарушает закон «никогда не переписывай с чистого листа». Microsoft это сошло с рук по двум причинам. Во-первых, у них был лучший в мире конструктор языков, человек, которому имы обязаны 90% прироста эффективности разработки программ за последние 20 лет, Андерс Гейльзберг, давший нам Turbo Pascal (спасибо!), Delphi (спасибо!), WFC (отлично!) и теперь .NET (сногсшибательно). ВО-вторых, они посадили за эту работу тьму инженеров на целых три года, в какой-то мере ослабив на это время свое участие в конкурентной борьбе. Запомните: если Microsoft может что-то себе позволить, это не значит, что то же самое можете вы.

Джоэл Спольски. Джоэл о программировании, 2006. Глава 44. Наша стратегия .NET. Стр. 321-322.

Оригинал: Joel Spolsky. Our .NET Strategy, 11 April 2002.

Оригинальный текст
… Finally, the class libraries that ship with .NET are great. The fact that everything, from data access to web development to GUI development, was redesigned means that there is incredible consistency from top to bottom. <...> OK, I admit it — .NET violated the Never Rewrite From Scratch rule. Microsoft got away with it because they had two things. First, they had the world's best language designer, the man who was responsible for 90% of the productivity gains in software development in the last 20 years: Anders Hejlsberg, who gave us Turbo Pascal (thank you!), Delphi (thank you!), WFC (nice try!) and now .NET (smacked the ball outta the park). Second, they put about a zillion engineers on it for about three years, during a period where much of their competition was more-or-less stalled. Remember, just because Microsoft can do something, doesn't mean you can.


0
Джоэл был прав в том месте где он говорит что стратегия «переписывания всего» в .NET чертовски облегчила жизнь программистам. С этим, собственно, никто не спорит. Однако он был неправ в том месте, что «Microsoft это сошло с рук». Нифига подобного — позже сам же Джоэл описал к чему это на самом деле привело. Сейчас Джоэл статей почти не пишет, но остальные процесс отслеживают.

Увы и ах, но .NET — ни разу не контрпример. Да, Microsoft пережил его. Но сваливание на одну ступень всё равно произошло. Microsoft из монстра, который крутил-вертел всей IT-индустрией как хотел — превратился просто в «ещё одну компанию».
+2
Как это не печально, но старину Джоеля по настоящему, так сказать полностью не возможно понять пока не появится вполне конкретный свой собственный опыт, но загвоздка в том что, когда этот самый опыт появляется ты понимаешь старину Джо, но его советы по большей части уже лишние.
0
Вспоминается данная притча, ставшая уже бояном, но, мне кажется, что она подходит как пример для данного случая.

Вася и Петя одновременно начали писать один и тот же продукт.
Вася был «ориентирован на результат» и начал сразу писать говнокод не продумав толком архитектуру.
А Петя месяц разрабатывал архитектуру, месяц делал удобный интуитивный интерфейс, которому позавидывал бы Джони Айв, потом месяц писал тесты, потом два месяца писал сам код и получил идеальное стабильное приложение.
Но Вася выпустил уже через месяц первую версию программы, пусть и не идеальную, пусть с багами, но рабочую, и начал её продавать. Ещё через месяц выпустил вторую версию исправляющие баги первой и добавляющие новые баги. Ещё через месяц на доходы от продаж нанял двух толковых программеров, которые за два месяца перелопатили весь код, согласно пожеланиям пользователей допилили интерфейс и выпустили третью версию программы.
Итого, через пять месяцев у Васи было два работника, куча клиентов и сносно работающее приложение отвечающее желаниям клиентов.
У Пети было вылизанное никому не известное приложение, минус на банковском счёте и ни одного клиента.
В завершение этого выдуманного примера можно сказать, что через полгода Вася купил все наработки Пети, Петю взял в штат тестировщиком, а сам по пьяни разбился на своём новеньком Туареге

http://bash.im/quote/420672

Можно сделать как можешь, чтобы работало хорошо, а потом купить малоизвестный, но хорошо спроектированный продукт конкурента.
+3
Проект сделанный за месяц это не проект, а проектик, т.е. совсем маленький. Хитрый и сложный ОО дизайн там наворотить просто негде и незачем (у Пети руки из не из того места растут). К тому же, много денег на таком не поднимешь.

А вот на проекте длительностью от года без грамотного дизайна можно зашиться.
Начало будет хорошим: в первые же недели будут появляться новые фичи, а конец плохим: с какого-то этапа каждая следующая фича будет как минимум цикломатическую сложность программы линейно увеличивать, что в конечном счёте приведёт к тому что сложность программы превысит когнитивную сложность разработчик(а|ов), и дальнейшая её разработка станет практически невозможной.
0
Мне кажется или из статьи получается что Опера как раз и решила повторить судьбу Netscape?
0
Нет. Не правильно судите о решении команды Opera. Решение о переходе на новый web-движок вполне логично и правильное.
+2
Но в глобальном масштабе аналогия все же очень даже есть. В старой опере была куча вещей, за которую ее любили. В новой опере это все обещают сделать, но пока что получается не очень. Зато у нее «абсолютно новый код»©
0
Да, я именно это и имел ввиду. По факту получается что там теперь совсем новый код, от старой оперы ничего не осталось.
+4
Тоже был сторонником этой идеи, пока не увидел, какой код написал сотрудник до меня (гуманитарий по образованию).
0
Согласен с большинством выводов в статье.
«С нуля» — вовсе не значит, что будет лучше/быстрее/качественнее.
Надо 33 подумать, прежде чем переписывать.
Может лучше еще раз попытаться прочитать чужой код или нанять кого-то для этого?
0
это фиксы багов

На самом деле это костыли.

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

Добавлю ещё, что лучше всего работать с кодом, как с чёрным ящиком. Именно по этому стоит писать комментарии (javadocs, если говорить о джаве) для описания функций (методов).
Only those users with full accounts are able to leave comments.  , please.