Как компании начать разрабатывать собственное ПО: полное практическое руководство

Автор: Инженер-программист

От бизнес-задачи до работающей системы за 6 месяцев

Почему собственное ПО — это не про экономию, а про контроль

Реальная история:
Производственная компания (оборот 5 млрд руб.) использовала комбинацию: 1С для учёта, западная MES для производства, самописные Excel-макросы для планирования. Проблемы появились в 2022:

  • MES перестал обновляться (санкции)
  • Интеграции ломались каждый месяц
  • Данные не сходились между системами
  • Изменения требовали 3 месяца согласований

Решение: Разработали собственную систему за 8 месяцев (бюджет 25 млн руб.). Результат через год:

  • Time-to-market новых продуктов: с 6 месяцев до 3 недель
  • Интеграционные ошибки: -85%
  • Независимость от вендоров: 100%
  • Окупаемость: 14 месяцев

Вывод: Собственное ПО — это стратегический актив, а не IT-проект.


Шаг 1: Определить границы — что писать, а что покупать

Матрица принятия решений

КритерийПисать самимПокупать готовое
Критичность для бизнесаЯдро процессовВспомогательные функции
УникальностьКонкурентное преимуществоСтандартные операции
Частота изменений> 1 раза в месяц< 1 раза в год
ИнтеграцииСложная связка системИзолированная функция
РегуляторикаСпецифические требованияОбщие стандарты
Риски блокировкиЗависимость от вендораСтабильный рынок

Примеры задач для собственной разработки

Писать самим:

  1. Диспетчеризация производства
    • Уникальная технология
    • Интеграция с 15+ системами
    • Изменения каждую неделю
    • Пример: управление линиями розлива с учётом специфики рецептур
  2. Система ценообразования
    • Сложные алгоритмы расчёта
    • Десятки переменных (курсы, склады, логистика)
    • Конкурентное преимущество
    • Пример: динамическое ценообразование для ритейла
  3. Интеграционная шина
    • Связь ERP ↔ MES ↔ SCADA ↔ BI
    • Трансформация данных
    • Управление потоками
    • Пример: единая точка входа для всех систем

Не писать (купить готовое):

  • CRM (Битрикс24, amoCRM)
  • Бухгалтерия (1С, SAP)
  • Email-рассылки (SendPulse, Unisender)
  • Видеоконференции (Яндекс.Телемост, Сферум)

Чек-лист принятия решения

Писать самим, если 3 и более пункта совпадают:

  • Задача критична для основного бизнеса
  • Готовых решений нет или они не подходят на 80%+
  • Требуется глубокая интеграция с другими системами
  • Нужны частые изменения (еженедельно/ежемесячно)
  • Есть риски блокировки вендора
  • Планируем масштабирование на 3+ года

Шаг 2: Архитектура — думать слоями, а не монолитом

Базовая 5-слойная модель

┌─────────────────────────────────────┐
│  Слой 5: Представление (UI/UX)     │
│  • Веб-интерфейсы                   │
│  • Мобильные приложения             │
│  • Дашборды                         │
├─────────────────────────────────────┤
│  Слой 4: API / Интеграции          │
│  • REST/GraphQL                     │
│  • Message queues (RabbitMQ/Kafka) │
│  • Event bus                        │
├─────────────────────────────────────┤
│  Слой 3: Бизнес-логика             │
│  • Расчёты                          │
│  • Правила                          │
│  • Workflow                         │
├─────────────────────────────────────┤
│  Слой 2: Данные                     │
│  • PostgreSQL (транзакции)          │
│  • ClickHouse (аналитика)           │
│  • Redis (кэш)                      │
├─────────────────────────────────────┤
│  Слой 1: Безопасность / Управление │
│  • Аутентификация (Keycloak)        │
│  • Аудит                            │
│  • Мониторинг                       │
└─────────────────────────────────────┘

Пример: система управления складом

Неправильно (монолит):

[Одно приложение]
  ├── Учёт товаров
  ├── Приёмка
  ├── Отгрузка
  ├── Инвентаризация
  ├── Интеграция с 1С
  └── Отчёты

