Когда переписывать базу кода с нуля


Я вспоминаю статью Джоэла Спольски о том, что никогда не переписывать код с нуля. Подводя итог его аргументу: код не становится ржавым, и хотя он может не выглядеть красиво после многих релизов обслуживания, если он работает, он работает. Конечному пользователю все равно, насколько хорош код.

вы можете прочитать статью здесь: Вещи, Которые Вы Никогда Не Должны Делать

Я недавно взял на себя ПРОЕКТ и после просмотра их кода, это довольно ужасно. Я сразу же подумал о прототипах, которые я построил раньше, и прямо заявил, что он не должен использоваться для какой-либо производственной среды. Но конечно, люди не слушают.

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

Я дал рекомендации держателям акций, что, хотя мы должны сохранить существующий код, и сделать исправления ошибок релизы, и некоторые незначительные релизы функций, мы должны начать переписывать его немедленно с тестовой разработки в виду и с четким разделением проблем. Я подумываю о том, чтобы пойти ASP.NET маршрут MVC.

моя единственная забота, конечно, сколько времени может потребоваться, чтобы переписать с нуля. Это не совсем сложно, довольно запустить веб-приложение mill с членством и т. д..

кто-нибудь из вас сталкивался с подобной проблемой? Любой какие конкретные шаги Вы предприняли?

обновление:

Так.. Что я в итоге решил сделать? Я принял подход Мэтта и решил рефакторинг многих областей.

  • так как App_Code становился скорее большой и тем самым замедляет сборку время, я удалил многие из классов и преобразовал их в класс Библиотека.
  • Я создал очень простой доступ к данным Слой, в котором содержались все АДО вызывает и создает SqlHelper объект для выполнения этих вызовов.

  • я реализовал более чистое ведение журнала
    решение, которое гораздо более лаконично.

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

17 59

17 ответов:

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

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

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

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

книги факты и заблуждения программной инженерии констатирует этот факт: "Модификация повторно используемого кода особенно подвержена ошибкам. Если требуется пересмотреть более 20-25 процентов компонента, то более эффективно и эффективно переписать его с нуля." Цифры взяты из некоторых статистических исследований, проведенных по этому вопросу. Я думаю, что цифры могут отличаться из-за качества базы кода, поэтому в вашем случае, кажется, более эффективным и эффективным переписать его с нуля, принимая это заявление во внимание.

статья Джоэла действительно говорит все это.

в принципе никогда.

Как отмечает Джоэл: вы просто потеряете слишком много, делая это с нуля. Это, вероятно, займет гораздо больше времени, чем вы думаете, и каков конечный результат? Что-то, что в основном делает то же самое. Так в чем же бизнес за это?

Это важный момент: это стоит денег, чтобы что-то написать с нуля. Как вы будете отыгрывать эти деньги? Многие программисты игнорируют это точки просто потому, что им не нравится код-иногда с оправданием, иногда нет.

У меня было такое приложение, и переписать было очень полезно. Тем не менее, вы должны попытаться aviod ловушку "улучшение".

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

убедитесь, что вы решили, что именно будет изменено, а что будет только переписано - in вперед.

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

  • Windows NT (оторвался от старого кода DOS-базы. На этом фундаменте были построены Win2k, WinXP и предстоящий Win7. Да, Виста тоже. Последняя версия Windows на старой базе была печально известной WinME)
  • Mac OS X (перестроил свой флагманский продукт на FreeBSD)
  • много случаев, когда конкурент вытесняет стандарт де-факто. (например, Excel против Lotus 123)

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

Я был частью небольшой команды, которая переписал код с нуля, включая реинжиниринг бизнес-правил кодекса. Первоначальная заявка была на веб-сервис, написанный на C++ (регулярные сбои и серьезные утечки памяти) и веб-приложения ASP.NET 1.0 и замена на C# 2.0 на asmx веб-службы, а также ASP.Net приложения Web 2.0 с помощью AJAX. Это сказало некоторые вещи, которые команда сделала и объяснила руководству

  1. мы поддерживал существующую базу кода в производстве до тех пор, пока новый код не был готов.
  2. руководство согласилось, что перезапись (первый релиз) не будет вводить никаких новых функций, а просто реализовать существующие функции. Мы добавили только 1-2 новые функции в конце.
  3. небольшая команда состояла из очень опытных разработчиков с отличной способностью понимать и сотрудничать.
  4. было сложнее получить талант C++ в организации, и C# рассматривался как лучшая альтернатива для будущего обслуживания.
  5. мы договорились агрессивной таймфрейме, но в то же время были уверены в себе и целеустремленных для работы в C# 2.0, ASP.Net 2.0 и т. д.
  6. у нас был лидер команды, чтобы защитить нас от высшего руководства, и мы следовали scrum, как процесс.

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

