На моей первой программистской работе использовался Паскаль. Он позволяет решить проблему циклических связей между модулями так: модуль делится на две части, интерфейс и реализацию.
Для интерфейса и реализации отдельно задаётся импорт, т.е. перечень ссылок.
Интерфейсы ссылаются друг на друга, образуя дерево. Реализации могут ссылаться друг на друга, образуя произвольный граф.
И - вуаля! Нет проблемы циклических ссылок. Система сама понинает, что в каком порядке собирать, функции из разных модулей могут вызывать друг друга.
Примерно то же самое, но более мощное, и более грязное, мы видим в С. Роль интерфейса играет заголовочный файл. Заголовочные файлы включаются друг в друга, образуя дерево. В теле файла *.c можно писать что угодно. Так реализации могут циклически ссылаться друг на друга.
Линкер решает проблему ссылок, собирая циклический граф вызовов функций.
В CL, Python и Golang я не вижу этого механизма. Точно могу сказать за CL, что этого механизма нет. Нужно вручную выделять часть, образующую цикл и выносить её в отдельный пакет. В Питоне пишут про какие-то «хаки». В Go предлагают объединить весь код в один модуль или вынести общий интерфейс вверх по иерархии. То, что раньше делал компьютер, нужно делать руками.
Производительность труда разработчика снизилась.
В ИТ отрасли произошла деавтоматизация. А казалось бы, компьютер придуман, чтобы автоматизировать труд, в т.ч. труд разработчика.
Что не так со мной? Или не со мной?