/
Praxis/

Доменные модели и конфигурация

Контекст

Прежде чем обращаться к внешнему API, нужно определить, как данные будут представлены внутри приложения. Доменные модели описывают «что» хранится (температура, город, время), но не «откуда» и «как» данные получены. Если завтра вместо Open-Meteo понадобится другой погодный сервис — модели останутся прежними, изменится только адаптер.

Также на этом этапе нужно научить приложение сохранять настройки между запусками. Город по умолчанию будет храниться в YAML-файле — при следующем запуске программа подхватит его автоматически.

Ключевая концепция: Доменные модели

— структура данных, описывающая бизнес-сущность приложения. Она не содержит логики получения данных, не знает про HTTP или JSON. Это внутренний контракт: любой провайдер погоды заполняет одну и ту же структуру.

type Weather struct { City string Temperature float64 Condition string UpdatedAt time.Time }

💡 Gotcha: Не добавляйте json-теги в доменные модели. JSON-теги нужны только структурам, которые непосредственно десериализуются из ответа API. Доменные модели заполняются вручную в коде маппинга.

Ключевая концепция: YAML для конфигурации

— формат хранения настроек, удобный для чтения и редактирования. Пакет gopkg.in/yaml.v3 позволяет маппить YAML-поля на поля структуры через теги.

type Config struct { DefaultCity string `yaml:"default_city"` } data, _ := os.ReadFile("config.yaml") var cfg Config yaml.Unmarshal(data, &cfg)

💡 Gotcha: При первом запуске файла конфигурации не существует. Ошибку os.ErrNotExist нужно обрабатывать отдельно — возвращать пустой Config, а не ошибку.

Используемые пакеты

ПакетНазначениеКлючевые функции
gopkg.in/yaml.v3Чтение/запись YAMLUnmarshal, Marshal
osРабота с файламиReadFile, WriteFile
errorsПроверка типа ошибкиIs

Цели этапа

Определить внутреннее представление данных и механизм хранения настроек.

Что необходимо сделать:

Пакет internal/domain:

  • Структура Today — текущая погода:

    • Поле City (string) — название города
    • Поле TemperatureC (float64) — температура в °C
    • Поле FeelsLikeC (float64) — ощущаемая температура
    • Поле Condition (string) — описание условий
    • Поле WindSpeedMS (float64) — скорость ветра (м/с)
    • Поле WindDirectionDeg (int) — направление ветра (градусы)
    • Поле HumidityPercent (int) — влажность (%)
    • Поле PressureHPa (int) — давление (гПа)
    • Поле VisibilityKm (float64) — видимость (км)
    • Поле PrecipitationMm (float64) — осадки за час (мм)
    • Поле UpdatedAt (time.Time) — время обновления
  • Структура HourlyEntry — запись почасового прогноза:

    • Поле Time (time.Time) — временная метка
    • Поле TemperatureC (float64) — температура
    • Поле POPPercent (int) — вероятность осадков (Probability of Precipitation)
    • Поле WindSpeedMS (float64) — скорость ветра
  • Структура DailyEntry — запись дневного прогноза:

    • Поле Date (time.Time) — дата
    • Поле TempMinC (float64) — минимальная температура
    • Поле TempMaxC (float64) — максимальная температура
    • Поле POPPercent (int) — вероятность осадков
    • Поле WindSpeedMS (float64) — скорость ветра
    • Поле Condition (string) — описание условий

Пакет internal/config:

  • Структура Config — настройки приложения:

    • Поле DefaultCity (string) — город по умолчанию, с yaml-тегом default_city
  • Функция:

    func Load() (Config, error)

    Логика:

    1. Определить путь к файлу конфигурации
    2. Прочитать файл
    3. Если файл не существует — вернуть пустой Config без ошибки
    4. Десериализовать YAML в структуру
  • Функция:

    func Save(cfg Config) error

    Логика:

    1. Сериализовать Config в YAML
    2. Записать в файл

Пример работы

$ cat config.yaml default_city: "Novosibirsk" $ go run main.go Default city: Novosibirsk

При отсутствии файла конфигурации:

$ go run main.go Default city:

Полезные материалы

  • Структуры в Go — Go by Example
  • gopkg.in/yaml.v3 — документация пакета
  • errors.Is — проверка типа ошибки
  • Работа с файлами в Go — на русском

Критерии

не проверялось
  • Структура Today в пакете internal/domain содержит поля City string, TemperatureC float64, FeelsLikeC float64, Condition string, WindSpeedMS float64, HumidityPercent int, UpdatedAt time.Time
  • Структуры HourlyEntry и DailyEntry определены в пакете internal/domain с полями для временных меток типа time.Time
  • Структура Config в пакете internal/config содержит поле DefaultCity string с yaml-тегом
  • Функция Load() (Config, error) в пакете internal/config обрабатывает отсутствие файла через errors.Is и возвращает пустой Config без ошибки
  • Функция Save(cfg Config) error создана в пакете internal/config
Войдите в аккаунт, чтобы начать проект
Запустите первую проверку