Программисты часто ставят перед собой множество дилемм, в частности, вопрос о прогрессивности стека технологий. Вот и я, находясь на позиции «junior», столкнулся с необходимостью оптимизации кода – и после частого откладывания этого вопроса на потом мне всё же пришлось поднять его снова. Сегодня я бы хотел поделиться своим опытом на эту тему.
Как я пришёл к этому
При работе над продакшн-разработкой и написании пет-проектов я часто задумывался о лаконичности и унификации кода и архитектуры, а также об оптимизации их производительности.
Я думаю, что многим программистам по мере их профессионального роста и наращивания стека технологий сильно не хватает времени. Это касается как технических аспектов (например, проектирование архитектуры или масштабируемость приложений), так и общей организации работы. Даже если не учитывать все эти нюансы, вход в новый проект требует значительных временных затрат на изучение теории и создание портфолио, особенно для стажеров и джуниоров.
По мере вхождения в проект, изучая документацию и инфраструктуру, я начал чаще сталкиваться с вопросами, связанными с ускорением алгоритмов и потреблением памяти, я также интересовался прокачкой хард-скиллов. Если раньше мне было достаточно базовых возможностей LINQ, то с увеличением объёмов данных из внешних источников я задумался о рефакторинге и смене подходов к разработке.
В конечном итоге я начал пересматривать использование различных алгоритмов — как встроенных в библиотеки, так и собственных решений. В сложных случаях это становится ключевым фактором при выборе архитектуры и методов оптимизации.
Пример
Для наглядности приведу недавний пример.
Представим, что доступ к базе данных осуществляется только через REST API, который не поддерживает фильтрацию, но позволяет сортировать данные по определённому полю. В такой ситуации возникает вопрос: как эффективно извлечь три последовательных элемента из полученного набора?
На первый взгляд задача простая: найти нужный элемент, а далее — найти предыдущий и последующий по индексам элементы. Однако стандартная реализация поиска в LINQ использует линейный перебор, что при большом объёме данных может серьёзно замедлить обработку. Особенно, если учитывать задержки на стороне сервиса.
Для этого конкретного случая я де-факто выбрал бы бинарный поиск, который значительно ускорил бы выполнение операции.
Вопрос по обучению
Когда встал вопрос об обучении, из множества вариантов я выбрал, на мой взгляд, самый быстрый и оптимальный способ с использованием искусственного интеллекта. Такой выбор был неслучайным, так как я поставил перед собой сжатые сроки и тем самым отсеял книги и курсы с большим объёмом информации.
Для структурированного обучения я выбрал LeetCode, так как в нём представлено множество учебных планов. Для этого выделил сразу ряд ее плюсов:
Главное, платформа помогает научиться решать технические задачи.
Имеет достаточно большое комьюнити – а это в свою очередь в сравнении с банальными курсами и книгами даёт большее преимущество между выбором способа извлечения информации.
Помогает разнообразить пути решения задач на основе уже представленных решений другими разработчиками.
Чтобы не отказываться от удобства среды разработки, я писал код в Visual Studio, предоставляя себе все удобства в написании кода, такие как профилирование и отслеживание итераций, наряду с другими полезными функциями.
Процесс обучения
Учитывая все имеющиеся временные ресурсы, а именно 4-6 внерабочих часов, я установил рамки для обучения. В качестве основы для построения алгоритмической базы выбрал первый попавшийся план – как мне показалось, это было бы хорошим стартом. План включал изучение базовых алгоритмов для массивов и строк, постепенно переходя к битовым манипуляциям, суровым структурам данных и динамическому программированию.
Не впадая в долгие раздумья и основываясь скромными требованиями к модели, в качестве ментора выбрал DeepSeek.
Первый шагом на пути к обучению заключался в разборе алгоритмов: их определении и объяснении принципов работы. Посчитав, что избыточность информации будет лишней, для быстрого погружения в темы брал за основу лаконичные промпты как для определений, так и для описания работы самих алгоритмов. В качестве примера выступит бинарный поиск c последующим описанием алгоритма псевдокодом.


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



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

Так был написан код по каждому пункту:






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

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