Архитектура и бекенд14 мин

Структурата на един проект (1): стандартът, който не беше стандарт

От · основател и главен изпълнителен директор на Hábil ·

Най-популярното хранилище за структура на Go казва, че не е официално. Ръководството на Go иска cmd/ и internal/, а инструментът пази само internal/. С шаблон.

Структурата на един проект · част 1 от 7 · Go

Сценарий: героите и историята са измислени. Техническите данни и цитатите са с източник в края.

За 1 минута

  • Най-популярното хранилище за «стандартна структура» на Go (56,7 хиляди звезди към 22 октомври 2026 г.) казва в своя README, че не е официален стандарт и че за прост проект е прекалено [2][3].
  • Официалното ръководство на Go иска малко за един сървър: програмите в cmd/ и логиката в internal/ [1].
  • От папките, в които живее кодът ти, само internal/ поставя граница, която инструментът go налага: на практика друг модул не може да я импортира [6][7].
  • Тръгваш си с шаблон, който се клонира и тръгва от първия път, със скрипт, който доказва тази граница, като става червен, когато трябва.
  • За понеделник: отвори своето хранилище и попитай всяка папка какъв проблем решава днес. Тази, която не може да отговори, е излишна.

В тази статия

  1. Какво се случи в 23:40?
  2. Какво наистина иска ръководството на Go?
  3. Кои са петте най-чести грешки?
  4. Упражнение: можеш ли да направиш границата червена?
  5. Ключови изводи
  6. Какво следва?
  7. Шаблонът и курсът
  8. Какво прави Hábil?
  9. Източници

Какво се случи в 23:40?

Иван наследи програма от 300 реда, разпределена в четиринайсет папки, и нито една не му казваше къде да сложи нова функция.

Понеделник, 23:40. Празен офис, трети етаж.

Беше първият му ден като стажант по дуалната програма. Седми семестър, кафето изстинало от девет и една-единствена задача на таблото: «Проверителят да предупреждава, когато някоя услуга отговаря за повече от една секунда».

Проверителят беше програма на Go, която запитваше списък с услуги по HTTP и казваше кои отговарят. Беше я написал Родриго, предишният стажант, който си тръгна в петък, без да остави нищо освен хранилището.

Иван го клонира и остана загледан в екрана.

api/  assets/  build/  cmd/  configs/  deployments/  docs/
examples/  init/  internal/  pkg/  scripts/  test/  web/

Четиринайсет папки за около 300 реда Go. api/: един README.md, който казваше «тук отива договорът». web/: празна. deployments/: файл от 2019 г. за сървър, който вече не съществуваше. pkg/util: единайсет функции, които нямаха нищо общо помежду си.

Задачата беше малка. Десет реда, може би. Но къде? В pkg/util, до функция, която форматираше дати? В internal/? Имаше ли правила, или беше навик? README-то на Родриго казваше: «Стандартна структура на Go», с връзка.

Той я последва: golang-standards/project-layout, над 56 хиляди звезди. Иван си отдъхна. Щом толкова хора го ползваха, това трябваше да е стандартът. А във втория абзац на увода на README-то, с удебелен шрифт, откри нещо, което не очакваше:

«NOT an official standard defined by the core Go dev team» [2].

Не е официален стандарт на екипа на Go. Казва го самото хранилище.

Иван се облегна на стола. Щом стандартът не беше стандарт, коя част от тези четиринайсет папки наистина имаше значение?

В 23:58 писа на Лусия, техническата ръководителка. Отговорът дойде за две минути:

— От тези четиринайсет коя пази инструментът? Коя променя това, което командата go позволява да се импортира?

Иван отново погледна списъка. Нито една не изглеждаше да пази нещо.

— Не знам — написа.

— Една. Утре ще ти покажа коя и защо другите тринайсет са въпрос на мнение.

Какво наистина иска ръководството на Go?

За един сървър официалното ръководство на Go се побира в две папки: програмата в cmd/ и всичко останало в internal/.

