job4j.ru - Практика. Ревью. Результат.
771 subscribers
75 photos
186 links
О жизни в IT:
- Языки: Go, Rust, Java, Kotlin
- Технологии: PostgreSQL, Kafka
- Инфраструктура: Docker, Kubernetes
- Soft Skills: общение, интервью, карьера
Download Telegram
Задачи на эту неделю

https://leetcode.com/problems/climbing-stairs/
Темы: динамическое программирование

https://leetcode.com/problems/rotate-array/
Темы: массив, циклические сдвиги, реверс

https://leetcode.com/problems/third-maximum-number/
Темы: массив, сортировка или трёхкомнатный учёт

https://leetcode.com/problems/plus-one/
Темы: массив, симуляция сложения

https://leetcode.com/problems/pascals-triangle/
Темы: массив, динамическое программирование

https://leetcode.com/problems/intersection-of-two-linked-lists/
Темы: односвязный список, два указателя

https://leetcode.com/problems/linked-list-cycle/
Темы: односвязный список, два указателя (черепаха и заяц)

https://leetcode.com/problems/symmetric-tree/
Темы: дерево, рекурсия или BFS

https://leetcode.com/problems/single-number/
Темы: массив, побитовое XOR

https://leetcode.com/problems/majority-element/
Темы: массив, голосование Бойера–Мура или хэш-таблица

Черканите, в комментариях, кто еще пробует со мной этот марафон.
👍4
Шаблон Request - Reply

