Современный ИТ-рынок требует от компаний максимальной отдачи при минимальных затратах. Бизнес ждет быстрых результатов, технические команды сталкиваются с дефицитом ресурсов, а выбор языка программирования может кардинально повлиять на оба этих фактора.

Возглавляя бэкенд-команду витрины в KION, я, Леша Жиряков, постоянно балансирую между скоростью вывода фичей и стабильностью работы системы. Сегодня решил перевести абстрактные технические дискуссии в конкретные цифры. А еще — поделиться расчетами, которые помогут принять экономически обоснованное решение: что выбрать для следующего проекта — Python или Java?

Ниже разберу:

В конце сделаю выводы: какой ЯП, на мой взгляд, лучше использовать в проектной и продуктовой разработке для приведенных мной выкладок.

Скорость разработки

И сразу начну с исследований по теме:

Исследование Лутца Прехельта, 2000 год. В нем 80 программистов решали одинаковую задачу на разных ЯП. Результат — разработчики на Python завершили задачу в среднем в 2,2 раза быстрее, чем разработчики на Java.

Исследование Рэя Байшахи, 2014 год. Проанализировали 729 проектов, 80 миллионов строк кода на GitHub и обнаружили, что Python требует значительно меньше кода для выполнения аналогичных задач. Результат — программисты на Python пишут в 2,5 раза меньше строк кода для эквивалентной функциональности по сравнению с Java.

Исследование Биссьянде, 2013 год. На этот раз взяли 100 000 проектов с открытым исходным кодом и оценили время, затраченное на разработку эквивалентных функциональных требований. Результат — на реализацию функциональных требований на Python уходит в среднем в 2–3 раза меньше времени, чем на Java.

Исследование Нанца, 2015 год. Анализировали 10 языков программирования на 7 задачах из коллекции Rosetta Code. Результат — программы на Python требуют в среднем в 2,7 раза меньше строк кода и в 1,9 раза меньше времени разработки по сравнению с Java.

Из приведенных данных ясно, что скорость разработки на Python выше. Но какие факторы приводят к такому результату?

  • Компактный синтаксис. Python требует меньше кода для выполнения тех же задач. Отсутствие фигурных скобок, точек с запятой и других синтаксических элементов делает код чище и понятнее.

  • Встроенные высокоуровневые структуры данных. Python предлагает мощные инструменты, такие как списки, словари и множества с богатым API, что позволяет решать многие задачи в одну строку.

  • Интерпретируемость. Отсутствие необходимости компиляции ускоряет цикл разработки — внесли изменения, сразу запустили код.

  • Богатая стандартная библиотека. Принцип «батарейки включены» значит, что многие задачи можно решить без установки дополнительных пакетов.

  • Экосистема библиотек. PyPI предлагает более 400 000 пакетов практически для любой задачи, а их установка через pip очень проста.

Можно сколько угодно находиться в первой стадии принятия, но скорость разработки на интерпретируемом языке высокого уровня сложно сделать медленней чем на ЯП более низкого уровня.

А теперь сравним количество строк кода на примере нескольких типичных задач(просто примеры, исследования на объеме выше):

1. Парсинг JSON-файла

Python:

import json

with open('data.json') as file:
    data = json.load(file)
    
print(data['key'])  # Доступ к данным

Количество строк: 5.

Java:

import org.json.JSONObject;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.io.IOException;

