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

156

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

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

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

Есть ли полезные советы о том, как сохранить исходный код действительно поддерживаемым на протяжении многих лет?

времени
источник
9
Настоятельно рекомендуем книги: «Руководство по выживанию программных проектов» Стива Макконнелла, «Быстрая разработка» Стива Макконнелла, «Рефакторинг» Мартина Фаулера
Имран Омар Бухш
15
... и «Чистый код» дяди Боба;) (Роберт С. Мартин)
Гэндальф
34
Не является ли этот вопрос чем-то, что породило несколько десятилетий интенсивного чтения и целых курсов в университетах?
детально
17
@ Эрик Инь - я не согласен с комментариями. Для меня они являются запахом кода, и в более долгосрочных проектах, как правило, приносят больше вреда, чем пользы, потому что они неизбежно устаревают и становятся обманчивыми.
JohnFx
8
@Eric Yin: стремиться к самодокументируемому коду. Используйте комментарии о намерениях только там, где они улучшают понимание.
Mitch Wheat

Ответы:

138

Единственное реальное решение, позволяющее избежать гниения кода - это хорошо кодировать!

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

Обычные хорошие практики могут помочь:

  1. Будь проще.
  2. Будь проще. Особенно это относится к архитектуре, «большой картине». Если разработчики , имеющие трудное время , чтобы получить общую картину, они будут закоди- против него. Поэтому сделайте архитектуру простой, чтобы все разработчики получили ее. Если архитектура должна быть не простой, то разработчики должны быть обучены понимать эту архитектуру. Если они не усваивают это, то они не должны кодировать это.
  3. Цель для низкого сцепления и высокой когезии . Убедитесь, что все в команде понимают эту идею. В проекте, состоящем из слабо связанных, связных частей, если некоторые части становятся неразбавляемым беспорядком, вы можете просто отключить и переписать эту часть. Труднее или почти невозможно, если муфта тугая.
  4. Быть последовательным. Какие стандарты соблюдать мало, но, пожалуйста, следуйте некоторым стандартам. В команде каждый должен следовать тем же стандартам. С другой стороны, легко стать слишком привязанным к стандартам и забыть обо всем остальном: пожалуйста, поймите, что хотя стандарты полезны, они являются лишь небольшой частью создания хорошего кода. Не делай из этого большого количества.
  5. Обзоры кода могут быть полезны, чтобы заставить команду работать последовательно.
  6. Убедитесь, что все инструменты - IDE, компиляторы, системы управления версиями, системы сборки, генераторы документации, библиотеки, компьютеры , стулья , общая среда и т. Д. - в хорошем состоянии, чтобы разработчикам не приходилось тратить свое время на второстепенные проблемы, такие как как борьба с конфликтами версий файлов проекта, обновлениями Windows, шумом и прочими банальными, но раздражающими вещами. Необходимость многократно тратить значительное время на такие неинтересные вещи снижает моральный дух, что, по крайней мере, не улучшит качество кода. В большой команде может быть один или несколько парней, основной задачей которых является поддержка инструментов разработчика.
  7. Принимая технологические решения, подумайте, что потребуется, чтобы переключить технологию; какие решения необратимы, а какие нет. Оцените необратимые решения очень тщательно. Например, если вы решили написать проект на Java , это довольно необратимое решение. Если вы решите использовать какой-нибудь самодельный двоичный формат для файлов данных, это также довольно необратимое решение (как только код выйдет в дикую природу, и вы должны продолжать поддерживать этот формат). Но цвета графического интерфейса пользователя можно легко отрегулировать, функции, которые изначально были исключены, могут быть добавлены позже, поэтому меньше внимания уделяйте таким вопросам.