Добавил урок в курс https://job4j.ru/profile/courses/21
Request-Reply шаблон [#505464]

У кого есть желание может попробовать решить задание тоже.

В этом уроке мы поговорим об асинхронной природе Kafka.

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

А теперь представьте ситуацию: у вас есть сервис A, который принимает от клиентов запрос через REST API. Ему нужны данные от сервиса B, который в вашей архитектуре общается только асинхронно, то есть через Kafka. Возникает неприятная ситуация конфликта двух идеологий: синхронного и асинхронного общения.

Очевидное решение такой проблемы — заблокировать синхронный вызов до момента прихода асинхронного ответа. Эта идея выражена в шаблоне Request-Reply. В Spring Cloud Kafka есть готовая реализация этого шаблона, но мы будем реализовывать её самостоятельно.

Сначала рассмотрим простую ситуацию без очередей.

* Thread — клиент REST API.
* Thread — асинхронный клиент Kafka.
* ReqReply — контейнер, который блокирует Thread REST API на заданное время. Если в это время приходит ответ от Thread Kafka, контейнер разблокируется и возвращает ответ.

package ru.job4j.kafka.reqreply

import java.util.concurrent.FutureTask

class ReqReply(val timeout: Long) {
private val monitor = Object()
private var message = ""
private var received = false

fun send(): String {
synchronized(monitor) {
if (!received) {
try {
monitor.wait(timeout)
} catch (e: InterruptedException) {
Thread.currentThread().interrupt()
return "Interrupted while waiting"
}
}
return if (received) message else "Happened timeout $timeout"
}
}

fun receive(text: String) {
synchronized(monitor) {
received = true
message = text
monitor.notifyAll()
}
}
}

fun main() {
val reply = ReqReply(10)
val task = FutureTask({
reply.send()
})
Thread(task).start()
Thread({
Thread.sleep(500)
reply.receive("Send message")
}).start()
println(task.get())
}


Напомню, что здесь происходит:
— wait переводит нить в режим ожидания и освобождает монитор.
— notifyAll переводит все нити, ожидающие на мониторе, в состояние RUNNING.

Задание:

1. Доработайте код, приведённый выше, так, чтобы он работал с ключом correlationId:


   val correlationId = UUID.randomUUID().toString()
val reply = ReqReply(10)
val task = FutureTask({
reply.send(correlationId)
})


2. Добавьте тесты (три сценария):

* send(correlationId = 1), receive(correlationId = 1)
* send(correlationId = 1), таймаут
* send(correlationId = 1), receive(correlationId = 2), таймаут

3. Загрузите код в репозиторий и оставьте ссылку на изменения.
👍6🔥1
Channel name was changed to «Job for Java»
Алго-марафон | 4 Неделя

Я продолжаю решать алгоритмы на Leetcode, но скажу, что переоценил свои усилия. За прошлую неделю решил только три задачи на динамическое программирование. Как я и говорил, они у меня вызывали сложности, потому что я в них не особо разобрался.

Сегодня перечитывал раздел о динамическом программировании в книге "Грокаем алгоритмы". Вроде бы написано довольно просто, но всё равно вызывает сложности в понимании.

Хочу предложить вам свой вариант разбора алгоритмов с динамическим программированием.

Начну с того, как определить задачу с ДП (динамическим программированием, далее по тексту):

* Имеет оптимальные подзадачи — задачу можно разбить на несколько меньших, которые решаются отдельно.
* Есть повторяющиеся вычисления — одна и та же подзадача решается несколько раз.
* Зависит от предыдущих решений — решение задачи зависит от решений предыдущих подзадач (перекрывающиеся подпоследовательности или выборы).

Рассмотрим задачу с вычислением числа Фибоначчи.
Само определение чисел Фибоначчи говорит о том, что у нас есть повторяющиеся вычисления.
Число Фибоначчи вычисляется как сумма n - 1 и n - 2.
У чисел Фибоначчи есть начальные значения: f(0) = 0, f(1) = 1, f(2) = 1.

И теперь главное правило: когда мы начинаем решать задачу на ДП, мы начинаем её с массива dp, где будут храниться промежуточные результаты.

Второй обязательный элемент — это инициализация начального состояния. В данном случае мы заполняем ячейки 0, 1, 2 изначально известными значениями.

Теперь задача сводится к заполнению массива.

https://leetcode.com/problems/fibonacci-number/description/

Попробуйте решить её на Java.

А я приведу пример на Go:

func fib(n int) int {
if n == 0 {
return 0
}
if n == 1 || n == 2 {
return 1
}
dp := make([]int, n + 1)
dp[0], dp[1], dp[2] = 0, 1, 1
for i := 3; i <= n; i++ {
dp[i] = dp[i - 1] + dp[i - 2]
}
return dp[n]
}


Особенность этой задачи в том, что нам изначально известна зависимость последовательности.
Посмотрите на другой пример, где тоже изначально известна зависимость последовательности:
https://leetcode.com/problems/pascals-triangle/?envType=problem-list-v2&envId=dynamic-programming.

Идем по шагам:

1. Создаем массив. В данном случае он будет двумерным.
2. Инициализируем начальные состояния.
3. Вычисляем последующие значения на основании предыдущих.

В задачах посложнее вам нужно будет самостоятельно найти закономерность последовательности:
https://leetcode.com/problems/min-cost-climbing-stairs/description/?envType=problem-list-v2&envId=dynamic-programming.

Давайте начнем с начальных этапов:

1. Создаем массив.
2. Инициализируем начальные состояния. 0 шагов — стоимость 0, 1 ступенька — cost(1), 2 ступеньки — cost(2).
А теперь нужно посчитать стоимость движения по 3 ступеньке. Она будет равна стоимости самой ступеньки плюс стоимости ступеньки, с которой мы пришли.
И тут есть нюанс: мы можем шагнуть либо с предыдущей ступеньки, либо с предпредыдущей.
Так как нам нужна минимальная стоимость, мы должны выбрать тот путь, который будет дешевле.

Этот раздел я также добавлю в наш курс: https://job4j.ru/courses/32.
Изначально его не добавил, так как на собеседованиях не встречал, но потом вспомнил, что было собеседование, где нужно было вычислить количество способов размена купюры монетами. У нас есть подобная задача в разделе "Базовый синтаксис", которая решается через жадный алгоритм, но для ответа на возможное количество способов нужно использовать решение через ДП.
🔥5
Из Java в Go за 5 месяцев | Пошаговый план

https://youtu.be/c5xlrhRQrVE?si=d-bsrlmYSwUuxAft
🔥6
Топ 5 заблуждений о GoLang

В этой статье хотел бы рассказать о 5 заблуждениях о языке Go. Я сам попался на эти мифы, когда только начал изучать Go.

Go — это простой язык

Это самый большой миф о языке. Причем его распространяют повсеместно, и это часть маркетинга компании, причем крайне успешно. Я, например, тоже попался на это, но теперь понимаю, что Go совсем не легкий язык. С первого взгляда действительно язык выглядит компактным: базовые конструкции программирования (условия, циклы), три структуры данных (массив, слайс и карта), не до ООП, не до ФП и козырь горутины.

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

Небольшой пример из моего проекта — антиспам-бот:

func NewConnect(path string) (*sqlx.DB, error) {  
cfg, err := load(path)
if err != nil {
return nil, &ConfigError{message: fmt.Sprintf("failed to load config from %s", path)}
}
cnn, err := sqlx.Connect(cfg.driverName, cfg.dsn)
if err != nil {
return nil, &DbError{message: fmt.Sprintf("failed to connect to %s", err.Error())}
}
return cnn, nil
}

db, err := database.NewConnect(".env")
defer func() {
if err := db.Close(); err != nil {
log.Printf("error closing db: %v", err)
}
}()
if err != nil {
log.Printf("Error connecting to database: %v", err)
return
}


Если при создании подключения что-то пошло не так, указатель на db будет nil, а в функции defer мы пытаемся вызвать у него метод, что приведет к panic.

Go — выразительный и лаконичный

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

Я думал, что то же самое будет с Go. И действительно, первые программы на LeetCode выглядели компактными. Но когда я перешел к написанию своего проекта, dionea, я сразу понял, что писать придется много. Причем иногда код прямо повторяется, особенно при работе с объектами error.

if err != nil {
return fmt.Sprintf("occurred error %v", err)
}


Пример — функция-обертка для транзакций:

func tx(db *sqlx.DB, logic func(tx *sql.Tx) error) error {  
tx, err := db.Begin()
if err != nil {
return err
}

var logicErr error
defer func() {
if logicErr != nil {
rbErr := tx.Rollback()
if rbErr != nil {
log.Printf("Error during rollback: %v", rbErr)
}
}
}()
logicErr = logic(tx)
if logicErr != nil {
return logicErr
}
logicErr = tx.Commit()
if logicErr != nil {
return logicErr
}
return nil
}


Аналогичный код на Java:

public <T> T tx(Function<Session, T> command) {
Session session = sf.openSession();
Transaction transaction = null;
try {
transaction = session.beginTransaction();
T rsl = command.apply(session);
transaction.commit();
return rsl;
} catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
throw e;
} finally {
session.close();
}
}


