Java for Beginner
870 subscribers
1.01K photos
275 videos
14 files
1.69K links
Канал от новичков для новичков!
Изучайте Java вместе с нами!
Здесь мы обмениваемся опытом и постоянно изучаем что-то новое!

Наш YouTube канал - https://www.youtube.com/@Java_Beginner-Dev

Наш канал на RUTube - https://rutube.ru/channel/37896292/
Download Telegram
Что такое массив (array) и как с ним работать? 🤓

Ответ:

Массив
— это структура данных, которая хранит фиксированное количество элементов одного типа.

Доступ к элементам осуществляется по индексу (начиная с 0).

Массивы в Java являются объектами. Длина массива задается при создании и не может быть изменена. Массивы могут быть одномерными и многомерными. Для работы с массивами есть удобный класс Arrays с методами: sort(), binarySearch(), toString(), equals(), fill().

При создании массива все элементы получают значения по умолчанию (0, false, null).


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История IT-технологий сегодня — 19 Февраля

ℹ️ Кто родился в этот день

Никола́й Копе́рник (пол. Mikołaj Kopernik, нем. Niklas Koppernigk[5]; 19 февраля 1473, Торунь — 24 мая 1543, Фромборк) — польский и немецкий астроном, математик, механик, экономист, каноник эпохи Возрождения. Наиболее известен как автор гелиоцентрической системы мира, положившей начало первой научной революции.


🌐 Знаковые события

1946доклад Алана Тьюринга об ACE. На заседании исполнительного комитета Национальной физической лаборатории (NPL) представил первый детальный дизайн хранимо-программного компьютера ACE (Automatic Computing Engine). Это был первый проект компьютера с хранимой программой, вдохновлённый идеей машины Тьюринга; ACE стал важным шагом к архитектуре фон Неймана и стал прототипом для многих последующих систем.