Joonas Pulakka
источник
8
Это отличные моменты. Я должен признать, что я борюсь с «будь проще». Кажется, это означает разные вещи для разных людей в разных контекстах, что делает «простые» довольно сложными (но тогда у меня есть естественная склонность усложнять вещи).
Kramii
3
Я полностью согласен с вашими точками, особенно "KIS". Но я вижу тенденцию, что все больше (моложе?) Разработчиков используют довольно сложные структуры для описания даже самых простых контекстов.
chrmue
10
@chrmue: Смотрите «Как написать Факториал на Яве» ;-)
Joonas Pulakka
8
Хм, и "8. Будьте проще".
Дауд ибн Карим
7
№ 6 достоин +10.
Джим Г.
55

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

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

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

Tom Squires
источник
3
Очень важный момент. Я взял на себя устаревшую систему, много классов, много строк кода, никакой документации, никаких юнит-тестов. После тщательного создания модульных тестов для всех исправлений и улучшений кода, дизайн системы превратился в более чистое и более обслуживаемое состояние. И у нас есть «смелость» переписать существенные основные части (охваченные юнит-тестами).
Сэм Голдберг
40

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

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

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

maple_shaft
источник
Очень хороший момент, вы попали в глаза быков! Грустно сказать, но это именно то, что здесь происходит. И кажется невозможным изменить вещи без технического лидерства ...
chrmue
4
@chrmue Просто так, как я думаю, но я устаю от этого. Во многих отношениях мне бы хотелось, чтобы я снова стал младшим разработчиком, когда не знал, насколько все неправильно вокруг. Похоже, я нахожусь на раннем этапе кризиса. Но я болтаю ... рад помочь.
maple_shaft
1
@Murph Почему бы вам не иметь руководящего состава на этапе обслуживания? Каждый босс, которого я когда-либо ожидал, не ожидал ничего меньшего от лидера команды, и когда я был лидером команды, я не ожидал ничего меньшего от себя.
maple_shaft
1
@maple_shaft, потому что а) я не предполагаю, что есть руководитель команды, посвященный этому одному проекту, и это более или менее первое требование, и б) я думаю, что вам нужно понять дизайн и реализацию (все это), и это жесткий. С одной стороны, мы все утверждаем, что у нас не должно быть единого шрифта всех знаний в наших проектах, и все же здесь мы говорим, что у нас должен быть один? Это не складывается?
Murph
2
@maple_shaft, вероятно, я старый сварливый программист (-: Но есть проблема в том, что часто это «стиль» реализации, которому нужно следовать глубоко в существующей кодовой базе - и это может быть чуждо и кодеру, и ведущему (для многих реальных причин).
Мерф
18

Мы можем сделать несколько вещей:

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

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

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

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

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

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

Kramii
источник
1
+1, особенно за «создание команды, которая может хорошо работать вместе и на самом деле доставлять рабочий продукт».
deworde
1
Это хорошая идея, чтобы за архитектуру отвечал один человек. Однако если вы часто используете эту ответственность, у вас появляется «командный запах»: команда должна, естественно, прийти к общим выводам, а не полагаться на одного человека, который предоставит ответы. Почему? Общими знаниями о проекте всегда делятся, и в конечном итоге его закрепление за одним человеком приведет к более серьезным проблемам: удовлетворяется только его мнение, эффективно отсекающее крылья остальной части команды. Вместо этого наймите лучших людей и дайте им решить это вместе.
Каспер
1
@casper: Точно. Вы выражаете то, что я имел в виду, лучше, чем я.
Kramii
18

Способ, которым я решаю эту проблему, заключается в том, чтобы снять ее с корня:

Мое объяснение будет использовать термины из Microsoft / .NET , но будет применимо к любой платформе / панели инструментов:

  1. Используйте стандарты для именования, кодирования, проверок, потока ошибок, потока процессов - в основном все что угодно.
  2. Не бойтесь попрощаться с членами команды, которые не придерживаются стандартов. Некоторые разработчики просто не могут работать в рамках определенного набора стандартов и становятся врагами 5-го столбца на поле битвы, чтобы поддерживать чистоту базы кода
  3. Не бойтесь направлять на тестирование более опытных членов команды на длительные периоды времени.
  4. Используйте все инструменты в вашем арсенале, чтобы избежать проверки на гниение кода: это включает в себя специальные инструменты, а также предварительно написанные модульные тесты, которые проверяют файлы сборки, файлы проекта, структуру каталогов и т. Д.
  5. В команде из 5-8 человек, пусть ваш лучший парень занимается рефакторингом почти постоянно - убирая беспорядок, оставленный другими. Даже если вы найдете лучших специалистов в этой области, у вас все еще будет беспорядок - это неизбежно, но это может быть ограничено постоянным рефакторингом.
  6. Пишите модульные тесты и поддерживайте их - НЕ полагайтесь на модульные тесты, чтобы поддерживать чистоту проекта, они не зависят.
  7. Обсудить все Не бойтесь часами обсуждать дела в команде. Это распространит информацию и устранит одну из основных причин плохого кода: путаницу в технологиях, целях, стандартах и ​​т. Д.
  8. Будьте очень осторожны с консультантами, пишущими код: их код, почти по определению, будет настоящим дерьмом.
  9. Делать отзывы желательно как шаг процесса перед регистрацией. Не бойтесь отката коммитов.
  10. Никогда не используйте принцип открытия / закрытия, если только на последнем этапе перед выпуском: он просто приводит к тому, что гниющий код остается обонянием.
  11. Всякий раз, когда проблема заключена в единое целое, потратьте время, чтобы в полной мере понять ее, прежде чем внедрять решение - большая часть гнили кода исходит из реализации решения проблем, которые не полностью поняты.
  12. Используйте правильные технологии. Они часто бывают комплектными и свежими: лучше полагаться на бета-версию фреймворка, от которого вам гарантирована поддержка в будущем, чем полагаться на чрезвычайно стабильные, но устаревшие фреймворки, которые не поддерживаются.
  13. Нанимайте лучших людей.
  14. Увольняйте остальных - у вас нет кафе.
  15. Если менеджмент не самый лучший архитектор и он вмешивается в процесс принятия решений - найди другую работу.
casper
источник
1
Теперь, что бы вы сделали, если бы вам пришлось поддерживать и улучшать кошмарное 12-летнее приложение VB6 с сотнями форм и классов, работая над перепиской на C # в «свободное время»?
jfrankcarr
7
Не согласен с # 3. Тестирование не должно рассматриваться как наказание для неподготовленных. Фактически, это должно быть сделано всеми разработчиками и считаться столь же важным, как и кодирование и проектирование! Если в команде нет Мистера Неподготовленного, то выведите его из команды для тренировки !.
NWS
1
«Не согласен с №3. Тестирование не должно рассматриваться как наказание для неподготовленных». - Это не должно и не то, что я написал, позвольте мне объяснить: тестирование - это хороший способ дать людям, которым вы еще не доверяете, вносить изменения, чтобы войти в код. Лучшие тестеры, которых я нашел, - это те, кто стремится стать авторами кода и доказывают свою компетентность, просматривая код, запуская программу и демонстрируя способность соотносить свои результаты во время выполнения с исходным кодом. Это не наказание - это тренировка.
Каспер
1
«Не согласен с №10 - это помогает с качеством кода, если все сделано правильно». Это абсолютно неверно в моем опыте работы: заблокированный код не может быть реорганизован, то есть он будет оставаться в своем текущем состоянии, пока не будет разблокирован. Можно проверить, что это состояние работает на некоторой стадии, но на более поздней стадии эта проверка является ложноположительной: весь код должен оставаться открытым для рефакторинга вплоть до стадии перед финальным тестированием системы.
Каспер
3
@casper: ИМХО, принцип «открытый / закрытый» следует понимать не как «вы не можете изменить источник», а скорее «проектируйте код так, как он будет заморожен». Убедитесь, что вы можете расширить код как необходимый, не требуя внесения в него изменений. В результате получается более слабая связь и высокая согласованность, чем в среднем коде. Этот принцип также важен при разработке библиотеки для использования третьими лицами, поскольку они не могут просто войти и изменить ваш код, поэтому вам нужно, чтобы он был должным образом расширяемым.
Кевин Кэткарт
12

Очистите сгнивший код путем рефакторинга при написании модульных тестов. Выплачивайте (этот) долг за весь код, к которому вы прикасаетесь, когда вы:

  • Разработать новую функцию
  • Исправить проблему

Значительно ускорите цикл разработки в первую очередь с помощью:

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

Код рефакторинга для использования слабой связи (высоко внутренне связанных элементов) посредством:

  • Более простые (более) функции (процедуры)
  • Модули
  • Объекты (и классы или прототипы)
  • Чистые функции (без побочных эффектов)
  • Предпочитающее делегирование, а не наследование
  • Слои (с API)
  • Коллекции небольших одноцелевых программ, которые могут работать вместе

Органический рост это хорошо; большой авангардный дизайн - это плохо.

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

Читайте книги по рефакторингу.

оборота MarkDBlackwell
источник
1
+1 Хороший первый ответ, отличный способ представиться нам!
Яннис
11

Простой ответ: вы не можете .

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

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

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

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

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

Джох
источник
9

Я работаю над базой кода для продукта, который постоянно совершенствуется с 1999 года, так что, как вы можете себе представить, он сейчас довольно сложный. Самый большой источник хакерства в нашей кодовой базе - это многочисленные случаи, когда нам приходилось переносить его с ASP Classic на ASP.NET , с ADO на ADO.NET, с обратных передач на Ajax , переключения библиотек пользовательского интерфейса, стандартов кодирования и т. Д.

В целом мы проделали разумную работу по поддержанию поддерживаемой базы кода. Главные вещи, которые мы сделали, которые способствовали этому:

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

2) Сохраняйте аккуратную среду разработки - будьте бдительны в отношении удаления кода, который больше не используется, и не оставляйте резервные копии / рабочие копии / экспериментальный код в каталоге проекта.

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