Проблемы:

  • Изменение отчётов требует полного релиза
  • Падение приёмки = падение всей системы
  • Невозможно масштабировать отдельные функции

Правильно (модульный монолит):

[Ядро WMS]
  ├── Модуль: Inventory (учёт остатков)
  ├── Модуль: Receiving (приёмка)
  ├── Модуль: Shipping (отгрузка)
  └── Модуль: Reporting (отчёты)

[Интеграционный слой]
  ├── Connector: 1С (REST API)
  ├── Connector: TMS (транспорт)
  └── Event Bus (RabbitMQ)

[UI слой]
  ├── Web-кабинет кладовщика
  └── Мобильное приложение (ТСД)

Преимущества:

  • Модули развиваются независимо
  • Отказ одного модуля не роняет систему
  • Можно масштабировать по нагрузке
  • Легко передать разным командам

Шаг 3: Технологический стек — прагматично, а не модно

Матрица выбора по задачам

ЗадачаРекомендацияАльтернативаКогда НЕ подходит
Backend (бизнес-логика)Java/Spring BootPython/FastAPI, C#/.NETНужен прототип за неделю
API-сервисыGo, Node.jsJava, PythonСложная бизнес-логика
Аналитика/MLPythonR, JuliaReal-time обработка
Frontend корп.TypeScript + ReactVue, AngularПростые формы (используйте low-code)
Мобильные приложенияFlutterReact Native, нативноНужны специфичные API устройств
Real-time/IoTGo, RustC++, Node.jsНет требований к скорости
ИнтеграцииPython, Node.jsJava

Рекомендация для старта (команда 3–5 человек)

Минимальный стек:

  • Backend: Java 17 + Spring Boot (стабильность, enterprise-ready)
  • Frontend: TypeScript + React (большое комьюнити)
  • База данных: PostgreSQL (универсальность)
  • Очереди: RabbitMQ (простота)
  • Кэш: Redis
  • Мониторинг: Prometheus + Grafana

Почему именно так:

  • Один язык для backend (Java) = легче поддерживать
  • TypeScript = меньше ошибок в продакшене
  • PostgreSQL = решает 90% задач
  • Все инструменты open source = нет vendor lock-in

Антипаттерн: зоопарк технологий

Плохо (реальный кейс):

- Backend: Java + Python + Go + Node.js
- Frontend: React + Vue + Angular
- БД: PostgreSQL + MySQL + MongoDB + Redis
- Очереди: RabbitMQ + Kafka + Redis Pub/Sub

Результат: Команда из 8 человек тратит 60% времени на синхронизацию, а не на фичи.

Правило: 1 язык для backend, 1 для frontend, 1 БД для транзакций, 1 для аналитики.


Шаг 4: Безопасность — закладывается сразу, а не «потом»

Принципы Security by Design

1. Минимальные привилегии

Плохо:

sql

-- Приложение работает от суперпользователя
GRANT ALL PRIVILEGES ON DATABASE myapp TO app_user;

Правильно:

sql

-- Отдельные роли для чтения и записи
CREATE ROLE app_reader;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO app_reader;

CREATE ROLE app_writer;
GRANT INSERT, UPDATE ON specific_tables TO app_writer;
```

**2. Разделение контуров**
```
[Production]     [Staging]      [Development]
  ↓                ↓               ↓
Реальные данные  Анонимизация  Тестовые данные
Доступ: 2 чел.   Доступ: 5 чел. Доступ: все
VPN обязателен   VPN обязателен  Локально

3. Шифрование

Обязательно шифровать:

  • Пароли (bcrypt/Argon2, НИКОГДА MD5)
  • Персональные данные (ФИО, паспорта, СНИЛС)
  • Финансовые данные (счета, карты)
  • API ключи и токены
  • Backup-копии

Пример (Java):

java

// Шифрование данных AES-256
public class DataEncryptor {
    private static final String ALGORITHM = "AES/GCM/NoPadding";
    