#Biography #Birth_Date #Events #19февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍4
[Совет по Java #007]

Тема: System.currentTimeMillis() для замеров производительности ненадежен. Всегда используйте System.nanoTime().

Проблема: Использование System.currentTimeMillis() для измерения времени выполнения участков кода (профилирования, бенчмаркинга) является распространенной, но методологически неверной практикой.

Этот метод возвращает текущее время в миллисекундах, отсчитываемое от эпохи Unix (1 января 1970 года). Он подвержен влиянию корректировок системного времени, как ручных, так и автоматических (например, синхронизация через NTP — Network Time Protocol). Если во время замера системные часы будут переведены назад, результат может оказаться отрицательным, а если вперед — существенно завышенным. Кроме того, точности в миллисекундах может не хватать для измерения очень быстрых операций, длительность которых составляет микросекунды или наносекунды.

Решение: Для измерения интервалов времени предназначен метод System.nanoTime(). Он использует высокоточный таймер (high-resolution timer) с наносекундной точностью, если это поддерживается платформой. Важно понимать, что nanoTime() измеряет относительное время — некоторый произвольный, но фиксированный момент в прошлом (например, момент загрузки JVM).

Его нельзя использовать для получения текущего времени суток, но он идеально подходит для вычисления разницы (дельты) между двумя событиями. Метод не подвержен корректировкам системных часов и монотонно увеличивается, гарантируя корректность измерения промежутков времени.

import java.util.concurrent.TimeUnit;

public class PerformanceMeasurement {
public static void main(String[] args) throws InterruptedException {
//Антипаттерн: Измерение через currentTimeMillis()
long startMillis = System.currentTimeMillis();

// Имитация работы
Thread.sleep(100);

long endMillis = System.currentTimeMillis();
long durationMillis = endMillis - startMillis;
System.out.println("currentTimeMillis() duration: " + durationMillis + " ms");

// Проблема: если во время замера часы переведятся назад,
// duration может быть отрицательным или неточным.

//Решение: Измерение через nanoTime()
long startNanos = System.nanoTime();

// Имитация работы
Thread.sleep(100);

long endNanos = System.nanoTime();
long durationNanos = endNanos - startNanos;

// Конвертация в миллисекунды для читаемости
long durationMs = TimeUnit.NANOSECONDS.toMillis(durationNanos);
double preciseMs = durationNanos / 1_000_000.0;

System.out.println("nanoTime() duration: " + durationNanos + " ns");
System.out.println("nanoTime() duration (ms): " + durationMs + " ms");
System.out.println("nanoTime() duration (precise ms): " + preciseMs + " ms");

// Демонстрация для сверхбыстрых операций
long fastStart = System.nanoTime();
int sum = 0;
for (int i = 0; i < 1000; i++) {
sum += i;
}
long fastEnd = System.nanoTime();
System.out.println("Loop duration: " + (fastEnd - fastStart) + " ns");

// Важно: nanoTime() нельзя использовать для получения времени суток
// System.out.println(System.nanoTime()); // Бессмысленное огромное число
}

// Правильный способ измерения среднего времени выполнения
public static double measureAverageTime(Runnable task, int iterations) {
// Прогрев JVM (warm-up) для компиляции и оптимизации кода
for (int i = 0; i < 10_000; i++) {
task.run();
}

long totalNanos = 0;
for (int i = 0; i < iterations; i++) {
long start = System.nanoTime();
task.run();
long end = System.nanoTime();
totalNanos += (end - start);
}

return (double) totalNanos / iterations;
}
}


#Java #советы
👍3🔥1
Объяснение: Метод System.nanoTime() использует наиболее точный таймер, доступный на платформе (например, TSC — Time Stamp Counter на процессорах x86).

Его точность и стабильность зависят от конкретной реализации JVM и операционной системы, но гарантированно не хуже, чем у currentTimeMillis(), а обычно на несколько порядков выше. Важно отметить, что на некоторых системах (например, виртуальные машины) nanoTime() может использовать тот же таймер, что и currentTimeMillis(), но без корректировок системного времени. При проведении микро-бенчмарков необходимо также учитывать необходимость прогрева JVM (как показано в методе measureAverageTime), чтобы код был скомпилирован JIT-компилятором, и результаты отражали реальную производительность, а не работу в режиме интерпретации.

Для серьезного бенчмаркинга следует использовать специализированные фреймворки, такие как JMH (Java Microbenchmark Harness), которые автоматически решают эти и многие другие проблемы.

#Java #советы
👍33
Что выведет код?

package oleborn.taskswithspring.tasks.year2026;

public class Task190226 {
public static void main(String[] args) throws InterruptedException {
long start = System.currentTimeMillis();
Thread.sleep(5);
long end = System.currentTimeMillis();

long startNano = System.nanoTime();
Thread.sleep(5);
long endNano = System.nanoTime();

System.out.println("Millis diff: " + (end - start));
System.out.println("Nanos diff in ms: " + (endNano - startNano) / 1_000_000);
}
}


#Tasks
👍2
Что такое switch и как он работает? 🤓

Ответ:

switch
— это условный оператор, который позволяет выбирать один из нескольких блоков кода для выполнения.

Он работает с типами: byte, short, char, int, их обертками, enum, String (начиная с Java 7). Оператор сравнивает значение выражения со значениями в case. При совпадении выполняется соответствующий блок до оператора break (если break нет, выполнение проваливается в следующий case — это называется fall-through).

Начиная с Java 12, появился более лаконичный switch-выражение с -> и yield.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История IT-технологий сегодня — 20 Февраля

ℹ️ Кто родился в этот день

Лю́двиг Бо́льцман (нем. Ludwig Eduard Boltzmann; 20 февраля 1844, Вена — 5 сентября 1906, Дуино, Цислейтания) — австрийский физик-теоретик, основатель статистической механики и молекулярно-кинетической теории. Его работы по статистической механике и энтропии напрямую предвосхитили формулу Шеннона для количества информации. Теория информации — математический фундамент сжатия данных, криптографии и передачи сигналов.

Джон Уи́ллард Ми́лнор (англ. John Willard Milnor; род. 20 февраля 1931, Ориндж[англ.], Нью-Джерси, США) — американский математик. Его работы по дифференциальной топологии и алгебраической топологии используются в компьютерной графике, геометрическом моделировании и теории сложных систем.


🌐 Знаковые события

1986 — выведен на орбиту базовый блок орбитальной станции «Мир».


#Biography #Birth_Date #Events #20февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍3
Раздел 8. Stream API и функциональный стиль в Java

Глава 3: Чистые преобразования и борьба с исключениями

filter, map, flatMap — кирпичи декларативности

Stream API предоставляет минимальный, но выразительный набор операций для декларативной обработки данных. Если императивный код строится из циклов, условий и временных переменных, то потоковый код компонуется из трёх фундаментальных примитивов: фильтрации, отображения и свёртки. Рассмотрим первые два и их мощное обобщение — flatMap.

filter: селекция по предикату

Операция filter принимает Predicate<T> — функцию, возвращающую boolean — и возвращает поток, содержащий только элементы, удовлетворяющие условию. Это декларативный аналог условного оператора в цикле, но без видимого управления состоянием.
Stream<Book> classics = library.stream()
.filter(book -> book.year() < 1980);


Важно понимать, что filter — операция без состояния (stateless). Она не требует памяти, пропорциональной количеству элементов, и не изменяет порядок. Каждый элемент проверяется независимо, в изоляции от других. Это делает filter идеальным для распараллеливания: элементы можно проверять в любом порядке и в любых потоках без синхронизации.

Стоимость filter — O(1) на элемент плюс стоимость выполнения предиката. Предикат должен быть чистой функцией: детерминированной, без побочных эффектов, зависящей только от входного элемента.

Нарушение этого правила — распространённый источник багов:
// Антипаттерн: предикат с побочным эффектом
AtomicInteger counter = new AtomicInteger(0);
Stream<Book> everyThird = library.stream()
.filter(b -> counter.incrementAndGet() % 3 == 0); // Недетерминировано при parallel()


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


#Java #для_новичков #beginner #stream_api #filter
👍4
map: структурная трансформация

Операция map принимает Function<T, R> и применяет её к каждому элементу, заменяя его результатом функции. Это преобразование типа: из потока книг делаем поток названий, из потока строк — поток их длин, из потока заказов — поток сумм.
Stream<String> titles = library.stream()
.map(Book::title);

Stream<Integer> lengths = titles.map(String::length);


map также stateless и ленив. Функция вызывается только при запросе элемента терминальной операцией. Стоимость — O(1) на элемент плюс стоимость функции. Функция должна быть чистой: один и тот же вход всегда даёт один и тот же выход, без модификации внешнего состояния.

Композиция map позволяет выстраивать цепочки преобразований, читаемые справа налево или через method reference:
// Цепочка преобразований: Book -> String -> Integer -> String
String summary = book.stream()
.map(Book::author) // Book -> String
.map(String::toUpperCase) // String -> String
.map(author -> author.substring(0, 3)) // String -> String
.map(prefix -> "Author: " + prefix) // String -> String
.findFirst()
.orElse("Unknown");


Каждый map — отдельный узел конвейера, отдельный объект в памяти. Для простых преобразований это приемлемо, но для тяжёлых операций композиция нескольких map может быть менее эффективна, чем одно комплексное преобразование, из-за накладных расходов на вызовы лямбд и промежуточные объекты.


flatMap: разворачивание иерархий

flatMap — наиболее мощный и наиболее сложный из трёх примитивов. Он решает проблему, которую map решить не может: когда один элемент источника порождает ноль, один или множество элементов результата.

Сигнатура flatMap требует функцию, возвращающую Stream<R> вместо R. Операция применяет эту функцию к каждому элементу, получает потоки результатов и сливает их в единый выходной поток. Это аналог вложенных циклов или операции "расплющивания" (flattening) в функциональных языках.

Классический сценарий: коллекция внутри коллекции

Предположим, у нас есть список заказов, каждый содержит список позиций.

Нужно получить поток всех позиций всех заказов:

List<Order> orders = fetchOrders();

// Императивный подход: вложенные циклы, временная коллекция
List<OrderItem> allItems = new ArrayList<>();
for (Order order : orders) {
for (OrderItem item : order.getItems()) {
allItems.add(item);
}
}

// Декларативный подход: flatMap
Stream<OrderItem> itemStream = orders.stream()
.flatMap(order -> order.getItems().stream());


Здесь order -> order.getItems().stream() — функция, превращающая один Order в Stream<OrderItem>. flatMap выполняет слияние этих потоков, устраняя уровень вложенности. Результат — плоский поток всех элементов.

Нулевое и единичное отображение


flatMap универсален: он обрабатывает все случаи количества выходных элементов на входной:
Ноль элементов: возвращаем Stream.empty(), элемент исключается из результата
Один элемент: возвращаем Stream.of(element), эквивалентно map с последующим filter(Objects::nonNull)
Множество элементов: возвращаем collection.stream(), все элементы включаются в результат

// Фильтрация через flatMap: ноль или один элемент
Stream<Book> validBooks = rawData.stream()
.flatMap(data -> {
try {
Book book = parseBook(data); // Может бросить исключение
return Stream.of(book); // Один элемент при успехе
} catch (ParseException e) {
return Stream.empty(); // Ноль элементов при ошибке
}
});


#Java #для_новичков #beginner #stream_api #filter #flatMap #map
👍5
Сложность и читаемость

Мощь flatMap оборачивается риском чрезмерной сложности.

Вложенные flatMap создают "лестницу" преобразований, сложную для восприятия:
// Антипаттерн: глубокая вложенность flatMap
Stream<String> deepStream = orders.stream()
.flatMap(order -> order.getShipments().stream()
.flatMap(shipment -> shipment.getPackages().stream()
.flatMap(pkg -> pkg.getItems().stream()
.flatMap(item -> item.getTags().stream()))));


Этот код эквивалентен четырём вложенным циклам. Он работает, но его трудно читать и отлаживать. Каждый уровень вложенности добавляет лексический контекст, и переменные верхних уровней (order, shipment) доступны во вложенных лямбдах, создавая неявные зависимости.

Рефакторинг через промежуточные методы улучшает читаемость:
// Лучше: именованные методы с ясной семантикой
Stream<String> tags = orders.stream()
.flatMap(this::extractShipments)
.flatMap(this::extractPackages)
.flatMap(this::extractItems)
.flatMap(this::extractTags);

private Stream<Shipment> extractShipments(Order order) {
return order.getShipments().stream();
}
// ... и так далее


Или использование mapMulti (Java 16+) — операции, комбинирующей map и flatMap с более эффективной реализацией для множественного вывода:
// mapMulti: более эффективен, чем flatMap, для множественных элементов
Stream<String> tags = orders.stream()
.<String>mapMulti((order, consumer) -> {
for (Shipment s : order.getShipments()) {
for (Package p : s.getPackages()) {
for (Item i : p.getItems()) {
for (String tag : i.getTags()) {
consumer.accept(tag); // Прямая передача без создания Stream
}
}
}
}
});


mapMulti избегает создания промежуточных объектов Stream для каждого элемента, что снижает нагрузку на GC при глубокой вложенности.


Анализ стоимости

filter: O(1) на элемент. Память: O(1). Параллелизм: отличный, нет синхронизации.
map: O(1) на элемент плюс стоимость функции. Память: O(1) для примитивов, O(1) для ссылок (создаётся новый объект результата). Параллелизм: отличный.
flatMap: O(1) на элемент плюс стоимость создания выходного потока плюс стоимость его обхода. Память: зависит от размера выходных потоков. Параллелизм: сложный — слияние множественных потоков требует координации.

Скрытая стоимость flatMap — в аллокациях. Каждый вызов функции создаёт новый объект Stream (обычно через Collection.stream() или Stream.of()). Для больших коллекций это давит на Young Generation. Оптимизация через mapMulti или специализированные сплитераторы уместна в критичных секциях.


Композиция как язык запросов

Комбинация filter, map, flatMap образует внутренний DSL (domain-specific language) для преобразования данных.

Хорошо спроектированный конвейер читается как предложение на естественном языке:
// "Найти все уникальные теги из активных заказов, отсортированные по алфавиту"
List<String> sortedUniqueTags = orders.stream()
.filter(Order::isActive) // которые активны
.flatMap(o -> o.getTags().stream()) // извлечь все теги
.distinct() // уникальные
.sorted() // отсортированные
.collect(toList()); // собрать в список


Каждая операция — глагол, каждый метод reference или лямбда — дополнение. Порядок операций отражает логику обработки: сначала сужаем (filter), затем расплющиваем (flatMap), затем нормализуем (distinct, sorted).

#Java #для_новичков #beginner #stream_api #filter #flatMap #map
👍3
Что выведет код?

import java.util.stream.Stream;

public class Task200226 {
public static void main(String[] args) {
Stream.of(1, 2, 3, 4, 5)
.filter(i -> {
System.out.print(i + " ");
return i % 2 == 0;
})
.map(i -> i * 10)
.findFirst()
.ifPresent(i -> System.out.print("result: " + i));
}
}


#Tasks
👍2
1
Чем отличается throw от throws? 🤓

Ответ:

Оба ключевых слова связаны с обработкой исключений, но выполняют разные функции.

throws используется в сигнатуре метода, чтобы объявить, что метод может выбросить указанные исключения (обычно проверяемые). Это предупреждение для вызывающего кода.

throw — это оператор, который фактически создает и выбрасывает объект исключения (например, throw new IOException("Ошибка")).

throw используется внутри тела метода.


#собеседование
Please open Telegram to view this post
VIEW IN TELEGRAM
👍5
История технологий сегодня — 21 Февраля

ℹ️ Кто родился в этот день

Михаи́л Алекса́ндрович Бонч-Бруе́вич (9 (21) февраля 1888, Орёл — 7 марта 1940, Ленинград) — русский и советский радиотехник, основатель российской радиоламповой промышленности. Член-корреспондент АН СССР (1931). Профессор Московского высшего технического училища (1922), Ленинградского института инженеров связи (1932), доктор технических наук, один из основателей и руководителей Нижегородской радиолаборатории. Внёс значительный вклад в развитие советской радиофизики, разработку новых типов радиоламп, аппаратуры радиовещания и радиосвязи. Автор учебников, научных работ, а также около 60 патентов на изобретения в области радиотехники.


🌐 Знаковые события

2006 — космическим телескопом «Хаббл» открыт астрономический объект неизвестного типа SCP 06F6, природу которого астрономы не могут объяснить до сих пор.


#Biography #Birth_Date #Events #21февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
🔥1
С 14.02 по 20.02
Предыдущий пост(с 07.02 по 13.02)

Воскресный мотивационный пост:
Не было мотивации

Запись встреч/видео:
6. От сырых метрик к production-мониторингу: Prometheus и Grafana

Обучающие статьи:
Раздел 8. Stream API и функциональный стиль

Глава 2: Анатомия Stream API. Ленивость и стоимость операций
Ленивость и Short-Circuit — ключ к эффективности
(Практика): Диссекция конвейера в «Библиотеке»

Глава 3: Чистые преобразования и борьба с исключениями
filter, map, flatMap — кирпичи декларативности

Советы по Java:
[Совет по Java #006]
Используйте Enum вместо строковых констант для ограниченного набора значений

[Совет по Java #007]
System.currentTimeMillis() для замеров производительности ненадежен. Всегда используйте System.nanoTime().

Полезные статьи и видео:
Hot reload секретов под нагрузкой в Java-сервисах на Spring


Как и всегда, задачи можно найти под тегом - #Tasks, вопросы с собеседований - #собеседование
👍3🔥22
А давайте сегодня, часиков в 17 по мск встретимся и поболтаем? ☺️

Что-то давно Вас всех не видел)))