JohnFx
источник
8

Так как вы пометили вопрос с управлением проектами, я попытался добавить некоторые не кодовые пункты :)

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

  • Последовательность / однородность не могут быть подчеркнуты достаточно. Это будет препятствовать культуре «иди в одиночку» и побудит новых разработчиков спросить, сомневаются ли они.

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

  • Документация - особенно архитектура - почему были приняты решения, и стандарты кодирования. Также сохраняйте ссылки / заметки / дорожные карты при документировании бизнес-домена - вы будете удивлены, насколько трудно корпоративному бизнесу объяснить, что они делают, разработчику без опыта работы с доменом.

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

  • Убедитесь, что архитектура и особенно слои кода четко разграничены и разделены - это потенциально позволит заменить слои кода по мере появления новых технологий, например, заменить интерфейс Web Forms на HTML5 jQuery UI и т. Д., Что может купить год или около того дополнительного долголетия.

StuartLC
источник
7

Одним из свойств кода с высокой степенью доступности является чистота функции .

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

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

Когда ваша функция чиста, ее тип сам по себе является очень хорошей документацией. Кроме того, написание и чтение документации с точки зрения аргументов / возвращаемого значения намного проще, чем упоминание некоторого глобального состояния (возможно, доступ к которому осуществляется другими потоками O_O).

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

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