    public byte[] encrypt(String data, SecretKey key) {
        Cipher cipher = Cipher.getInstance(ALGORITHM);
        cipher.init(Cipher.ENCRYPT_MODE, key);
        return cipher.doFinal(data.getBytes(UTF_8));
    }
}

4. Аудит всех действий

Что логировать:

  • Вход/выход пользователей
  • Изменения критичных данных (суммы, статусы)
  • Изменения прав доступа
  • Экспорт данных
  • API-запросы с результатами

Формат лога:

json

{
  "timestamp": "2025-01-09T14:30:00Z",
  "user_id": "ivan.petrov@company.com",
  "action": "update_order_status",
  "resource": "order_12345",
  "old_value": "pending",
  "new_value": "approved",
  "ip": "192.168.1.100",
  "session_id": "abc123"
}

Чек-лист безопасности перед запуском

  • Все пароли хэшированы (bcrypt/Argon2)
  • HTTPS для всех соединений
  • SQL injection защита (prepared statements)
  • XSS защита (экранирование HTML)
  • CSRF токены для форм
  • Rate limiting для API (макс. 100 req/min)
  • Secrets в Vault, не в коде
  • Логирование всех изменений
  • Backup ежедневно, хранение 30 дней
  • Тестирование на проникновение (пентест)

Шаг 5: Интеграции — как связать с другими системами

Типы интеграций и их реализация

1. Синхронная интеграция (REST API)

Когда использовать:

  • Нужен немедленный ответ
  • Небольшой объём данных (< 1000 записей)
  • Критична актуальность (цены, остатки)

Пример: получение данных из 1С

python

import requests

def get_product_price(product_id):
    response = requests.get(
        f"https://1c.company.com/api/products/{product_id}",
        auth=('api_user', 'password'),
        timeout=5
    )
    
    if response.status_code == 200:
        return response.json()['price']
    else:
        # Fallback: использовать кэш
        return get_cached_price(product_id)

2. Асинхронная интеграция (Message Queue)

Когда использовать:

  • Большой объём данных
  • Не критична скорость
  • Нужна гарантия доставки

Пример: отправка заказа в ERP

python

import pika

def send_order_to_erp(order_data):
    connection = pika.BlockingConnection(
        pika.ConnectionParameters('rabbitmq.company.local')
    )
    channel = connection.channel()
    
    channel.queue_declare(queue='erp_orders', durable=True)
    
    channel.basic_publish(
        exchange='',
        routing_key='erp_orders',
        body=json.dumps(order_data),
        properties=pika.BasicProperties(
            delivery_mode=2  # сообщение персистентно
        )
    )
    
    connection.close()
```

**3. Событийная интеграция (Event Bus)**

**Когда использовать:**
- Множество систем должны знать о событии
- Decoupling (системы не знают друг о друге)
- Асинхронная обработка

**Схема:**
```
[WMS: Товар отгружен] → [Event Bus] → Подписчики:
                                      ├─ [1С: Списать со склада]
                                      ├─ [CRM: Уведомить клиента]
                                      ├─ [BI: Обновить аналитику]
                                      └─ [Логистика: Создать ТТН]

Паттерн: Anticorruption Layer (ACL)

Проблема: 1С возвращает данные в неудобном формате.

Решение: Адаптер, который трансформирует данные.

java

// Адаптер для 1С
public class OneCAdapter {
    private OneCApiClient client;
    
    public Product getProduct(String id) {
        // Получаем данные из 1С
        OneCProduct raw = client.fetchProduct(id);
        
        // Преобразуем в нашу модель
        return Product.builder()
            .id(raw.getCode())
            .name(raw.getDescription())
            .price(raw.getPrice().divide(100)) // копейки → рубли
            .available(raw.getStock() > 0)
            .build();
    }
}
```

**Преимущества:**
- Наша система не зависит от структуры данных 1С
- Легко заменить 1С на другую ERP
- Все изменения в одном месте

---

## Шаг 6: Работа с реальными данными (IoT, датчики, оборудование)

### Архитектура сбора данных
```
[Датчики/PLC] → [Edge-шлюз] → [MQTT Broker] → [Backend] → [БД]
                     ↓
              Предобработка
              Фильтрация
              Буферизация

