Плюсы и минусы Go отклоняют неиспользуемые зависимости

Новый язык Google Go пытается облегчить управление зависимостями явно требуя, чтобы все зависимости, перечисленные в модуле, фактически использовались. Компилятор отклонит модуль, объявляющий зависимость от модуля, не используя ничего из этого модуля.

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

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

Есть ли у вас опыт работы с другими языками, соблюдающими это? Каковы плюсы и минусы этого подхода?

Ответ 1

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

Они раздражают. Но это сделает других счастливыми, потому что они получают чистый код.

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

Ответ 2

Я предполагаю, что самая большая мотивация для этого и самый большой результат - это улучшение во время компиляции. Техническое предварительное видео сделало основной момент их способности составлять большие объемы кода за короткие промежутки времени (их пример составлял 200 000 строк кода за 8 секунд на MacBook - никаких спецификаций машины).

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

Вот пример того, как что-то будет работать в текущей системе C/С++:

Класс A определен в файле заголовка C_H и реализован в C_CPP. Класс B происходит от C и реализуется в файлах B_H и B_CPP. Класс A происходит от B и реализуется в файлах A_H и A_CPP.

Из-за цепей деривации A_CPP включает A_H, B_H и C_H. B_CPP включает B_H и C_H. C_CPP включает C_H. Из-за характера препроцессора C, который по существу превращает операцию #include в операцию вырезания и вставки, содержимое C_H запускается через компилятор 3 раза, а B_H запускается дважды.

Кроме того, содержимое A_CPP, B_CPP и C_CPP все живут в своих объектных файлах. Следовательно, когда компоновщик переходит к решению A.o, он вынужден загружать и обрабатывать как B.o, так и C.o. Кроме того, когда он разрешает B.o, он должен снова обрабатывать C.o.

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

Go подходит к вещам по-разному. В словах прямо из PDF из их технического обсуждения:

"Компилятор Go переводит транзитивный информация типа зависимостей от объекта файл - но только то, что ему нужно. Если A.go зависит от B.go зависит от C.go: - скомпилировать C.go, B.go, затем A.go. - для компиляции A.go компилятор читает B.o not C.o. В масштабе это может быть огромным убыстрение".

ОК, делается небольшая касательная. Почему это имеет значение? Ответ также находится в Go Tech Talk PDF:

"Модель пакета: Явные зависимости для обеспечения более быстрой сборки".

Я предполагаю, что разработчики Go пришли к выводу, что, когда время компиляции измеряется за считанные секунды, даже для очень больших проектов, более эффективный для разработчиков сохранить короткие сроки компиляции. Скажем, мне требуется 8 секунд для компиляции 200 000 строк кода и выясните, что у меня есть внешний импорт пакетов, 5-10 секунд (с хорошей IDE или хорошее знакомство с вашей средой dev), чтобы найти его и исправить, и еще 8 секунд, чтобы перекомпилировать. Назовите это 30 секунд всего - и теперь все мои будущие компиляции остаются в 10-секундном диапазоне. Или мы можем позволить нашему модулю расти за счет включения ненужных зависимостей и следить за тем, чтобы время компиляции увеличивалось с 8 до 10, 12 или 15 секунд. Это не похоже на то, потому что мы все привыкли составлять время порядка минут, но когда вы начинаете понимать, что это ухудшение производительности на 25%, вы остановитесь и подумайте об этом в течение минуты.

Время компиляции Go уже молниеносно. Считайте также, что скорости процессора все еще растут (если не так сильно, как в прошлом) и что количество доступных ядер также увеличивается (а компиляция больших объемов кода хорошо подходит для многопоточности). 200 000 строк кода за 8 секунд сегодня означают, что неразумно представить 200 000 строк кода, составляющих практически мгновенно через 10 лет. Я думаю, что команда Go сделала сознательное решение здесь, чтобы сделать время компиляции ушедшим в прошлое, и хотя проблема, которую вы поднимаете, является лишь малой частью этого, она все еще является частью этого.

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

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

Ответ 3

Как уже упоминалось yuku, если у вас есть IDE, совместимая с тем, что Netbeans и Eclipse могут делать для java, вам действительно не нужно заботиться об этом.

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

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

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

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