Rotsor
источник
2
Другое название того, что вы описываете, - это свойство быть детерминированным
jinglesthula
6

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

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

Другой подход - заставить всех прочитать comp.risks и The Daily WTF, чтобы они узнали о последствиях плохого дизайна и плохого программирования, и они будут бояться увидеть свой собственный код, опубликованный на The Daily WTF .

джеймс
источник
6

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

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

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

Тем не менее, даже если у вас есть серьезные ограничения по времени, я считаю, что еще одна хорошая вещь, чтобы иметь в виду:

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

И мой личный любимый совет - больше цитата, хотя я не могу вспомнить источник:

«Кодируйте, как будто человек, который идет за вами, является психопатом-убийцей, который знает, где вы живете»

Aatch
источник
Я всегда находил полезными комментарии к функциям и классам, даже если они просто обеспечивают разделение сегментов кода в местах расположения функций и классов с помощью подсветки синтаксиса. Я очень редко помещаю комментарии в код функции, но пишу строку для каждого класса и функции, например, /** Gets the available times of a clinic practitioner on a specific date. **/или /** Represents a clinic practitioner. **/.
Ник Бедфорд
5

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

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

Просто мои 2 цента.

Джорджио
источник
Что если бизнес-требования, выраженные в рабочем коде, изменятся? Не трогайте плохо продуманный, но технически «работающий» код может нанести вам вред в долгосрочной перспективе, особенно когда приходит время вносить необходимые изменения.
Jinglesthula
@jinglesthula: «Открыть для расширения» означает, что вы можете добавить новую функциональность в качестве новой реализации (например, класса) существующего интерфейса. Конечно, плохо структурированный код не позволяет этого: должна существовать абстракция, подобная интерфейсу, который позволяет коду «изменяться» путем добавления нового кода вместо изменения существующего кода.
Джорджио
5
  • Будь разведчиком . Всегда оставляйте код чище, чем вы его нашли.

  • Исправить разбитые окна . Все эти комментарии «изменяются в версии 2.0», когда вы используете версию 3.0.

  • Когда есть серьезные хаки, разработайте лучшее решение в команде и сделайте это. Если вы не можете исправить взлом как команда, то вы недостаточно хорошо понимаете систему. «Попроси взрослого о помощи». Старейшие люди вокруг, возможно, видели это раньше. Попробуйте нарисовать или извлечь диаграмму системы. Попробуйте нарисовать или извлечь сценарии использования, которые особенно полезны в качестве диаграмм взаимодействия. Это не исправляет это, но по крайней мере вы можете видеть это.

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

  • Если вы объясните, как работает система (хотя бы один случай использования), и вам снова и снова придется извиняться за подсистему, это проблема. Какое поведение будет делать остальную часть системы проще (независимо от того, насколько сложно это реализовать по сравнению с тем, что есть). Классическая подсистема для перезаписи - это та, которая загрязняет каждую другую подсистему своей операционной семантикой и реализацией. «О, вы должны собрать значения перед тем, как передать их в подсистему froo, а затем снова отключить их при получении вывода из froo. Может быть, все значения должны быть сброшены при чтении из пользователя и хранилища, и остальная часть системы не так? Это становится более захватывающим, когда есть два или более различных grozification.

  • Проведите неделю в команде, удаляя предупреждения, чтобы увидеть реальные проблемы.

  • Переформатировать весь код в стандарт кодирования.

  • Убедитесь, что ваша система контроля версий привязана к вашей системе отслеживания ошибок. Это означает, что будущие изменения приятны и подотчетны, и вы можете решить ПОЧЕМУ.

  • Занимайтесь археологией. Найдите оригинальные проектные документы и просмотрите их. Они могут быть на этом старом компьютере в углу офиса, в заброшенном офисе или в шкафу, который никто никогда не открывает.

  • Переиздание проектной документации в вики. Это помогает институционализировать знания.

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

  • Попробуйте непрерывную интеграцию . Чем раньше вы получите неудачную сборку, тем меньше времени проект сможет потратить с рельсов.

  • Если руководитель вашей команды не делает этого, это плохо для компании.

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

  • Попробуйте выполнить модульное тестирование некоторых старых битов, которые не были протестированы. Это помогает сократить страх перемен.

  • Автоматизируйте интеграционные и регрессионные тесты, если можете. По крайней мере, есть контрольный список. Пилоты умны, им платят много, и они используют контрольные списки. Они также облажались довольно редко.