public class JsonParser {
    public static void main(String[] args) {
        try {
            String content = new String(Files.readAllBytes(Paths.get("data.json")));
            JSONObject jsonObject = new JSONObject(content);
            System.out.println(jsonObject.getString("key"));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Количество строк: 14.

2. Обработка CSV-файла

Python:

import csv

with open('data.csv') as file:
    reader = csv.reader(file)
    for row in reader:
        print(row[0])  # Печать первого столбца

Количество строк: 5.

Java:

import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;

public class CsvProcessor {
    public static void main(String[] args) {
        String line;
        try (BufferedReader br = new BufferedReader(new FileReader("data.csv"))) {
            while ((line = br.readLine()) != null) {
                String[] values = line.split(",");
                System.out.println(values[0]);
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

Количество строк: 15.

3. Реализация алгоритма быстрой сортировки

Python:

def quicksort(arr):
    if len(arr) <= 1:
        return arr
    pivot = arr[len(arr) // 2]
    left = [x for x in arr if x < pivot]
    middle = [x for x in arr if x == pivot]
    right = [x for x in arr if x > pivot]
    return quicksort(left) + middle + quicksort(right)

sorted_array = quicksort([3, 6, 8, 10, 1, 2, 1])

Количество строк: 9.

Java:

import java.util.Arrays;

public class QuickSort {
    public static void main(String[] args) {
        int[] array = {3, 6, 8, 10, 1, 2, 1};
        quickSort(array, 0, array.length - 1);
        System.out.println(Arrays.toString(array));
    }
    
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            int partitionIndex = partition(arr, low, high);
            
            quickSort(arr, low, partitionIndex - 1);
            quickSort(arr, partitionIndex + 1, high);
        }
    }
    
    private static int partition(int[] arr, int low, int high) {
        int pivot = arr[high];
        int i = low - 1;
        
        for (int j = low; j < high; j++) {
            if (arr[j] <= pivot) {
                i++;
                
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        
        int temp = arr[i + 1];
        arr[i + 1] = arr[high];
        arr[high] = temp;
        
        return i + 1;
    }
}

Количество строк: 34.

4. HTTP-клиент с авторизацией

Python (с HTTPX):

import httpx

async def fetch_data():
    async with httpx.AsyncClient() as client:
        headers = {"Authorization": "Bearer your_token"}
        response = await client.get("https://api.example.com/data", headers=headers)
        return response.json()

Количество строк: 6.

Java:

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

public class HttpClientExample {
    public static void main(String[] args) {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create("https://api.example.com/data"))
                .header("Authorization", "Bearer your_token")
                .GET()
                .build();
        
        try {
            HttpResponse<String> response = client.send(request, 
                    HttpResponse.BodyHandlers.ofString());
            System.out.println(response.body());
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Количество строк: 22.

5. Асинхронная обработка событий

Python:

import asyncio

async def process_data(data):
    await asyncio.sleep(1)  # Имитация асинхронной операции
    return f"Обработано: {data}"

async def main():
    tasks = [process_data(i) for i in range(5)]
    results = await asyncio.gather(*tasks)
    for result in results:
        print(result)

if __name__ == "__main__":
    asyncio.run(main())

Количество строк: 13.

Java:

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;

public class AsyncExample {
    public static void main(String[] args) {
        List<CompletableFuture<String>> futures = new ArrayList<>();
        
        for (int i = 0; i < 5; i++) {
            final int index = i;
            futures.add(CompletableFuture.supplyAsync(() -> {
                try {
                    Thread.sleep(1000); // Имитация асинхронной операции
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
                return "Обработано: " + index;
            }));
        }
        
        CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]))
            .thenRun(() -> 
                futures.forEach(f -> {
                    try {
                        System.out.println(f.get());
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                })
            ).join();
    }
}

Количество строк: 28.

Собрал таблицу со сравнением скорости разработки:

Задача

Строк на Python

Строк на Java

Соотношение
Java и Python

Парсинг JSON-файла

5

15–20

~3–4x

Простой веб-сервер

8

30–40

~4–5x

Подключение к БД и выполнение запроса

7

25–30

~3,5–4x

Обработка CSV-файла

4

15–20

~4–5x

Реализация алгоритма быстрой сортировки

10

25–30

~2,5–3x

HTTP-клиент с авторизацией

12

35–45

~3–3,8x

Многопоточная обработка данных

15

45–60

~3–4x

Создание и обучение простой ML-модели

10

50–70

~5–7x

Работа с регулярными выражениями

3

8–10

~2,7–3,3x

REST API (базовый CRUD)

20

60–80

~3–4x

Реализация класса с инкапсуляцией

8

15–20

~1,9–2,5x

Асинхронная обработка событий

12

35–45

~2,9–3,8x

Получается, в среднем Python требует в 2–4 раза меньше кода для решения типичных задач, а это напрямую влияет на скорость разработки и читаемость кода. Поэтому его чаще выбирают для быстрой разработки прототипов, скриптов и для проектов, где максимально важна скорость вывода на рынок.

Теперь подытожим. По исследованиям, которые я привел выше, понятно, что разработка на Python в 2–3 раза быстрее, чем на Java. И это только простые примеры — со сложными разница будет больше.

Меньше кода — больше скорость

 «Чем меньше кода, тем легче его изменять» — так звучит один из фундаментальных принципов в современной разработке ПО. Давайте разбираться, почему это утверждение верно и какие практические выводы из него можно сделать.

1. Объем кода напрямую влияет на когнитивную нагрузку разработчика.

Когда разработчик вносит изменения, ему нужно держать в голове структуру программы, взаимосвязи между компонентами и возможные побочные эффекты изменений. Если уменьшить объем кода, снизится и объем информации, которую нужно анализировать и учитывать.

2. Каждая строка кода — потенциальное место для ошибки.

Формула проста:

Вероятность ошибок ≈ количество строк кода × сложность каждой строки

Меньший объем кода автоматически уменьшает первый множитель в этом уравнении. Результат — меньше багов.

3. С ростом кодовой базы возрастает количество потенциальных взаимодействий между компонентами. Каждая дополнительная тысяча строк кода увеличивает вероятность появления ошибок примерно на 2–5% в зависимости от сложности системы.

4. Большой объем кода приводит к накоплению «технического долга» — ситуации, когда для поддержания работоспособности системы нужно все больше и больше времени и ресурсов. При этом вносить изменения — всегда рискованно.

5. В компактном коде изменения обычно более локализованы. Тут меньше мест, где нужно обновлять одну и ту же логику, и ниже вероятность «забыть» обновить какую-то часть кода. А еще — меньше конфликтов при слиянии веток (merge conflicts).

В сфере разработки программного обеспечения давно известно, что код читают значительно чаще, чем пишут. Код на Python короче, чем на Java, минимум в три раза. Что это значит:

  • Код легче поддерживать и изменять с точки зрения когнитивной нагрузки на разработчика. Необязательно нанимать сеньора, чтобы он мог разобраться в проекте.

  • Развитие и поддержка обходятся дешевле.

Исследование Роберта Гласса в книге Facts and Fallacies of Software Engineering показало, что на поддержку кода, включая чтение, понимание и модификацию, уходит примерно в 4–5 раз больше времени, чем на его первоначальное написание.

Битва титанов, или Сравнение производительности

Дальше покажу, как Python и Java справляются с задачами в реальных сценариях. Использовать буду Python 3.11.

Бенчмарки веб-серверов

RPS (Requests Per Second) для простых ответов

Возьму популярные фреймворки: FastAPI (Python) и Spring Boot (Java). При тестировании простых эндпоинтов, возвращающих JSON {"message": "Hello World"}, результаты выглядят так:

Фреймворк

RPS (запросов в секунду)

Средняя задержка

FastAPI (Uvicorn)

~9 000–12 000

~5–8 мс

Spring Boot

~25 000–30 000

~2–4 мс

Как видим, Java со Spring Boot демонстрирует примерно в 2,5–3 раза более высокую пропускную способность.

Пример с кодом:

Python:

# FastAPI пример
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"message": "Hello World"}

Java:

// Spring Boot пример
@RestController
public class HelloController {
    @GetMapping("/")
    public Map<String, String> hello() {
        return Map.of("message", "Hello World");
    }
}

Парсинг JSON-файла

Для сравнения парсинга JSON обработаем файл размером 100 Мб со вложенными структурами:

Язык/библиотека

Время парсинга (секунды)

Использование памяти

Python (json)

~1,8–2,2

~300–350 Мб

Python (ujson)

~0,9–1,1

~300–350 Мб

Java (Jackson)

~0,5–0,7

~200–250 Мб

Java с библиотекой Jackson обрабатывает JSON примерно в 2–4 раза быстрее стандартной библиотеки Python и использует меньше памяти. Даже с ускоренной библиотекой ujson Python все равно отстает.

Пример:

Python:

# Python пример парсинга
import json
import time

start_time = time.time()
with open("large_file.json", "r") as f:
    data = json.load(f)
print(f"Parsing took {time.time() - start_time} seconds")

Java:

// Java пример парсинга
ObjectMapper mapper = new ObjectMapper();
long startTime = System.currentTimeMillis();
JsonNode data = mapper.readTree(new File("large_file.json"));
System.out.println("Parsing took " + 
    (System.currentTimeMillis() - startTime) / 1000.0 + " seconds");

Java предсказуемо выигрывает у Python в чистой производительности, демонстрируя в 2–4 раза лучшие показатели в типичных веб-сценариях. Но современные Python-фреймворки вроде FastAPI сокращают этот отрыв, особенно в асинхронных задачах. К тому же отставание в производительности можно ликвидировать «железом», просто увеличив количество подов в кубере.

Больше публикаций с бенчмарками и сравнениями Python и Java:

Циклы обновления ПО

Прежде чем приступить к самому интересному — расчетам, давайте поймем, сколько в среднем служит софт.

Исследование Forrester Research показывает, что типичный жизненный цикл корпоративного программного обеспечения составляет:

  • 7–10 лет до полного переписывания в крупных корпоративных системах ERP, CRM;

  • 4–7 лет во внутренних бизнес-приложениях;

  • 2–4 года в потребительских веб-приложениях.

А вот данные из отчета McKinsey & Company Developer Velocity Index:

  • компании, использующие микросервисы, обновляют отдельные компоненты каждые 2–4 недели и полностью переписывают их каждые 12–18 месяцев;

  • DevOps-ориентированные компании выпускают обновления в 46 раз чаще с циклом переписывания 18–24 месяца;

  • традиционные модели разработки: обновление каждые 3–6 месяцев, переписывание каждые 5–8 лет.

Но в каких случаях код действительно нужно переписывать? В исследовании CAST проанализировали более 1,3 миллиарда строк кода, а потом выявили факторы, которые приводят к необходимости переписать код:

  • технический долг превышает 25% от стоимости разработки — точка, после которой поддержка становится дороже переписывания;

  • устаревание технологий — 78% решений о переписывании связаны с устаревшими технологиями;

  • безопасность — 42% случаев полной переработки связаны с проблемами безопасности.

Согласно исследованию Stripe, ИТ-компании тратят около 42% времени разработчиков на поддержку существующего кода и устранение технического долга, а не на создание нового ПО.

Еще можно сказать об экономических аспектах переписывания кода: затраты на поддержку ПО после трехлетнего периода растут в среднем на 15–20% ежегодно, а к 7 году поддержка обходится в 3–4 раза дороже, чем разработка с нуля. И отраслевые различия — например, в финтехе и банковском секторе полное обновление базовых систем в среднем происходит каждые 10–15 лет, в розничной торговле и e-commerce — каждые 3–5 лет, а в медицинском ПО — 7–10 лет.

Если резюмировать все вышесказанное, в развивающейся компании софт переписывается или меняется в среднем раз в 5 лет.

Стоимость инфраструктуры

В зависимости от модели оплаты — за потребленные или за выделенные ресурсы — цены на инфраструктуру могут варьироваться в пределах 10–15%. Возьмем средние показатели за месяц в 2025 году:

CPU

225,00 ₽

за ядро

RAM

180,00 ₽

за Гб

SSD fast

3,50 ₽

за Гб

Кажется, все уже стало понятно. Но доведу дело до конца — посчитаю стоимость разработчика. Допустим, у нас есть сеньор-разработчик на Python и такой же на Java с зарплатой 300 000 рублей на руки. Сколько компания платит на самом деле?

Если зарплата на руки 300 000 рублей, компания платит 448 275,87

Что мы имеем:

  • скорость разработки на Python в три раза быстрее, чем на Java;

  • Java производительней Python в среднем в три раза;

  • стоимость ядра CPU — 225 рублей;

  • стоимость потребления памяти примерно на одном уровне;

  • стоимость разработчика — 450 000 рублей в месяц.

Задача, которую Python-разработчик сделает за месяц, будет стоить 450 000 рублей. В то же время Java-разработка обойдется в 1 350 000 рублей, application на Java будет в три раза быстрее.

Допустим, нам нужно обрабатывать 10 000 RPS, и на Python мы держим одним ядром 500 RPS. То есть не просто принять и записать в кафку, а асинхронно сходить в другие микросервисы, повзаимодействовать с другими API, получить ответы, десериализовать и применить бизнес-логику. Нам понадобится 20 ядер — это 5 000 рублей в месяц на инфраструктуру для Python-стека при оплате 250 рублей за ядро. Для Java нам понадобится 7 ядер, ведь он быстрее Python в 3 раза. Тогда получится 1 500 RPS на ядро. То есть 1 750 рублей в месяц на инфраструктуру для Java-стека.

Разница в затратах на оплату труда Python- и Java-разработчика — 900 000 рублей. То есть разрабатывая код на Java, мы тратим на 900 000 рублей больше. При этом экономим на инфраструктуре 3 250 рублей каждый месяц. Получается, Java сравняется по затратам c Python за 276 месяцев — это 23 года. Учитывая, что софт переписывается в среднем каждые пять лет, инвестиции не отобьются.

Теперь к выводам

При проектной разработке и условии, что после сдачи код никогда не будет меняться, затраты на Java-стек выходят в ноль по сравнению с Python за 5 лет при 50 000 RPS. Если взять горизонт окупаемости и цикла обновления софта в 2,5 года, то Java-стек окупается при 100 000 RPS. Это без учета поддержки, доработок, новых фич и большего ФОТ для Java-специалистов. То есть сценарий маловероятный. А с учетом того, что каждая новая версия Python получает прирост производительности благодаря проекту faster CPython, окупаемость Java-стека под еще большим вопросом.

Итак, Python сокращает затраты на разработку в 3 раза по сравнению c Java. Для продуктового подхода выгоднее выбирать именно его, ведь работа над продуктом не прекращается, и с кодом нужно работать постоянно. Для проектного подхода Python подойдет, если нагрузка меньше 100 000 RPS и вы не планируете поддерживать код.

Когда лучше выбрать Java:

  • Мобильная разработка. Хотя есть фреймворки вроде Kivy или BeeWare, Python не основной язык для iOS и Android. Для мобильных приложений обычно выбирают Swift, Kotlin или кроссплатформенные решения на JavaScript. Экосистема Android SDK оптимизирована для Java и Kotlin и дает лучшую производительность и доступ к нативным API. Компиляция в байт-код на Java VM в скорости превосходит интерпретируемый Python.

  • Низкоуровневое программирование. Для драйверов устройств, встраиваемых систем с ограниченными ресурсами, операционных систем Python не подходит из-за уровня абстракции и потребления ресурсов. Java предлагает прямой доступ к системным ресурсам через JNI (Java Native Interface) и позволяет интегрировать C/C++-код. Статическая типизация Java минимизирует ошибки времени выполнения, которые критичны для встраиваемых систем. У Java меньший накладной расход памяти и более предсказуемое управление ресурсами, так что в этой области это лучшее решение.

  • Игры с высокими требованиями к графике. Хотя есть библиотеки вроде PyGame, для AAA-игр Python не используется. Java дает лучшую производительность в графически интенсивных приложениях благодаря прямому доступу к OpenGL через библиотеки вроде LWJGL. Эффективная многопоточность Java, в отличие от ограничений GIL в Python, позволяет полностью использовать многоядерные процессоры. Развитая экосистема инструментов для оптимизации и профилирования — то, что нужно для высокопроизводительных игр.

И напоследок пара слов о Python для enterprise-разработки. В индустрии есть мнение, что на Python можно писать только скрипты и прототипы, а для чего-то более серьезного он не годится. Эта тема тянет на отдельную публикацию — и в ближайшее время я ею займусь. Пока скажу, что современный Python предлагает полноценный набор инструментов enterprise-уровня. Мы в KION используем его для бэкенда витрин, собираем персонализированные витрины в реалтайме и применяем к ним больше 60 бизнес-правил — и нас все устраивает.

Говорить об этом я мог бы еще долго, но текст и так получился объемным. Кому интересно продолжить тему, добро пожаловать в комментарии!