Расскажете как у вас дела
😉

Придете? 📞
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
ВСТРЕЧА

заходите, поболтаем, поотвечаем на вопросы, обменяемся мнениями
👍2
История технологий сегодня — 22 Февраля

ℹ️ Кто родился в этот день

Томас Курц (англ. Thomas Eugene Kurtz; 22 февраля 1928, Ок-Парк — 12 ноября 2024, Лебанон[англ.]) — американский учёный в области информатики, один из разработчиков языка программирования Бейсик. В начале — середине 1960-х годов совместно с Джоном Кемени разработал Бейсик и DTTS (англ. Dartmouth Time Sharing System) — операционную систему для PDP-1, отмечаемую как первую успешную крупномасштабную реализацию концепции разделения времени.

Ирвинг «Эл» Гросс (/ɡroʊs/; 22 февраля 1918 — 21 декабря 2000) — был пионером мобильной беспроводной связи. Он создал и запатентовал множество коммуникационных устройств, в частности, раннюю версию рации, радиостанции гражданского диапазона, пейджер и беспроводной телефон.


🌐 Знаковые события

1966 — запущен спутник «Космос-110» с собаками Ветерком и Угольком на борту.


#Biography #Birth_Date #Events #22февраля
Please open Telegram to view this post
VIEW IN TELEGRAM
👍2
ГЛОБАЛИЗАЦИЯ ЗАКАНЧИВАЕТСЯ