Казва се Organizing a Go module [1] и върви от най-малкото към най-голямото, в седем случая: пакет, програма, едно от двете с помощни пакети, няколко пакета, няколко програми, пакети и програми заедно и накрая сървър. За последния случай казва две неща.

Първото: един сървър обикновено няма пакети, които други да импортират, затова логиката му отива в internal/ [1]. Второто: тъй като обикновено има много папки, които не са на Go, е добре програмите да се съберат в cmd/ [1].

Това е всичко. Не споменава pkg/; папките без Go, като api/ или web/, оставя на твоята преценка [1].

През 2021 г., в дискусия в същото хранилище, Ръс Кокс (Russ Cox) го каза по-кратко: минималният стандарт за хранилище на Go, което може да се импортира (такова, чийто код други импортират), е LICENSE и go.mod в корена, а кодът — където ти е удобно. «That's it. That's the "standard"», написа той [5]. И добави, че дори cmd/ не е задължителна [5].

Шаблонът на тази част, estructura-go, следва ръководството буква по буква:

estructura-go/
├── go.mod
├── README.md
├── LICENSE
├── LICENSE-CONTENIDO.md
├── cmd/
│   └── revisor/main.go          el programa: lee la configuración, arma y arranca
├── internal/
│   ├── servicio/                el vocabulario: Servicio, Estado. Sin red ni archivos
│   ├── revisar/                 consulta muchos servicios a la vez
│   ├── httpapi/                 rutas, JSON y errores
│   └── config/                  banderas, entorno y la lista de servicios
├── testdata/servicios.json
├── herramientas/probar-frontera.sh
└── .github/workflows/verificar.yml

Да минем папка по папка, и при всяка въпросът е един и същ: какъв проблем решава днес?

Защо програмата живее в cmd/?

main.go е тънък нарочно: ако нещо в него заслужава тест, мястото му вече не е там.

cmd/revisor/main.go чете конфигурацията, сглобява частите от internal/ и стартира сървъра. Не решава какво е здрава услуга, нито как се запитва. Защо толкова слаб? Защото main прекратява процеса с os.Exit и чете реалната среда: каквото остане там, остава без тест. Шаблонът използва функция ejecutar, която връща грешка, а тестът я извиква със свободен порт.

Втора програма, например нощна задача, би отишла в cmd/tarea-nocturna/ и би споделяла всичко от internal/.

Какво е специалното на internal/?

internal/ е единствената папка в дървото с граница, която инструментът go налага: кодът, който живее там, не може да се импортира отвън на дървото, което я съдържа; на практика — от друг модул.

Според документацията на командата go пакет в папка internal може да се импортира само от код, който споделя пътя над тази папка [6]. Ако модулът ти е github.com/tu-usuario/revisor, целият този модул може да ползва revisor/internal/servicio; чужд модул — не. Внимание: важи по път, не по модул. Модул с име github.com/tu-usuario/revisor/otro би могъл, и скриптът за границата използва точно този случай.

Налага го не езикът, а командата go. Бележките към изданието на Go 1.4 го казват така: езикът няма как да наложи това разграничение, а командата go въвежда механизъм за дефиниране на «internal» пакети [7]. От Go 1.5 важи за всяко хранилище [7][8].

А какво печели един сървър? Това, което никой отвън не импортира, го променяш, без да счупиш нищо на никого. Затова ръководството съветва в internal/ да остане колкото може повече [1].

А другите тринайсет папки на Иван? Нито една не решава кой кого импортира. Командата go третира различно две други имена, които не са в неговия списък. testdata/ тя игнорира [6].

vendor/ наистина затваря пътя: ако модул импортира нещо през пътя на vendor/ на друг, инструментът отговаря use of vendored package not allowed (измерено с Go 1.27.1). Но твоят код не отива там: тя пази копия на зависимостите ти, а go mod vendor я изтрива и я създава наново всеки път [20]. За твоя код границата е internal/.

