Как правильно оформить проект Go [закрыто]

113

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

Есть ли какие-нибудь хорошие примеры того, что имеет смысл?

aussiegeek
источник

Ответы:

132

Обновление от мая 2013 г .: официальная документация находится в разделе « Организация кода »

Код Go должен храниться внутри рабочего пространства .
Рабочее пространство - это иерархия каталогов с тремя каталогами в корне:

  • src содержит исходные файлы Go, организованные в пакеты (по одному пакету на каталог),
  • pkg содержит объекты пакета и
  • bin содержит исполняемые команды.

go toolСтроит исходные пакеты и устанавливают результирующие бинарники к pkgи binкаталогам.

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

bin/
    streak                         # command executable
    todo                           # command executable
pkg/
    linux_amd64/
        code.google.com/p/goauth2/
            oauth.a                # package object
        github.com/nf/todo/
            task.a                 # package object
src/
    code.google.com/p/goauth2/
        .hg/                       # mercurial repository metadata
        oauth/
            oauth.go               # package source
            oauth_test.go          # test source

Обновление от июля 2014 г .: см. « Структурирование приложений в Go » от Бена Джонсона.

В этой статье есть такие советы:

Отделите двоичный файл от приложения

объединение main.goфайла и логики моего приложения в одном пакете имеет два последствия:

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

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

camlistore/
  cmd/
    camget/
      main.go
    cammount/
      main.go
    camput/
      main.go
    camtool/
      main.go

Разработка на основе библиотеки

Перемещение main.goфайла из корня позволяет создавать приложение с точки зрения библиотеки. Бинарный файл вашего приложения - это просто клиент библиотеки вашего приложения.

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

adder/
  adder.go
  cmd/
    adder/
      main.go
    adder-server/
      main.go

Пользователи могут установить двоичные файлы вашего «сумматора» с помощью команды «go get» с многоточием:

$ go get github.com/benbjohnson/adder/...

И вуаля, у вашего пользователя установлены « adder» и « adder-server»!

Не сходите с ума с подпакетами

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

  1. Сгруппируйте связанные типы и код в каждом файле. Если ваши типы и функции хорошо организованы, я считаю, что файлы имеют размер от 200 до 500 SLOC. Может показаться, что это много, но мне легко ориентироваться. 1000 SLOC - это обычно мой верхний предел для одного файла.
  2. Организуйте наиболее важный тип в верхней части файла и добавьте типы по убыванию важности в нижней части файла.
  3. Как только ваше приложение начинает получать более 10 000 SLOC, вы должны серьезно оценить, можно ли его разбить на более мелкие проекты.

Примечание: последняя практика не всегда хороша:

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


(Альтернатива от февраля 2013 г., srcтолько относительно )
Вы можете найти классический макет, проиллюстрированный в « Макете кода GitHub »:

Приложение и обе библиотеки находятся на Github, каждая в собственном репозитории.
$GOPATHявляется корнем проекта - каждый из ваших репозиториев Github будет проверен несколькими папками ниже $GOPATH.

Макет вашего кода будет выглядеть так:

$GOPATH/
    src/
        github.com/
            jmcvetta/
                useless/
                    .git/
                    useless.go
                    useless_test.go
                    README.md
                uselessd/
                    .git/
                    uselessd.go
                    uselessd_test.go
                    README.md

Каждая папка ниже src/github.com/jmcvetta/является корнем отдельной проверки git.

Это вызвало некоторую критику на этой странице Reddit :

Я настоятельно рекомендую не структурировать репо так, как вы это делаете, это сломает " go get", что является одной из самых полезных вещей в Go.
Гораздо лучше писать код для людей, которые действительно знают Go, поскольку они, скорее всего, будут его компилировать.
А люди, которые этого не делают, по крайней мере, почувствуют язык.

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

Это всего лишь двухэтапный процесс для загрузки, сборки, установки и настройки:

  • " go get <your repo path>": загружает и устанавливает код перехода с подкаталогом для ресурсов.
  • $GOPATH/<your repo path>/setup.sh: распределяет активы в нужное место и устанавливает службу
VonC
источник
15
Одна (большая) проблема setup.shзаключается в том, что Go достаточно кроссплатформенный, тогда как сценарии оболочки POSIX - нет.
kostix
Структура jmcvetta не нарушит работу go get, поскольку бесполезный импорт бесполезен, go get установит оба с помощью go get ... / uselessd. Но я согласен с тем, что если бесполезна библиотека, специально созданная для бесполезных, имеет смысл хранить ее в одном репозитории git в качестве подпапки или братьев и сестер.
mna
@PuerkitoBio Я согласен. Мое обучение управлению версиями и компонентному управлению ( stackoverflow.com/a/933735/6309 ) ведет меня больше к одному компоненту на репо, отсюда и вторая часть этого ответа.
VonC
7

Я предполагаю, что под словом «проект» вы подразумеваете не пакет Go, а программное обеспечение, которое вы разрабатываете. В противном случае вы можете получить помощь здесь и здесь . Однако это не сильно отличается от написания пакетов для Go: используйте пакеты, создайте папку для каждого пакета и объедините эти пакеты в своем приложении.

Чтобы составить собственное мнение, вы можете посмотреть популярные репозитории Go на github: https://github.com/trending/go . Яркие примеры - Кэли и Зевс .

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

Немо
источник
@aussiegeek, я не эксперт по Go, но я успешно применил то, что nemo предложил в моем собственном коде - идея в том, что у вас могут быть модули в каталоге вашего проекта, вам просто нужно ссылаться на них, используя их полный префикс - относительный к $GOPATH/srcили используя их go get-столы имен.
kostix
doozerdне очень хороший пример, даже его тесты слабые.
Inanc Gumus
@InancGumus Я призываю вас предложить лучший пример.
nemo
увидеть это и это .
Inanc Gumus
1

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

FigmentEngine
источник
1
Вот как макет $GOROOT, а не код в src/<project>каталоге.
docwhat 02