Помните эту картинку, нарисованную влажной рекламой?

Айтишник на лежаке у океана. В одной руке — «Пина колада». А другой — пуш в гит. Проект в России. Жизнь в Таиланде. Зарплата в долларах.

Многие пошли в айти из-за этого. Многие сорвались в далёкие страны за убегающей картинкой-мечтой.

И да, некоторые добились желаемого.

Но мне всегда хотелось понять: ценой чего?

Жить там, где тебя терпят, пока есть деньги?
Бросить родных, друзей, свой двор — чтобы пожить красиво?

Быть вечным чужим и никогда не почувствовать, что ты на своей земле?


ЭТО НЕ КРИЗИС. ЭТО ЗАКАТ ГЛОБАЛИЗАЦИИ.

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

Но многие всё ещё думают: потерпим, переждём, все вернётся к прежнему и привычному.

Нифига ребят.

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

Ограничения на полупроводники, ИИ, облака — долгосрочная политика ведущих держав. Данные больше не текут свободно — они стали стратегическим ресурсом, как нефть или уран.

И речь не о паре проблемных лет. Речь о том, что мир перестраивается навсегда.


IT ВНЕ ПОЛИТИКИ? ЗАБУДЬТЕ.

Раньше можно было прятаться за мантру: код — вне политики. GitHub — глобален. Мы — граждане интернета.