В Go нет ООП

Для меня этот пункт был самым интересным в начале моего пути в Go. Как же решаются вопросы без ООП? Как оказалось, все там есть — и ООП, и ФП, и даже процедуры.

Главный аргумент: как же ООП без наследования?

Оно тоже есть через embedded struct. Причем даже с ромбической проблемой. Но в Go есть философия: «Вот так делать не надо». Самое забавное, что в своих Java и Kotlin проектах я тоже придерживаюсь принципа замены наследования на композицию. А в учебных проектах настоятельно прошу студентов избегать использования наследования.
👍7
В Go нет фреймворков

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

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

В Go высокие зарплаты

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

Итог

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

Go дает возможность детально разобраться в задачах, которые мы делаем, не задумываясь. Например, аннотация @Transaction в Spring кажется простой, но если вы попробуете спроектировать подобную систему в Go, то поймете, что это крайне сложно. Go позволяет сфокусироваться на конечных технологиях: базе данных, синхронному и асинхронному общению, реализации авторизации и аутентификации, а не на особенностях конфигурирования фреймворков, как это бывает в Java.

Если вы рассматриваете язык только с точки зрения повышения зарплаты, то лучше посвятите это время прокачке целевых областей в вашем стеке и предметной области. Это принесет больше пользы и увеличение зарплаты, чем еще один язык в резюме с базовыми знаниями.
💯9👍7🔥5
Мок-собеседование