Защо servicio/ не импортира никого?

Пакетът, от който всички зависят, не зависи от нито един, и затова не може да затвори цикъл.

internal/servicio/ дефинира Servicio (име, URL, времеви лимит) и Estado (какво е отговорила, колко се е бавила, защо се е провалила). Не отваря връзки, не чете файлове, не знае нищо за JSON. Всички пакети в internal/ го импортират, а той не импортира никого от проекта:

Защо servicio/ не импортира никого?
ПакетИмпортира
cmd/revisorconfig, httpapi, revisar
httpapirevisar, servicio
revisarservicio
configservicio
servicioникого от проекта

Не е естетика: спецификацията забранява пакет да импортира сам себе си, пряко или косвено [11]. Тъй като servicio не импортира никого, той не може да е част от цикъл. И тъй като останалите стрелки вървят само в една посока (cmd → httpapi → revisar → servicio), днес няма нито един.

Името също е важно: по конвенция пакетите имат имена с малки букви и от една дума [17]. servicio казва какво има вътре; models или types биха казали само от какъв вид е.

Къде отива интерфейсът?

Интерфейсът живее в пакета, който го използва, а не в този, който го имплементира.

revisar запитва много услуги наведнъж и за това му трябва някой, който да запита една. Декларира го точно там:

// Consultor es lo único que Todos necesita: alguien que consulte UN servicio y
// diga cómo lo encontró. Un método, y nada más.
type Consultor interface {
	Consultar(ctx context.Context, s servicio.Servicio) servicio.Estado
}

func Todos(ctx context.Context, c Consultor, servicios []servicio.Servicio, paralelo int) []servicio.Estado

Реалното запитване е конкретен тип, *revisar.HTTP, който изпълнява този интерфейс, без да го декларира. Дублиращият обект за тестове, consultorFalso, живее в _test.go и не пътува с програмата.

Така го изисква Go Code Review Comments, ръководството за ревю на самия проект: по правило интерфейсите са в пакета, който използва стойностите, а не в този, който ги имплементира [10]. Това е грешка 4 по-долу.

А HTTP вратата?

httpapi само превежда: от заявка към извикване и от резултат към JSON.

Има три маршрута: GET /salud, GET /servicios и GET /servicios/{nombre}, с маршрутизатора на стандартната библиотека. От Go 1.22 net/http разбира метода и заместващите символи в шаблона и на POST отговаря с 405 Method Not Allowed, с валидните методи в заглавката Allow [12]. Измерено в шаблона: Allow: GET, HEAD.

Грешките, които пише шаблонът, излизат във формата на RFC 9457, Problem Details [13]; тези, които маршрутизаторът връща сам, като този 405 или несъществуващ маршрут, излизат като обикновен текст (измерено). Без собствен тип грешка се използва about:blank, а заглавието е стандартната фраза на кода, като «Not Found» [13]:

HTTP/1.1 404 Not Found
Content-Type: application/problem+json

{"type":"about:blank","title":"Not Found","status":404,"detail":"No hay ningún servicio llamado \"nomina\".","instance":"/servicios/nomina"}

Още нещо, защото един шаблон учи и на лоши навици: URL адресът на всяка услуга излиза без потребител, парола и параметри. https://usuario:clave@... или ?token=... носят тайна, а каквото излезе през API, стига до чужди логове. Конфигурацията отхвърля първото, а вратата изчиства второто, всяко със собствен тест. Пътят обаче излиза, защото казва какво се проверява: токен, пъхнат в пътя, би бил публикуван изцяло.

Какво е testdata/ и защо не пречи?

Командата go игнорира папките с име testdata: те са мястото за помощните данни.

Така папката остава на разположение за данните, които тестовете ползват [6]. В шаблона пази servicios.json, списъка от примера, и един тест го валидира: ако някой го счупи, разбира преди първия читател.

И къде отиват десетте реда на Иван?