Как же сейчас это звучит смешно. Китай и США, Россия и Европейский союз - полностью расходятся бортами.

Код — теперь инфраструктура государства. Облака — суверенитет. Чипы — оборона. Разработчик больше не "фрилансер". Он встроен в геоэкономическую систему конкретной страны.

И выбраться из этого нельзя — можно только осознать и принять или начать бороться с ветряной мельницей.

Вы думаете, вас не коснётся? Посмотрите на карту, компании разделяются на региональные экосистемы. Доступы к сервисам обрываются.

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


ПОЧЕМУ ЭТО ПРОИСХОДИТ ИМЕННО СЕЙЧАС?

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

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

Поэтому мир меняется. И не только в нашей стране.


ЧТО ЭТО ЗНАЧИТ ДЛЯ НАС?

Мир меняется. И вместе с ним меняются правила игры.

Раньше наши ребята писали код для стартапов из Кремниевой долины, делали фичи для европейских финтех-проектов, грезили офферами в FAANG. И успех измерялся тем, как далеко они уехали от дома.

Это была эпоха потребителей глобализации.

Теперь наступает эпоха строителей.

Посмотрите на карту: огромные рынки — Россия, Китай, Иран, многие страны Африки и Латинской Америки — выпадают из западной цифровой орбиты. Но люди там не перестали пользоваться приложениями, не перестали платить, не перестали общаться.
Кто закроет эти потребности?

Вспомните историю: когда Америка ввела эмбарго на технологии для СССР, мы не перестали летать в космос. Мы построили свою космонавтику.

Сейчас перед нами стоит точно такая же задача: построить свой цифровой мир. Не догоняющий и не копирующий, а свой.

Да, это сложно. Да, придется переучиваться. Придется забыть про "просто вставить готовую библиотеку с гитхаба" — потому что завтра её могут отозвать. Да и гитхаб заблокировать для пользователей "недружественной страны".

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

И да, нас ждут горы ошибок и тонны недальновидных, "топорных" решений. Но без этого, в мире гигантов мы останемся карликами.

Глобализация заканчивается. Начинается эра мастеров. И она уже идёт, прямо здесь и сейчас.


😎 @Oleborn
Please open Telegram to view this post
VIEW IN TELEGRAM
👍11🔥3