На нашей платформе есть раздел мок-собеседования.
Некоторое время назад я хотел вынести все разделы, связанные с собеседованиями, в отдельный проект, но не учел момент с привязанностью пользователей. У нас есть привычки, и чтобы их изменить, нужно приложить много усилий. Поэтому на сайт никто не стал заходить.
Я вернул функцию мок-собеседований на основную платформу, но интерес к ней потерялся.
А сейчас, когда мы проводим эксперимент с Go, такая функция оказалась востребованной.
Напомню, как она работает.
Вы хотите обсудить какой-то раздел, например, SQL — оптимизация запросов, индексы, explain.
Создайте новое мок-собеседование. Указываете, о чём хотели бы поговорить.
Ранее я настаивал, чтобы мок-собеседование было жёстко разделено на роли: тот, кто накидывает вопросы, и тот, кто старается ответить.
В новой версии я хотел бы уйти от этих жёстких правил. То есть цель мок-собеседования — поговорить на ту или иную тему.

https://job4j.ru/interviews
👍14
Курс DevOps | Метрики Prometheus

Добавил уроки про метрики Prometheus.

Системные метрики приложений [#505467]
Бизнес-метрики приложений [#505468]

Вчера просматривал очередное мок-собеседование по Go. Обратил внимание, что часто спрашивают вопросы про сбор метрик.
То есть теперь рынок требует не просто написать микросервис, но также и полноценно его внедрить.

Перечислю основные метрики.

Метрики производительности

* Время отклика
* Задержки
* Пропускная способность
* Частота ошибок

Метрики здоровья приложения

* Аптайм приложения
* Жизненные циклы
* Состояние базы данных
* Метрики JVM

Метрики работы с базой данных

* Количество запросов
* Типы запросов
* Задержки запросов

Метрики приложений

* Загруженность приложений
* Использование процессора и памяти

Метрики безопасности

* Аутентификация
* Авторизация

Метрики для работы с очередями

* Обработка сообщений
* Ошибки обработки сообщений

Метрики кэширования

* Работа с кэшем
* Размер кэша

Метрики приложения в облаке

* Использование ресурсов в облаке
* Использование облачных хранилищ

Метрики для Spring Security

* Проверки авторизации
* Ошибки доступа

Метрики для Spring Actuator

* Метрики запросов в Actuator
* Статистика по здоровью и меткам

Курс: https://job4j.ru/courses/35
🔥10👍3
Преза курса Go | C нуля до работы

https://job4j.ru/courses/38

В 2025 году я обратил внимание на язык Go. До этого я уже начал писать код для серверной стороны на Kotlin. У меня даже был порыв написать что-то на Python. Зачем? Для меня быть программистом — это придумывать технические решения. Чем больше у тебя в арсенале инструментов, тем проще подобрать быстрое и лучшее решение. В целом Java и языки JVM — это отличное решение, но Go предлагает нечто другое.

Скорость. Сверхбыстрая компиляция и такая же скорость выполнения самого приложения.
Исполняемые артефакты. Написал утилиту — и сразу можешь использовать её на сервере. Ничего дополнительно ставить не нужно.
Работа в многопоточной среде как с последовательным кодом. Просто и понятно.
Философия минимализма. В самом языке есть всё необходимое, а если чего-то нет — пиши сам.
На данный момент этот курс — эксперимент. Поэтому принять в нём участие можно бесплатно. Регистрируйтесь на платформе и пишите мне в Telegram @parsentev.

Этот курс мы создаём вдвоём с Михаилом. О его опыте и мыслях вы можете почитать в его Telegram-канале https://t.me/liferefactoring.

Весь курс можно разделить на две части.

Практическая часть, в которой ученики создают проект в микросервисной архитектуре. Хотелось бы акцентировать внимание на стеке. Он практически идентичен стеку в Java: Docker, Kubernetes, Kafka, Makefile, PostgreSQL, REST API, gRPC, Protobuf, Redis.

Другая часть — подготовка к собеседованиям. К сожалению, вам придётся зубрить теорию. Почему к сожалению? Потому что это не творческий процесс, но необходимый. Что сюда войдёт: обсуждение slice, map, error handling, goroutines и т. д. Не забудем и про алгоритмы.

Обучение строится по уже традиционным принципам нашей школы:

Весь материал представлен в виде уроков.
Каждый урок — это задание.
Задания проверяем мы — я и Михаил. Это code-review. Мы строгие, поэтому часто приходится переделывать ваши решения.
Разбор теории. Это подготовка к собеседованию.
В курсе около 150 уроков. Почему так много и нельзя ли быстрее?

Дело в том, что смена стека может привести к снижению уровня дохода. Чтобы этого избежать, вам нужно достичь того же уровня, что и ваш целевой язык, а ещё лучше — превзойти его. То есть если вы уже Middle, то искать работу нужно на Senior.

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

Но опять же, если у вас не такие амбиции, то, конечно, можно готовиться не так усиленно и согласиться на меньшую зарплату.
👍15🔥6❤1
job4j.ru - Практика. Ревью. Результат. pinned «Преза курса Go | C нуля до работы https://job4j.ru/courses/38 В 2025 году я обратил внимание на язык Go. До этого я уже начал писать код для серверной стороны на Kotlin. У меня даже был порыв написать что-то на Python. Зачем? Для меня быть программистом…»
Курс Kafka | Request Reply + Rest API

Добавил урок:
Request-Reply c Rest API | Javalin [#505469]

Описание курса 👉 https://job4j.ru/courses/21
🔥7
Велосипеды и структуры данных

В Go есть три основных структуры данных: массивы, срезы (slice) и отображения (map). По сути этих структур достаточно, чтобы решить 99 % бизнес‑задач. Раньше на собеседованиях я любил спрашивать: «Где используется связанный список?» Обычно никто не мог на это ответить, потому что на практике такие задачи встречаются редко.

Другое дело — алгоритмическая секция собеседования. Её избежать нельзя, а значит вам нужно помнить и, что ещё лучше, уметь реализовать основные структуры данных на Go.

Set

Set — это набор уникальных элементов. Реализуем функцию, которая убирает из среза дубликаты:

func UniqueInts(data []int) []int {
seen := make(map[int]struct{}, len(data))
result := make([]int, 0, len(data))
for _, v := range data {
if _, ok := seen[v]; !ok {
seen[v] = struct{}{}
result = append(result, v)
}
}
return result
}


Важные моменты:

* В качестве значения в map используется пустая структура (struct{}), она занимает 0 байт.
* При создании map и среза полезно указывать ожидаемый размер: это уменьшает число перераспределений памяти.
* Срез создаётся с длиной 0, но с capacity, равным длине входного среза, — так не нужно будет «эллоцировать» память при добавлении новых элементов.

LinkedHashSet и SortedSet

В Go map не сохраняет порядок элементов (он случайный). Чтобы получить LinkedHashSet, нужно дополнительно хранить срез вставленных значений. Для SortedSet достаточно отсортировать срез:

sort.Ints(nums)


Stack

LIFO (Last In, First Out) — последний зашёл, первый вышел.

type Stack struct {
data []int
}

func (s *Stack) Push(v int) {
s.data = append(s.data, v)
}

func (s *Stack) Pop() (int, bool) {
if len(s.data) == 0 {
return 0, false
}
v := s.data[len(s.data)-1]
s.data = s.data[:len(s.data)-1]
return v, true
}

func main() {
s := &Stack{}
s.Push(1)
s.Push(2)
for {
e, ok := s.Pop()
if !ok {
break
}
fmt.Println(e)
}
}


Все операции выполняются через append и срезы, без прямой работы с индексами элемента.

Queue

FIFO (First In, First Out) — первый пришёл, первый вышел.

type Queue struct {
data []int
}

func (q *Queue) Push(v int) {
q.data = append(q.data, v)
}

func (q *Queue) Pop() (int, bool) {
if len(q.data) == 0 {
return 0, false
}
v := q.data[0]
q.data = q.data[1:]
return v, true
}

func main() {
q := &Queue{}
q.Push(1)
q.Push(2)
for {
e, ok := q.Pop()
if !ok {
break
}
fmt.Println(e)
}
}


Где применяются Stack и Queue?

Они часто используются при обходе деревьев в глубину и ширину. Например, для задачи «Симметричное дерево»:
[https://leetcode.com/problems/symmetric-tree/](https://leetcode.com/problems/symmetric-tree/)

Задание

1. Дан двумерный массив, содержащий отчёт об участии в соревновании. Каждая строка массива — это один день, а элементы строки — результаты участника: его ID и Amount.
2. Если участник пропустил какой‑то день, он не учитывается в соревновании.

package main

import "fmt"

type MemberStat struct {
ID int
Amount int
}

type Champs struct {
IDS []int
Amount int
}

func main() {
stat := [][]MemberStat{
{{ID: 1, Amount: 5}, {ID: 2, Amount: 6}},
{{ID: 1, Amount: 15}, {ID: 2, Amount: 10}},
}
champs := getChamps(stat)
fmt.Printf("Champs: %v, %d", champs.IDS, champs.Amount)
}

func getChamps(stat [][]MemberStat) Champs {
return Champs{}
}


### Тесты
👍6
package main

import (
"testing"

"github.com/stretchr/testify/assert"
)

func TestGetChamps_Standard(t *testing.T) {
stat := [][]MemberStat{
{{ID: 1, Amount: 5}, {ID: 2, Amount: 6}},
{{ID: 1, Amount: 15}, {ID: 2, Amount: 10}},
}

got := getChamps(stat)
want := Champs{IDS: []int{1}, Amount: 20}

assert.ElementsMatch(t, want.IDS, got.IDS, "должен вернуть только ID чемпиона")
assert.Equal(t, want.Amount, got.Amount, "сумма очков должна быть максимальной")
}


Описание курса 👉 https://job4j.ru/courses/38
👍3
Рынок IT в 2025 | Наваливаем кринжа

Чтобы провести аналитику IT-рынка в этом году, я ждал 9 мая.
Все запланированные встречи состоялись, теперь можно подвести итоги и сделать предположения о перспективах.

Зачем это нужно? Ценностей всего две:

1. Ресурсы — то есть деньги;
2. Предназначение.

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

Начнём с цифр — количества вакансий по ключевым направлениям:

* Python ML: 1176 ↓ 26
* React + TypeScript: 1006 ↓ 23
* JS + Vue: 927 ↑ 2
* Java + Spring: 891 ↓ 16
* C# + .NET: 842 ↓ 17
* Go + Docker: 730 ↓ 18
* PHP + Laravel: 700 ↓ 17

Для сравнения: в 2023 году по каждому из этих направлений было около 2500 вакансий, а в 2022 — примерно 5000. Рынок явно просел. Пора ли искать новое направление?!

Теперь разберём причины — в обратном порядке, от незначительных к наиболее важным.
👍7🤔3🤯3😱2
LLM

Вы знаете, в каком году были созданы первые алгоритмы машинного обучения? Они появились в середине XX века. А с 2017 года нас пугают тем, что системы на базе LLM заменят всех — от программистов до врачей.

Я не раз пытался перейти от «ручного» программирования к vibe coding, но каждый раз бросал это занятие. К счастью, я посмотрел интервью Андрея Бреслава о его новом языке на основе LLM. Настоятельно рекомендую его посмотреть: «Андрей Бреслав и vibe coding».

В ролике он чётко описал два способа взаимодействия с LLM:

1. Как генератор кода.
Вы можете просто попросить сгенерировать код, но при этом должны понимать, что он делает. Например:
«Создай модель User с такими-то полями, а также контроллер, сервис и репозиторий для неё».

2. Как «чёрный ящик».
Вы не знаете, как написать код, и просите LLM добавить нужное поведение. Например:
«Сделай программу, которая будет авторизоваться на hh.ru под моей учёткой и откликаться на вакансии по заданным критериям».

Научными терминами это императивный и декларативный подходы. Язык Java — императивный: мы описываем, что нужно сделать. SQL — декларативный: мы указываем, какой результат хотим получить, но не знаем, как он будет достигнут.

Немного подробнее:

* LLM как генератор кода.
Сложность в том, что сгенерированный код нужно проверять: скорость разработки от этого не повышается, а лишь снижается, поскольку сначала нужно разобраться, как программа работает, а затем убедиться в её корректности.

* LLM как генератор полноценной программы.
LLM — это не компилятор, а статистическая модель: сгенерированный результат — вероятностный, а не гарантированный. Да, модель выдаёт высокий процент правильных случаев, но не 100 %. Кроме того, современные LLM испытывают проблемы с добавлением новых функций: чем больше уточнений, тем хуже результат. Поддерживать такие системы будет сложно.

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

Несомненно, LLM будут внедряться там, где не требуется точный результат: в колл-центрах, системах машинного перевода, чат-ботах, рекомендательных системах, фильтрации контента, продажах и т. д. Но в серьёзном программировании это пока не заменит профессионала.

Не верите? Попробуйте сами: поставьте Cursor и напишите игру «Змейка» на Python.
👍8🤔4
Курсы и инфобизнес

А при чём тут это? Кто обычно становится программистом? «Ботаники» — щуплые ребята в очках и свитерах, увлечённые математикой, физикой и компьютерными играми. А что сделали курсы по программированию? Они дали возможность работать в мире «ботаников» тем, кто сам ботаником не является.

За счёт чего? В первую очередь — за счёт социальных навыков. Задачи, которые выполняет рядовой программист, по силам любому человеку с техническим складом ума, а не только компьютерному гику. Соответственно на рынок хлынули мало или вовсе не менее способные люди с техническим складом ума. Тем самым сформировалась жёсткая конкуренция. Причём это уже не конкуренция среди ботаников, которые в присутствии незнакомых людей не могут связать и двух слов, а среди уверенных в себе специалистов, владеющих приёмами продажников и другими манипуляциями в переговорах.

Сейчас здесь идёт настоящий «пир во время чумы»: те, кто умеют продавать, рассчитывают на зарплату 600–800 тыс. ₽, а те, кто не умеют, — опускают ставку ниже 200 тыс. ₽.
👍10😁2
Автоотклики

Здесь стоит начать с жаргона. Мы сами навалили этот кринж. На курсах учат продавать себя: например, создавать несколько резюме, использовать автоотклики и т. д. HR не могут справиться с таким количеством нерелевантных откликов, и им на помощь приходит автоматизация. На автоотклик мы получаем автоотказ. Таким образом мы дополнительно создаём иллюзию запредельной конкуренции.

Объясните мне: как за 10 минут в новой вакансии появляется 100 откликов? Ребята, мы сами создали такую ситуацию.

Главный «кринж» в том, что я продолжаю наблюдать, как осознанные меркантилы говорят, что нужно продолжать автоматизировать поиск. Если вы задумались написать своего бота для автооткликов, то уже поздно — эта схема больше не работает.
👍7😁2
Глобальный кризис

Все перечисленные выше пункты меркнут по сравнению с главным — глобальным кризисом. Почему в 2022 году IT-рынок сократился вдвое? Потому что из России ушли инвесторы. Кто владеет капиталом, тот и диктует условия. К 2025 году ситуация лишь обострилась, но уже не только на российском рынке, а в глобальном масштабе. Этот факт — главная причина кризиса в IT, а не LLM или количество кандидатов.

У бизнеса нет возможности запускать новые проекты, поэтому всё, что не приносит дохода, замораживается. Внимание переключается на те проекты, которые приносят прибыль.

Требования к кандидатам тоже изменились: теперь нужны знания в разных областях и умение решать задачи по оптимизации и поддержанию проектов.
👍8🤔3