Tim Williscroft
источник
4

Прочитайте, а затем перечитайте Code Complete от Стива Макконнелла. Это похоже на библию хорошего написания программного обеспечения, от начального дизайна проекта до одной строки кода и всего, что между ними. Что мне больше всего нравится в этом, так это то, что он подкреплен десятилетиями надежных данных; это не просто следующий лучший стиль кодирования.

dwenaus
источник
3

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

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

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

jfrankcarr
источник
2

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

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

Люди не вводят хаки, потому что им это нравится; они вынуждены обстоятельствами.

Peter Mortensen
источник
Вынуждены обстоятельствами? Люди вводят хаки, потому что (а) они не знают лучше => нуждается в обучении, (б) они не видят более широкой картины => необходимы коммуникация, документация и дисциплина, (в) они думают, что они умнее => это самое большое Преодолеть препятствие (d), вызванное обстоятельствами => быстрые исправления в порядке, когда не хватает времени, но кто-то должен взять на себя ответственность и впоследствии очистить код. Любое другое «обстоятельство» - это просто БС . Из этого правила есть исключения, но большинство так называемых исключений означают «ленивый».
JensG
2

Я просто хочу поставить нетехническую проблему и (возможно) прагматический подход.

Если ваш менеджер не заботится о техническом качестве (управляемый код, простая архитектура, надежная инфраструктура и т. Д.), Становится сложно улучшить проект. В этом случае необходимо обучить указанного менеджера и убедить его «вкладывать» усилия в ремонтопригодность и решение технических проблем .

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