Правилото отива в домейна; вратата само го публикува.

«Да предупреждава, ако услуга се бави повече от една секунда» има две части. Да се реши какво е бавно е речник на програмата, също като да се реши какво е здраво: отива в servicio, като метод на Estado до OK(), и тестът му не се нуждае от мрежа. Да се съобщи навън е работа на httpapi: още едно поле в неговия JSON. Ако секундата трябва да се променя без прекомпилиране, config я чете. Никаква нова папка.

Във вторник Иван написа Lento() в servicio, теста към него и едно поле в httpapi. Десет реда, както си мислеше. Нито един в pkg/util.

Как да знам, че границата съществува?

Защото CI я чупи нарочно при всяка промяна и изисква инструментът да я отхвърли.

Правило, което никой не проверява, е правило, за което никой не знае дали още е живо. Затова шаблонът носи herramientas/probar-frontera.sh, с два експеримента във временна папка:

  1. Контрола. Модул, чийто път започва като този на шаблона (…/estructura-go/control), импортира internal/servicio. Правилото важи по път, затова го пропуска: трябва да се компилира. Ако не се компилира, експериментът е сглобен грешно и скриптът спира на червено.
  2. Нарушение. Модул с чужд път (ejemplo.com/intruso) импортира същия пакет, по същия начин. Трябва да се провали, и то със съобщението на правилото.

Това е реалният изход:

1/2 control: github.com/HabilMX/estructura-go/control importa github.com/HabilMX/estructura-go/internal/servicio
   ✅ compiló: con la misma ruta de arriba, la regla lo deja pasar
2/2 violación: ejemplo.com/intruso importa github.com/HabilMX/estructura-go/internal/servicio
     package ejemplo.com/intruso
     	main.go:3:8: use of internal package github.com/HabilMX/estructura-go/internal/servicio not allowed
   ✅ la herramienta go lo rechazó por la regla de internal/
✅ frontera: se sostiene

Защо контролата? Защото експеримент, който очаква само червено, става «зелен» и когато се провали по грешната причина, например заради грешно написан път. Контролата търси пакета по същия начин като нарушението, така че счупена настройка прави червена нея (проверихме го, като счупихме пътя).

А нарушението изисква точното съобщение на правилото, не какъв да е провал. Между двете стъпки се променя само кой импортира: правилото е доказано от двете страни.

CI в GitHub пуска този скрипт заедно с gofmt, go vet, тестовете с детектора за състояния на състезание (race detector) и компилирането на cmd/, при всяка промяна, ръчно и всеки понеделник, в случай че нова версия на Go счупи нещо. Ако хранилището остане 60 дни без активност, GitHub изключва понеделнишкото изпълнение и трябва да се включи отново [21].

Кои са петте най-чести грешки?

Първите три идват от това папката да се създаде преди проблема, който решава; последните две — от поставянето на кода от грешната страна на стрелка.

1. Копиране на golang-standards/project-layout в малък проект

Самото хранилище не го препоръчва за това.

README-то казва, че ако учиш Go или правиш доказателство на концепция или прост проект, тази структура «is an overkill» [2]. И препоръчва да започнеш с main.go и go.mod [2]. Хранилището има 19 папки в корена [3]. Да ги копираш всичките значи да наследиш деветнайсет въпроса без отговор, както стана с Иван.

2. Създаване на pkg/ по навик

Официалното ръководство не го споменава, а Ръс Кокс посочи, че огромното мнозинство от екосистемата не го ползва.

В issue #117 на това хранилище, на 9 април 2021 г., Ръс Кокс написа, че «the vast majority of packages in the Go ecosystem do not put the importable packages in a pkg subdirectory» [4]. Официалното ръководство не използва pkg/ в нито един пример [1]. А един сървър обикновено няма какво да експортира, затова логиката му отива в internal/ [1].

3. Пакети util, common или misc

Име, което не казва какво има вътре, се превръща в чекмедже, в което пада всичко.

