Как проектировать и управлять сложностью ПО?
==============================================

 Здравствуйте, интересует вопрос: как люди с опытом программирования планируют (и планируют ли) структуру будущей программы.  

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

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

Уверен, что наверняка существуют какие-то best practices в продумывании логики ПО и написании кода. Возможно есть какие-то подходы с помощью которых можно идти от простого к сложному, не теряя контроль над происходящим.  

Помогут ли в этом случае блок-схемы и UML-моделирование? Существует ли литература по данному вопросу?  

Интересует как вы боретесь со сложностью, а так же ссылки по теме.   

Спасибо 

 Я бы выделил два основополагающих подхода к решению этой (основной) проблемы разработки ПО:  

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

- Прагматичный: реализуй как можно проще необходимый минимум, обеспечивая возможность при необходимости (а она будет всегда) быстро изменять (улучшать) свой код. На мой взгляд наиболее удачная попытка формализовать и обобщить данный подход — это Test-Driven Development в самом общем виде (речь о синтезе "классического" TDD и Mockist-ского — aka Behavior-Driven Development — подходов). Мой личный выбор — именно TDD с небольшими вкраплениями наиболее ясных принципов из предыдущего пункта. 

 На все эти вопросы есть как минимум один ответ - экстремальное программирование.  

Ищите в поисковиках, материала очень много.  
  

p.s. по-поводу UML диаграмм. Помогут, но только как подсказка для решения какой-либо конкретной задачи.  

Не нужно воспринимать диаграмму как некую строгую документацию, которую нужно сначала разработать, а затем закодировать.  

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

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

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

Обо всём этом рассказывает экстремальное программирование и другие методики гибкой разработки. 

 Могу посоветовать прочесть книгу:  
[Совершенный код. С. Макконнелл](http://www.ozon.ru/context/detail/id/3159814/). 

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

 Лично мне очень хорошо помогает UML диаграмма. Но рисую я ее либо на witeboard либо в тетради. Не нашлось как-то удобного програмного инструмента. Да и на witebord постоянно перед глазами архитектура.