Удивительно, но я сам недавно думал над этими проблемами (видимо многие идеи витают в воздухе и считываются из ноосферы).
По пунктам распишу о чем думал:
1) Одной из ранних методологий программирования, которая была призвана решить "кризис программирования" была методология структурного программирования. Структурное программирование можно охарактеризовать тремя вещами: разработка сверху вниз, использование только структурных переходов и доказательство корректности системы на каждом шаге декомпозиции (формальное или неформальное).
В те годы во многих книгах по программированию обсуждается проблема того, как лучше разрабатывать модули системы сверху вниз или же снизу вверх. Недостатками метода сверху вниз является то, что каждый модуль декомпозиции является частью решения именно этой задачи и может не подойти для решение почти такой же, но немного другой задачи. Также проблемой является изменение спецификаций, если какие-то требования меняются, то это может повлечь изменение многих дочерних модулей.
Метод разработки снизу вверх использовался Дейкстрой при разработке операционной системы THE. У метода снизу вверх есть преимущество, что низ лежащие компоненты могут быть довольно универсальными и использоваться в различных проектах. Но при интеграции различных компонент в единое целое могут возникать проблемы с тем, что что-то плохо стыкуется и так далее.
Также в книгах, где затрагивается тема тестирования, обсуждается то, как лучше тестировать: сверху вниз или снизу вверх. Если тестировать сверху вниз, то низ лежащие модули надо заменить на заглушки, но преимущество в том, что уже с самого начала тестируется целая система пусть и с некоторыми заглушками. При тестировании снизу вверх преимущество в том, что можно тестировать сразу полноценный низ лежащий слой (например, вывод в лог или на экран или в консоль и т.д.) и не нужно писать заглушек для тестирования системы.
Затем пришла эра объекто-ориентированного программирования и многие эти темы стали малоактуальными. Вопрос про то, как лучше разрабатывать сверху вниз или снизу вверх по сути отпал, так как объектно-ориентированные системы могут представлять собой сеть или граф взаимозависимых объектов (например, шаблон MVC). Начали обсуждать вопросы шаблонов проектирования: как лучше организовать эти объекты. А вопрос доказательства программы стали умалчивать, так как было не понятно, как вообще можно что-либо доказывать с этими наследованиями, полиморфизмами и так далее. Барбара Лисков получила Тьюринговскую премию за то, что сформулировала принцип подстановки. Простыми словами, который можно сформулировать так, что при полиморфизме новый метод должен обладать не более сильным предусловием, чем исходный метод (иначе данный метод может упасть, если ему передать значение, которое не входит в его предусловие, но входило в предусловие его предка) и не более слабым постусловие (иначе может упасть вызывающая программа, так как может не принять результаты, которые возвращает данный метод). Но на практике мало кто применяет этот принцип и, соответственно, практически не используется для доказательства, так как при полиморфизме многие не следуют этому принципу, а по сути используют полиморфизм, как некий goto, который позволяет перейти в другое место и сделать что-то совершенно отличное от того, что делал родительский метод.
Горбунов-Посадов в книге "Расширяемое программирование" говорит о том, что метод сверху вниз является по сути анализом, а снизу вверх - синтезом. Анализ и синтез - это основные инструменты логического мышления человека и оба важны, поэтому надо анализировать как систему декомпозировать, а затем уже синтезировать. Этим он как бы примиряет оба метода и снизу вверх и сверху вниз.
2) Горбунов-Посадов в книге "Расширяемое программирование" затрагивает еще более высокоуровневые вопросы, например, как выделять вариант. Допустим, у нас есть несколько вариантов каких-то алгоритмов, например, у нас есть такой сборщик мусора и другой сборщик мусора и мы хотим иметь возможность довольно просто переключаться между ними. Также он говорит про разные варианты таких переключений, один из вариантов - это цепочечный подход, когда от порядка перечисления чего-либо, мы имеем различные варианты (например в BlackBox, при создании exe мы можем указать порядок включения модулей и соответственно порядок инициализации модулей, от этого порядка может зависеть то, какие функции будут инсталлированы и будут выполняться). Сам он говорит, что цепочечный подход не очень хорош, так как есть вероятность совершить ошибку и при небольшом изменении нужно переписать всю цепочку. Он также говорит, про задачу сокращения записи, что надо стремиться к тому, чтобы общие подвыражения не переписывать, а описывать только то, что поменялось.
3) Лично я считаю, что расположение модулей в системе должно быть не одноуровневым и не двухуровневым, а многоуровневым, как дерево (аналогия с методами сверху вниз и снизу вверх). Можно привести аналогию с языком Oberon-07 (и другими Oberon-нами), где разрешены вложенные подпрограммы. В Oberon-07 есть правило, что вложенная подпрограмма может обращаться к своим локальным переменным или же к переменным глобального уровня. Думаю, что что-то типа этого правила можно ввести и для модулей, что модули внутри какой-то папки (подсистемы) могут обращаться к модулям глобального уровня, своего уровня и своего дочернего уровня (но не к подмодулям дочернего уровня). Также нужно продумать то, как легко можно переключаться между вариантами реализации. Думаю, что можно создать один модуль интерфейса, который в IMPORT подключает один из вариантов модуля реализации. Таким образом, можно будет легко менять вариант реализации. Списки модулей, которые надо включить для сборки проекта должны включаться внутрь каждой подсистемы, чтобы на верхнем уровне указывать только включаемые подсистемы, а их списки подмодулей подключатся автоматически.
Пока это еще не завершенная идея, возможно, что-то здесь не совсем хорошо, надо еще думать над этим.