Пример: мониторинг температуры в холодильных камерах

1. Edge-устройство (Raspberry Pi с датчиками)

python

import paho.mqtt.client as mqtt
import time
from w1thermsensor import W1ThermSensor

# Подключение к MQTT
client = mqtt.Client()
client.connect("mqtt.company.local", 1883)

sensor = W1ThermSensor()

while True:
    temp = sensor.get_temperature()
    
    # Отправка в MQTT
    client.publish(
        "factory/warehouse_1/temperature",
        json.dumps({
            "value": temp,
            "timestamp": time.time(),
            "sensor_id": "temp_001"
        })
    )
    
    time.sleep(60)  # каждую минуту

2. Backend (обработка данных)

java

@Service
public class TemperatureMonitor {
    
    @Autowired
    private AlertService alertService;
    
    @MqttSubscribe("factory/+/temperature")
    public void handleTemperature(TemperatureReading reading) {
        // Сохраняем в БД
        temperatureRepo.save(reading);
        
        // Проверяем пороги
        if (reading.getValue() > 5.0) {
            alertService.sendAlert(
                "Превышение температуры в камере: " + 
                reading.getValue() + "°C"
            );
        }
    }
}

3. Хранение временных рядов (TimescaleDB)

sql

-- Таблица для временных рядов
CREATE TABLE temperature_readings (
    time        TIMESTAMPTZ NOT NULL,
    sensor_id   TEXT NOT NULL,
    value       DOUBLE PRECISION,
    warehouse   TEXT
);

SELECT create_hypertable('temperature_readings', 'time');

-- Запрос: средняя температура за последний час
SELECT 
    time_bucket('5 minutes', time) AS bucket,
    AVG(value) as avg_temp
FROM temperature_readings
WHERE time > NOW() - INTERVAL '1 hour'
GROUP BY bucket
ORDER BY bucket;

Шаг 7: Масштабирование — техническое и организационное

Техническое масштабирование

Горизонтальное (добавление серверов):

yaml

# docker-compose.yml (упрощённо)
version: '3.8'
services:
  app:
    image: myapp:latest
    deploy:
      replicas: 3  # 3 экземпляра приложения
    environment:
      - DATABASE_URL=postgresql://db:5432/myapp
  
  nginx:
    image: nginx:latest
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
  
  db:
    image: postgres:15
    volumes:
      - pgdata:/var/lib/postgresql/data

Кэширование:

java

@Service
public class ProductService {
    
    @Cacheable(value = "products", key = "#id")
    public Product getProduct(String id) {
        // Тяжёлый запрос выполнится только раз
        return productRepo.findById(id);
    }
    
    @CacheEvict(value = "products", key = "#product.id")
    public void updateProduct(Product product) {
        productRepo.save(product);
    }
}

Организационное масштабирование

Документация как код:

markdown

# docs/architecture/adr/001-use-postgresql.md

# ADR-001: Использование PostgreSQL как основной БД

## Статус
Принято (2025-01-09)

## Контекст
Нужна надёжная реляционная БД для хранения заказов, 
продуктов и пользователей.

## Решение
PostgreSQL 15

## Альтернативы
- MySQL — отвергнуто (лицензирование Oracle)
- MongoDB — отвергнуто (нужны ACID-транзакции)

## Последствия
+ Поддержка JSON
+ Полнотекстовый поиск
+ Зрелая экосистема
- Требует настройки производительности

Code review как стандарт:

markdown

# .github/PULL_REQUEST_TEMPLATE.md

## Что изменено
<!-- Описание изменений -->

## Зачем
<!-- Ссылка на задачу: Closes #123 -->

## Как проверить
1. Запустить `docker-compose up`
2. Открыть http://localhost:8080
3. Выполнить действия X, Y, Z