на ум приходит только одна квази-законная причина: политика.

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

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

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

политика может быть огромная боль.

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

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

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

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

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

мой ответ: переписать с нуля как можно чаще.

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

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

Это, как говорится, не все переписывает хорошая идея. Например, Windows Vista.

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

по крайней мере, сразу начать писать тесты.

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

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

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

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

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

в рамках исследования вы можете рассмотреть возможность написания некоторых автоматизированных тестов системы для исследования и документирования ожидаемого поведения. Сосредоточьтесь на тестировании черного ящика/интеграции, а не на модульном тестировании (что код, вероятно, не позволит в любом случае, если это так уродливо).

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

Я думаю, что это зависит от двух вещей:

1) Как испорчен основной дизайн устаревшей кодовой базы,

2) Время, которое потребуется для перезаписи.

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

2) несмотря на много кода и очень витиевато, запустить процессы. Наш двигатель делал не так уж много. Поэтому переписать не долго. Иногда менеджеры не понимают, что функциональность сотен тысяч строк кода может быть восстановлена за очень короткое время.

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

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

существует также противоречивое утверждение в экономике, которое говорит:

никогда не учитывайте затонувшие расходы

потопленные расходы, согласно Википедии (https://en.wikipedia.org/wiki/Sunk_cost):

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

когда потопленные расходы сочетаются с политическим давлением или личным эго (какой менеджер хочет быть тем, кто признает, что они приняли плохое решение или не контролировали должным образом результаты, даже если это было неизбежно или вне их непосредственного контроля?), это приводит к ситуации под названием эскалация приверженности (https://en.wikipedia.org/wiki/Escalation_of_commitment), который определяется как:

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

как это относится к коду?

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

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

все это, как говорится, не означает, что мы должны переписывать, когда это возможно, и не должны избегать переписывания рабочего кода любой ценой. Обе крайности потенциально расточительны, и последняя имеет тенденцию приводить к эскалации обязательств (потому что все означает С полным пренебрежением к затратам, даже если эти затраты полностью опережают выгоды). Необходимо провести объективную оценку затрат и выгод, связанных с переписыванием кода, по сравнению с постепенными улучшениями. Задача состоит в том, чтобы найти кого-то с опытом и объективностью, чтобы принять это решение должным образом. Для нас, разработчиков, мы обычно склонны к переписыванию, потому что это, как правило, намного интереснее и привлекательнее, чем работа над какой-то дерьмовой устаревшей кодовой базой. Бизнес-менеджеры, как правило смещен в другую сторону, потому что переписывание накладывает некоторые неизвестные с небольшой ощутимой непосредственной выгодой. Результатом, как правило, является отсутствие реального решения, которое затем по умолчанию продолжает сбрасывать часы в существующий код до тех пор, пока некоторые обстоятельства не потребуют направленного сдвига (или разработчик тайно переписывает код и обычно получает за это порку).

я работал над кодовыми базами, которые были несколько спасаемы, хотя и уродливы. Они не следовали установленным практики или стандарты, не использовали шаблоны, не были симпатичными, но они выполняли свои предполагаемые функции достаточно хорошо и были достаточно гибкими, чтобы их можно было изменить для удовлетворения ожидаемых будущих потребностей в течение ожидаемого срока службы приложения. Хотя это и не гламурно, было вполне приемлемо сохранить этот код живым, делая дополнительные улучшения, когда появилась такая возможность. В противном случае это принесло бы мало пользы, кроме как выглядеть красиво. Я бы сказал, что большинство кода о чем должен ли я переписать это? возникает вопрос подпадает под эту категорию, и я нахожу себя объясняя младшим разработчикам в команде, что, хотя было бы очень весело переписать YetAnotherLineOfBusinessApp в {insert whizzbang framework here}, это не является ни необходимым, ни желательным, и вот некоторые способы, которыми мы можем его улучшить...

Я также работал над кодовыми базами, которые были безнадежны. Это были приложения, которые едва запускались в первую очередь, обычно он отстает от графика и находится в состоянии ограниченной функциональности. Они были написаны таким образом, что никто, кроме оригинального разработчика, не имел бы никаких шансов понять, что в конечном итоге делает код. Я называю это кодом "только для чтения". Как только он написан, любая попытка изменения потенциально приводит к системному неразборчивому отказу неизвестного происхождения, что приводит к паническим массовым переписываниям массивных монолитных конструкций кода, которые не служат никакой цели, кроме как обучать текущий разработчик о том, что на самом деле происходит с переменной с умным именем obj_85 к моменту выполнения достигает линии 1,209 вложенных 7 уровней глубоко в if... else...,switch и foreach... заявления где-то в DoEverythingAndMakeCoffee(...) метод. Попытки рефакторинга этого кода приводят к сбою. Каждый путь, по которому вы следуете, ведет к другому вызову, и больше путей, а затем пути, которые ветвятся, а затем возвращаются к предыдущему пути, и после двух недель рефакторинга heads-down одного класса вы понимаете, что, хотя возможно, лучше инкапсулированный, новый код почти такой же странный и запутанный, как и старый код, вероятно, содержит еще больше ошибок, потому что первоначальное намерение того, что вы рефакторировали, было совершенно неясным, и, не зная, какие именно бизнес-кейсы привели к первоначальной катастрофе, вы не можете быть уверены, что полностью реплицировали функциональность. Прогресс почти не существует, потому что перевод кодовой базы почти невозможен, и что-то настолько невинное переименовывает переменную или использует правильный тип производит значительное количество побочных эффектов.

попытка улучшить кодовые базы, как указано выше, является упражнением в тщетности. Рефакторинг обычно приводит к 80% перезаписи в любом случае, и конечный результат нигде не приближается к 80% улучшению. Вы получаете что-то очень непоследовательное, и новый код имеет много компромиссов, которые должны были быть реализованы в интересах совместимости с устаревшим кодом (половина из которых была ненужной, потому что устаревший код, новый код, необходимых для взаимодействия с позже получает вынесен в любом случае). Есть только два пути, которым можно следовать... продолжайте накапливать технический долг, взламывая "исправления" и модификации, надеясь, что приложение устарело (или вы перенесетесь в другой проект), прежде чем оно рухнет под собственным весом, или кто-то принимает бизнес-решение и рискует сделать полную переписку. Я ненавижу оба этих варианта, потому что это обычно означает ожидание, пока что-то критическое не потерпит неудачу или проект сильно отстает от графика, а затем вы проводите следующие три месяца вечеров и выходных, пытаясь заставить что-то дышать, что, вероятно, никогда не должно было быть живым в первую очередь.

Итак, как вы решаете?

  1. насколько хорошо работает существующий код? Он надежен и относительно свободен от дефектов?
  2. способны ли люди в моей команде понять, что этот код делает с a разумная степень усилий? Если я приведу опытного разработчика, сможет ли он / она иметь достаточно смысла, чтобы стать продуктивным в разумные сроки?
  3. какие-то простые дефекты требуют геологического измерения времени для исправления; настолько, что мы не можем сделать реальные улучшения или уложиться в сроки проекта?
  4. является ли кодовая база настолько хрупкой и ожидаемый срок службы таким, что способность приложения адаптироваться к будущим ожидаемым потребностям бизнеса это очень сомнительно?
  5. действительно ли существующий код соответствует первоначальным требованиям к функциональности?
  6. ваша организация даже восприимчива к инвестированию в приложение, или кто-то (особенно кто-то на более высоком уровне на организационной диаграмме) собирается передать свои собственные *ss для этой проблемы?
  7. можете ли вы предоставить финансовое или основанное на риске обоснование, подкрепленное жесткими фактами, чтобы сделать бизнес-обоснование для переписывания?
  8. если после полного учет времени и затрат на переписывание (включая разработку надлежащих спецификаций, тестирование обеспечения качества, стабилизацию после производства и обучение, имеет ли смысл начинать переписывать код (американские разработчики, как правило, думают только о времени кодирования)?
  9. у вас есть выбор? Возможно ли вообще, чтобы существующий код соответствовал требованиям (потому что если нет, переписывание огромных полос будет частью проекта и будет считаться "улучшением" вместо переписать)?

есть старая пословица, которая говорит:

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

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

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