Или, если вы просто хотите приручить «проект Франкенштейна», вот мои советы:

  • Организовать и упростить
  • Сократить функции
  • Расставьте приоритеты читабельности по сравнению с эффективностью (когда это, конечно, приемлемо, а некоторые выигрыши в эффективности слишком убогие, чтобы их сохранить)

По моему опыту, программирование скорее энтропийно, чем эмерджентно (по крайней мере, в популярной парадигме с императивной структурой). Когда люди пишут код для «просто работы», возникает тенденция потерять свою организацию. Теперь для организации кода требуется время, иногда гораздо больше, чем просто заставить его работать.

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

Eric.Void
источник
«... проект обречен» - по моему опыту, это не обязательно так. Альтернатива состоит в том, чтобы обучить упомянутого менеджера и убедить его «вкладывать» усилия в ремонтопригодность и решение технических
комнат
Извините, я не мог заставить себя написать это, поскольку у меня уже был опыт, когда менеджер игнорировал все мои советы по поводу технических долгов. Но я думаю, что вы правы: примерно через год после того, как я отказался от этого проекта, менеджер потерял все свои полномочия над технической командой из-за своей неспособности управлять ими.
Eric.Void
1

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

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

Вы даже можете рассмотреть возможность совместного использования этих небольших независимых библиотек между многими проектами (подмодули git - ваши друзья).

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

Если вы используете C или C ++ и вам не нравится идея иметь много маленьких файлов .so, вы можете связать все библиотеки вместе в больший файл .so или, в качестве альтернативы, вы можете сделать статическое связывание. То же самое относится и к Java, просто измените .so на .jar.

juhist
источник
Это кажется слишком теоретическим с моей точки зрения. Конечно, проекты, которые я упоминал в своем вопросе, были построены из нескольких библиотек и модулей. Мой опыт за последние 26 лет разработки программного обеспечения состоял в том, что чем старше проект получает первоначальную организацию
17
0

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

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

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

Это не размер кодовой базы, которая усложняет обслуживание. Это размер кодовой базы, который необходимо поддерживать. Я использую миллионы строк кода, когда, скажем, использую API операционной системы. Но это не способствует затратам на обслуживание моего продукта, поскольку мне не нужно поддерживать исходный код операционной системы. Я просто использую код, и он работает. Код, который я просто использую и никогда не должен поддерживать, не требует никаких затрат на обслуживание с моей стороны.

оборота user204677
источник