Ответ
Да, это частая и очень полезная практика в разработке. Создание оберток позволяет изолировать приложение от деталей реализации внешних инструментов и предоставляет чистый, типизированный и удобный для использования в Go-коде интерфейс.
Основные причины для создания оберток:
- Инкапсуляция и упрощение: Скрытие сложных вызовов, флагов и форматов вывода за простым и понятным методом. Это реализация паттерна "Фасад".
- Типизация: Преобразование строковых аргументов и выводов в строго типизированные структуры Go, что уменьшает количество ошибок.
- Управление зависимостями: Зависимость от внешнего инструмента концентрируется в одном месте (в обертке), а не размазывается по всей кодовой базе.
- Тестируемость: Обертку легко подменить моком (mock) в unit-тестах. Для этого создается интерфейс, который реализует как реальная обертка, так и тестовая заглушка. Напрямую тестировать код, вызывающий
exec.Command
, гораздо сложнее. - Обработка ошибок: Централизованная и более осмысленная обработка ошибок, возвращаемых утилитой или API.
Пример: обертка над CLI-утилитой ffmpeg
Предположим, нам нужно конвертировать видеофайлы. Прямой вызов ffmpeg
из бизнес-логики — плохая идея. Лучше создать обертку.
import (
"context"
"fmt"
"os/exec"
)
// Converter определяет интерфейс для тестирования и мокирования.
type Converter interface {
Convert(ctx context.Context, inputPath, outputPath string) error
}
// FFmpegWrapper реализует интерфейс Converter.
type FFmpegWrapper struct {
binPath string // Путь к исполняемому файлу ffmpeg
}
// NewFFmpegWrapper создает новый экземпляр обертки.
func NewFFmpegWrapper(binPath string) *FFmpegWrapper {
return &FFmpegWrapper{binPath: binPath}
}
// Convert выполняет конвертацию видео.
func (f *FFmpegWrapper) Convert(ctx context.Context, inputPath, outputPath string) error {
// Пример команды: ffmpeg -i input.mp4 -c:v libx264 -crf 23 output.mp4
cmd := exec.CommandContext(ctx, f.binPath,
"-i", inputPath,
"-c:v", "libx264",
"-crf", "23",
outputPath,
)
output, err := cmd.CombinedOutput() // Получаем stdout и stderr
if err != nil {
return fmt.Errorf("ошибка выполнения ffmpeg: %w, вывод: %s", err, string(output))
}
return nil
}
Такой подход позволяет легко использовать конвертер в коде и так же легко заменить его на мок в тестах, не вызывая реальный ffmpeg
.