## Чек-лист
- [ ] Тесты добавлены/обновлены
- [ ] Документация обновлена
- [ ] Нет breaking changes
- [ ] Code coverage > 70%

Шаг 8: Roadmap от идеи до продакшена (6 месяцев)

Месяц 1: Фундамент

Недели 1–2: Проектирование

  • Event storming (выявление bounded contexts)
  • Выбор технологического стека
  • Схема архитектуры (C4 model)
  • Определение API-контрактов

Недели 3–4: Инфраструктура

  • Поднять Git-сервер (GitLab on-prem)
  • Настроить CI/CD
  • Развернуть dev/staging окружения
  • Настроить мониторинг

Месяц 2–3: MVP

Цель: Работающее ядро системы с 2–3 ключевыми функциями.

Недели 5–8:

  • Реализовать базовые CRUD операции
  • Интегрировать с 1 внешней системой
  • Написать unit-тесты (покрытие > 70%)
  • Создать базовый UI

Недели 9–12:

  • Интеграционные тесты
  • Нагрузочное тестирование (JMeter)
  • Документация API (Swagger)
  • Демо для стейкхолдеров

Месяц 4–5: Доработка и безопасность

Недели 13–16:

  • Внедрить аутентификацию (OAuth2/Keycloak)
  • Настроить аудит действий
  • Шифрование критичных данных
  • Пентест (внутренний или внешний)

Недели 17–20:

  • Оптимизация производительности
  • Добавить недостающие функции
  • User Acceptance Testing (UAT)
  • Исправление багов

Месяц 6: Запуск

Недели 21–22: Подготовка

  • Миграция данных из старой системы
  • Обучение пользователей
  • Runbook для production
  • План отката (rollback)

Недели 23–24: Go-live

  • Запуск в production
  • Мониторинг 24/7 первую неделю
  • Горячая линия для пользователей
  • Быстрые исправления по результатам

Недели 25–26: Стабилизация

  • Анализ метрик использования
  • Сбор обратной связи
  • Приоритизация доработок
  • Планирование версии 2.0

Бюджет и команда: реальные цифры

Минимальная команда (3 человека)

РольЗона ответственностиЗарплата/мес
Tech Lead / BackendАрхитектура, API, интеграции250–350 тыс.
Frontend DeveloperUI, UX, мобильные клиенты150–250 тыс.
DevOps / QACI/CD, тесты, инфраструктура150–250 тыс.

Итого: 550–850 тыс. руб./мес × 6 месяцев = 3.3–5.1 млн руб. (только з/п).

Дополнительные расходы

СтатьяСтоимость
Серверы (on-prem)1–2 млн (единоразово)
Лицензии (GitLab EE, IDE)500 тыс./год
Обучение команды300–500 тыс.
Пентест200–400 тыс.
Непредвиденное (15%)700 тыс.–1 млн

Итого за 6 месяцев: 6–9 млн руб.

Альтернатива: подрядчик

Разработка «под ключ»: 10–25 млн руб.
Но: Вы не владеете знаниями, зависимость от подрядчика, поддержка +30% ежегодно.

Вывод: Собственная команда окупается через 12–18 месяцев.


Главные принципы

  1. Начинайте с архитектуры, а не с кода: Без понятной структуры система развалится через год.
  2. Безопасность — с первого дня: «Добавим потом» = никогда не добавите правильно.
  3. Минимум технологий: 1 язык для backend, 1 для frontend, 1 БД = легче поддерживать.
  4. Документируйте решения: ADR сохранит знания при смене команды.
  5. CI/CD с первого коммита: Ручной деплой = дорого и опасно.
  6. Интеграции через адаптеры: ACL защитит от изменений внешних систем.
  7. Масштабируйтесь постепенно: Микросервисы нужны при 100+ разработчиках, не раньше.

Главная мысль:
Собственное ПО — это не «написать приложение», а построить управляемую систему, которая будет служить бизнесу 10+ лет. Инвестиция в правильную архитектуру окупается многократно через снижение TCO и независимость от вендоров.