Блогът на Go го обяснява в Package names: «Packages named util, common, or misc provide clients with no sense of what the package contains» [9]. С времето те трупат зависимости и забавят компилирането [9]. Go Code Review Comments добавя api, types и interfaces [10]. Изходът: раздели чекмеджето и кръсти всяка част според това, което прави (fecha, notificar).

4. Деклариране на интерфейса там, където се имплементира, «заради mock-овете»

Интерфейсът е от страната на този, който го използва; от страната, която имплементира, се връща конкретен тип.

Go Code Review Comments го казва направо: «Do not define interfaces on the implementor side of an API “for mocking”» [10]. И иска да не се декларира, преди да се използва: без реална употреба не се знае какви методи му трябват [10]. В шаблона revisar декларира Consultor, защото го използва, а дублиращият обект живее в _test.go.

5. Разделяне по слоеве, докато се затвори цикъл

Ако models има нужда от нещо от services, а services импортира models, програмата спира да се компилира.

Случва се с папките по слоеве (handlers/, services/, models/): рано или късно долният има нужда от нещо от горния. Спецификацията го забранява [11], а go build го казва така (измерено):

package ejemplo.com/capas/models
	imports ejemplo.com/capas/services from models.go
	imports ejemplo.com/capas/models from services.go: import cycle not allowed

Обратната крайност също не помага: Андрю Джеранд (Andrew Gerrand) предупреждаваше през 2012 г., че разделянето на твърде малки пакети те оставя заседнал в проектиране на интерфейси, вместо да довършиш работата [16]. Изходът на шаблона: домейн пакет, който не импортира никого, и стрелките — към него.

5. Разделяне по слоеве, докато се затвори цикъл
ГрешкаКакво я издаваИзточник
1. Копиране на целия layoutПразни папки или папки с един-единствен файл[2]
2. pkg/ по навикСървър с pkg/, който никой не импортира[1][4]
3. util, common, miscФункции, които нямат нищо общо помежду си[9][10]
4. Интерфейс от страната, която имплементираИнтерфейс с една-единствена имплементация и Mock до него[10]
5. Слоеве, които се импортират взаимноimport cycle not allowed[11]

Упражнение: можеш ли да направиш границата червена?

Ще счупиш границата нарочно и инструментът сам ще ти каже дали си успял.

Трябват ти Go 1.27 или по-нов (go version), Git и bash, около 20 минути. Ако системата ти идва с по-стар Go, както хранилищата на Linux Mint, инсталирай го от go.dev [22]. Linux и macOS вече имат bash; в Windows използвай WSL или Git Bash.

Стъпка 1. Клонирай и провери, че всичко е зелено.

git clone https://github.com/HabilMX/estructura-go
cd estructura-go
go test ./...
bash herramientas/probar-frontera.sh

Какво трябва да видиш: пет реда, които започват с ok, и накрая ✅ frontera: se sostiene.

Стъпка 2. Предвиди, преди да пипаш. Запиши какво става, ако преименуваш internal/ на interno/ и поправиш импортите. Компилира ли се? Какво казва скриптът?

Стъпка 3. Преименувай и поправи импортите.

Копирай само реда със sed за твоята система: този на macOS иска празен аргумент след -i.

mv internal interno

# En Linux:
grep -rl 'estructura-go/internal/' --include='*.go' . | xargs sed -i 's#estructura-go/internal/#estructura-go/interno/#'

# En macOS:
grep -rl 'estructura-go/internal/' --include='*.go' . | xargs sed -i '' 's#estructura-go/internal/#estructura-go/interno/#'

go build ./...

Ако go build не каже нищо, компилирало се е: програмата няма нужда от internal/, за да работи.

Стъпка 4. Пусни скрипта.

bash herramientas/probar-frontera.sh

Трябва да излезе червено, но виж кое:

❌ el control NO compiló; el experimento está mal montado:

