В этом файле собрано несколько основных общих замечаний к решениям.
NIT пункты (от фразы nit peak) — это мелкие придирки, которые могут быть нерелевантны в конкретной реализации.
## Парсинг флагов
### Парсинг аргументов массивов
В решениях частов встречается
```golang
flagExclude = flag.String("exclude", "", "Globs to exclude")
exclude := strings.Split(*flagExclude, ",")
```
Для подобных аргументов, передаваемых через запятую можно использовать библиотеку `pflag` — альтернативу стандартному `flag`: https://pkg.go.dev/github.com/spf13/pflag#StringSlice
```golang
import "github.com/spf13/pflag"
flagExclude = pflag.StringSlice("exclude", nil, "Globs to exclude")
```
`flagExclude` сразу будет слайсом.
### NIT Имена флагов.
Обычно имена переменных начинаются с подстроки, описывающих их природу,
например `ErrNotFound` для ошибки, `flagVerbose` для флага
т.е. вместо
```golang
exclude = flag.String("exclude", "", "Globs to exclude")
restrictTo = flag.String("restrict-to", "", "Globs to restrict")
```
канонично было бы написать
```golang
flagExclude = flag.String("exclude", "", "Globs to exclude")
flagRestrictTo = flag.String("restrict-to", "", "Globs to restrict")
```
## NIT Импорты
В go обычно импорты сгруппированы в три группы
```
import (
stdlib
external deps
current module deps
)
```
Между группами должна быть пустая строка.
Внутри каждой группы импорты должны быть отсортированы. Это проверяет fmt линтер.
Вот так выглядят плохие импорты
```golang
import (
"flag"
"log"
"gitlab.com/slon/shad-go/gitfame/configs"
"gitlab.com/slon/shad-go/gitfame/internal"
"github.com/spf13/pflag"
"strings"
)
```
Вот так хорошие:
```golang
import (
"flag"
"log"
"strings"
"github.com/spf13/pflag"
"gitlab.com/slon/shad-go/gitfame/configs"
"gitlab.com/slon/shad-go/gitfame/internal"
)
```
## Структура проекта
Для такого маленького проекта, как наш было бы абсолютно нормально все файлы, включая `main.go`, парсинг блейма и вывод результата положить в корень репозитория.
Однако, мы специально предложили познакомится со [стандартным лэйаутом go проектов](https://github.com/golang-standards/project-layout) и разложить код в разные директории.
### Не нужно класть реализацию непосредственно в internal или pkg
В месте вызова использование пакета будет выглядет как-то так:
Часто встречается подобная конструкция с бесконтрольной параллелизацией:
```golang
ch := make(chan struct{}, len(files))
for _, file := range files {
go blame(file, ch)
}
```
На большом репозитории одновременно будет зашущено неопределённое количество горутин и подпроцессов.
Во-первых, каждая горутина требует сколько-то килобайт на стэк и потенциально может закончиться память.
Во-вторых, в OS есть ограничение на количество процессов + каждый процесс потребляет сколько-то системных ресурсов (ram, cpu) и суммарное потребление может оказаться неопределённо большим.
Вместо этого стоит явно ограничить количество одновременно запущенных горутин-воркеров, обрабатывающих blame, константой с небольшим дефолтом (8), либо дополнительно можно вынести степень параллелизации за флаг.
Прочитайте [пост в go блоге](https://go.dev/blog/pipelines) про типичные pipeline паттерны.
Можно сделать одного producer'а workload'а, который будет писать файлы для обработки в канал фиксированного размера, а`n` worker'ов будут читать из этого общего канала и обрабатывать файлы.