Скриптът още търси internal/servicio, който вече не съществува, и отказа да ти даде зелено. Това е контролата в действие.

Стъпка 5. Насочи скрипта към новия пакет. Отвори herramientas/probar-frontera.sh, намери реда, който започва с paquete=, и смени internal с interno. Пусни скрипта отново:

❌ COMPILÓ: otro módulo pudo importar github.com/HabilMX/estructura-go/interno/servicio. La frontera no existe.

Сега вече да: чужд модул импортира кода ти и никой не го спря. С друго име папката е просто папка.

Стъпка 6. Върни всичко.

git checkout -- . && git clean -fd
bash herramientas/probar-frontera.sh

Внимание: git clean -fd изтрива и новите файлове, които си създал там, например бележките си.

Как да знаеш, че си се справил: видял си три различни изхода в четири пускания, в този ред: зелено в стъпка 1, червено «el control NO compiló» в 4, червено «COMPILÓ» в 5 и пак зелено в 6. Ако в стъпка 5 се повтори «el control NO compiló», редът paquete= не е останал с interno (или не си записал). Ако излезе зелено, internal/ още съществува: прегледай стъпка 3.

За по-нататък (по желание): добави в servicio функция, която използва нещо от revisar. Преди да компилираш, предвиди съобщението. После го сравни с това от грешка 5.

Ключови изводи

Три въпроса, които да зададеш на своето хранилище тази седмица.

  1. За всяка папка в корена: какъв проблем решава днес? Ако отговорът е «за всеки случай, някой ден», изтрий я и го отбележи в README-то.
  2. Ако друг екип импортира кода ти утре, кои пакети би му позволил да ползва? Всичко останало в internal/ ли е?
  3. Кой е пакетът ти, от който всички зависят? Импортира ли нещо от проекта? Ако импортира, там е следващият цикъл.

Какво следва?

В Go границата я пази инструментът. В Python я пази инсталацията и е лесно да не забележиш, докато не гръмне.

Три дни по-късно Иван вече местеше папки без страх. Тогава му се падна проект на Python. Тестовете — зелени. Колежката му инсталира пакета: ModuleNotFoundError.

Файлът съществуваше. Беше в папката. Тестовете го намираха. Но никога не беше влизал в пакета.

Как минава тест върху код, който не съществува за този, който го инсталира? В част 2: папка, наречена src/, и защо тя променя всичко.

Шаблонът и курсът

  • Шаблон: github.com/HabilMX/estructura-go. Използва се като шаблон в GitHub или се клонира [19]. README-то обяснява всяка папка, какво не съдържа, кога да добавиш всяко нещо и как да махнеш примера. Кодът е под MIT; текстът и обясненията — под CC BY-SA 4.0.
  • Версии: go.mod изисква Go 1.27, версията, излязла през август 2026 г. [15]. Тестван е с Go 1.27.3, най-новата стабилна версия към 22 октомври [14], и ползва само стандартната библиотека. CI взема версията от go.mod и търси най-новата корекция на 1.27 [18].
  • Курсът по Go на Hábil: ако internal/, пакетите или табличните тестове са нови за теб, урок 5 ги обяснява от нулата: Курс по Go · Урок 5, Модули и тестове.

Пиша от това, което виждаме всеки ден в Hábil, където изграждаме системи за банки, застраховане и компании в Мексико. Ако в работата или в университета ти и колегите ти попаднете на хранилище, за което никой не знае откъде да го хване, да поговорим: habil.mx

Какво прави Hábil?

Учим на програмиране със същото, с което изграждаме: тестван, обяснен и отворен код.

Тази поредица идва от същото място като нашите курсове. Курсът по Go води от нулата до писането на добра програма и го публикуваме отворено, с лиценз Creative Commons; урок 5 обяснява модулите, пакетите и тестовете, които използва шаблонът от тази статия. А в каталога има още курсове по програмиране, безплатни и с тестван и обяснен стъпка по стъпка код.

Разгледай Курса по Go и каталога Курсове по програмиране.

Ако екипът ти наследи система, за която никой не знае откъде да я хване, или трябва да изгради такава, която да може да се поддържа и занапред, правим и това: разгледай Изграждане на система по поръчка. Поискай първи разговор, без заплащане. В него преглеждаме дали си струва да се настрои това, което екипът ти вече има, да се ползва продукт или да се изгради, и какво би получил екипът във всеки случай. Пиши ни в WhatsApp.

Източниците са консултирани на 22 октомври 2026 г. Цитатите на английски са възпроизведени без промяна, без курсива и удебеляването на оригинала.

Източници

  1. Go Team, «Organizing a Go module», go.dev. https://go.dev/doc/modules/layout
  2. golang-standards, «Standard Go Project Layout» (README), GitHub. https://github.com/golang-standards/project-layout
  3. GitHub, данни за хранилището golang-standards/project-layout (56 702 звезди; 19 папки в корена; първо място по звезди при търсене на «go project layout», 812 резултата, следващото с 954), измерени на 22 октомври 2026 г. https://api.github.com/repos/golang-standards/project-layout
  4. Russ Cox, «this is not a standard Go project layout», issue #117, 9 април 2021 г. https://github.com/golang-standards/project-layout/issues/117
  5. Russ Cox, коментар в issue #117, 28 април 2021 г. https://github.com/golang-standards/project-layout/issues/117#issuecomment-828503689
  6. Go Team, «Command go»: «Internal packages» и «Test packages», pkg.go.dev. https://pkg.go.dev/cmd/go
  7. Go Team, «Go 1.4 Release Notes»: «Internal packages», go.dev. https://go.dev/doc/go1.4
  8. Go Team, «Go 1.5 Release Notes», go.dev. https://go.dev/doc/go1.5
  9. Sameer Ajmani, «Package names», The Go Blog, 4 февруари 2015 г. https://go.dev/blog/package-names
  10. Go Team, «Go Code Review Comments»: «Interfaces» и «Package Names», go.dev. https://go.dev/wiki/CodeReviewComments
  11. Go Team, «The Go Programming Language Specification»: «Import declarations» (версия go1.27, 26 май 2026 г.). https://go.dev/ref/spec#Import_declarations
  12. Jonathan Amsterdam, «Routing Enhancements for Go 1.22», The Go Blog, 13 февруари 2024 г. https://go.dev/blog/routing-enhancements
  13. M. Nottingham, E. Wilde и S. Dalal, «RFC 9457: Problem Details for HTTP APIs», IETF, юли 2023 г. https://www.rfc-editor.org/rfc/rfc9457
  14. Go Team, изтегляния на Go (актуална стабилна версия: go1.27.3). https://go.dev/dl/
  15. Go Team, «Go 1.27 Release Notes», go.dev. https://go.dev/doc/go1.27
  16. Andrew Gerrand, «Organizing Go code», The Go Blog, 16 август 2012 г. https://go.dev/blog/organizing-go-code
  17. Go Team, «Effective Go»: «Package names», go.dev. https://go.dev/doc/effective_go#package-names
  18. GitHub, «actions/setup-go» v5, README. https://github.com/actions/setup-go/blob/v5/README.md
  19. GitHub Docs, «Creating a template repository». https://docs.github.com/en/repositories/creating-and-managing-repositories/creating-a-template-repository
  20. Go Team, «Go Modules Reference»: «Vendoring», go.dev. https://go.dev/ref/mod#vendoring
  21. GitHub Docs, «Disabling and enabling a workflow». https://docs.github.com/en/actions/how-tos/manage-workflow-runs/disable-and-enable-workflows
  22. Go Team, «Download and install», go.dev. https://go.dev/doc/install

Вашата дейност среща ли тези предизвикателства?

Да обсъдим вашия проект

Предпочитате имейл? Пишете ни на hola@habil.mx