Будучи программистом, вы постоянно изучаете новые термины, техники и лучшие практики. Но что, если я открою целый мир понятий, о существовании которых многие программисты даже не подозревают, — понятий, которые могут полностью изменить ваш подход к написанию и осмыслению кода? Будь вы начинающим программистом или опытным профессионалом, эти 18 малоизвестных терминов помогут вам подняться на новый уровень в освоении JS
и Python
.
1. Преобразователь (thunk): извлечение пользы из отложенного выполнения
Вы когда-нибудь откладывали выполнение какого-либо действия до последнего момента? Thunk делает именно это — откладывает выполнение функции до тех пор, пока она не станет абсолютно необходимой.
Представьте, что у вас есть задача, которая требует больших затрат на вычисление, но вы не уверены, что результат вам понадобится. Вместо того, чтобы вычислять его заранее, оберните его в thunk.
const thunk = () => 5 + 10;
console.log(thunk()); // Вычисления происходят только при вызове
2. Монада (monad): защитная сетка для кода
Монада — своего рода защитная сетка для функций. Они помогают выстраивать цепочки операций и обрабатывать неожиданное поведение (например, ошибки или нулевые значения), не приводя к сбою всей программы. Если вы работаете с асинхронными данными, то наверняка уже использовали их, даже не подозревая об этом!
new Promise((resolve) => resolve(5))
.then(value => console.log(value)) // Вывод: 5
Чтобы монады не казались чем-то непостижимым, представляйте их как контейнеры, которые безопасно передают данные по конвейеру.
3. Замыкание (closure): код, который помнит
Представьте, что ваше прошлое «я» смогло бы передать вашему будущему «я» воспоминания даже после того, как ваше прошлое «я» осталось далеко позади. Именно это и делает замыкание. Оно позволяет функции «помнить» переменные из контекста, в котором эта функция была создана.
def counter(): count = 0 def _(): nonlocal count count += 1 return count return _ increment = counter() print(increment()) print(increment()) print(increment())
1 2 3
4. Мемоизация (memoization): будьте эффективны
Вам когда-нибудь задавали один и тот же вопрос снова и снова? Раздражает, правда? Ваш компьютер тоже так думает. Мемоизация решает эту проблему, сохраняя результаты, чтобы не повторять дорогостоящие вычисления.
def fib(n, memo={}): if n in memo: return memo[n] if n < 2: return n memo[n] = fib(n - 1, memo) + fib(n - 2, memo) return memo[n] fib(100) #354224848179261915075
5. Продолжение (continuation): держите будущее в своих руках
Продолжение — своего рода нажатие «паузы» в коде с сохранением последующих шагов на потом. Это секретный «ингредиент» многих асинхронных систем.
function asyncTask(callback) { setTimeout(() => { console.log("Task complete"); callback(); }, 1000); } asyncTask(() => console.log("Next step"));
- Через 1 секунду будет выполнен код внутри стрелочной функции
() => { console.log("Task complete"); callback(); }
.
Вы когда-нибудь сталкивались с асинхронным программированием? С коллбэком в конце? Это продолжение как взгляд в будущее, позволяющий определить, что будет дальше!
6. Идемпотентность (idempotence): делай правильно, даже если делаешь это 100 раз
В программировании некоторые действия должны иметь одинаковое поведение независимо от того, сколько раз вы их выполняете. Это и есть идемпотентность — вызываете ли вы API один раз или 100 раз, результат будет один и тот же.
GET /user/123 HTTP/1.1
Сколько бы вы ни вызывали GET /user/123
, всегда будете получать в ответ одного и того же пользователя. Мир API основан на этом принципе — именно он обеспечивает предсказуемость и безопасность.
7. Куайн (quine): программа, которая воспроизводит сама себя
Куайн — умная часть кода, которая выводит свой исходный код. Это все равно что посмотреть в зеркало и увидеть… свой генетический код, который смотрит прямо на вас.
s = 's = {!r}; print(s.format(s))'; print(s.format(s)) #output => s = 's = {!r}; print(s.format(s))'; print(s.format(s))
8. Зиппер (zipper): суперэффективная навигация по структурам
Навигация и модификация структур данных без нарушения порядка может оказаться непростой задачей. Вводим функцию zipper — и она позволяет эффективно перемещаться и изменять структуры (например, деревья), не разрушая оригинал.
class Zipper: def __init__(self, left, right): self.left = left self.right = right def move_left(self): return Zipper(self.left[:-1], [self.left[-1]] + self.right) def move_right(self): return Zipper(self.left + [self.right[0]], self.right[1:])
Зипперы — навигационный компас для сложных структур данных.
9. Функтор (functor): возможность отображения
Функтор — то, через что можно отобразить функцию. Это все равно что применять преобразование к каждому элементу в контейнере, не трогая сам контейнер. Это больше, чем просто функциональное программирование — это мощная комбинация.
numbers = [1, 2, 3] squared = list(map(lambda x: x ** 2, numbers)) print(squared) # [1, 4, 9]
Списки в Python являются функторами, что позволяет отображать операции без изменения исходной структуры.
10. TCO: бесконечная рекурсия без переполнения стека
TCO (tail call optimization — оптимизация хвостового/завершающего вызова) позволяет писать рекурсивные функции, не беспокоясь о нехватке памяти. Если функция вызывает саму себя в качестве последнего действия, TCO может повторно использовать стековый кадр текущей функции.
def factorial(n, acc=1): if n == 0: return acc return factorial(n - 1, acc * n)
Примечание: в примере выше показана только структура TCO, но помните, что Python не поддерживает TCO нативно.
11. Каррирование (currying): один аргумент за раз
Каррирование разбивает функцию, принимающую несколько аргументов, на ряд функций, каждая из которых имеет один аргумент. Это похоже на пошаговую реализацию рецепта.
def add(x): def inner(y): return x + y return inner add_five = add(5) print(add_five(3)) # 8
Каррирование — ключ к гибкости, если понадобится частично применить аргументы. Каррирование поддержит вас в этом.
Можете также использовать partial для каррирования функций.
from functools import partial def adder(a, b): return a + b two_adder = partial(adder, 2) two_adder(10) #12
12. Spectre и Meltdown: скрытые угрозы для CPU
Вы наверняка слышали о Spectre и Meltdown — печально известных уязвимостях, которые потрясли мир в 2018 году. Они воспользовались технологией оптимизации производительности современных процессоров для похищения конфиденциальных данных.
if (untrusted_input < array_size) { temp = array[untrusted_input * 512]; }
Эксплойты высокой производительности вернулись, чтобы преследовать нас. Спекулятивное исполнение может ускорить работу, но иногда дает больше утечек, чем нам хотелось бы!
13. Гомоморфизм (homomorphism): сохранение структуры
Гомоморфизм — модное слово для обозначения функции, которая сохраняет структуру двух алгебраических систем. Это очень важно как в математике, так и в программировании при преобразовании данных (гомоморфизм — одна из важнейших концепций функционального программирования).
numbers = [1, 2, 3, 4]
def square(x):
return x * x
squared_numbers = list(map(square, numbers))
print(squared_numbers)
# Вывод: [1, 4, 9, 16]
14. Ленивая оценка (lazy evaluation): только тогда, когда нужно
Ленивая оценка откладывает оценку выражения до тех пор, пока не понадобится значение. Это полезно для повышения производительности в программах с большими наборами данных или вычислениями.
def lazy_range(n): i = 0 while i < n: yield i i += 1 for num in lazy_range(5): print(num)
Генератор в данном случае вычисляет значения только по мере необходимости, экономя память и время обработки.
В чем разница между преобразованием и генераторами?
- Ленивая оценка — стратегия откладывания оценки выражения до тех пор, пока его значение не понадобится. Она помогает оптимизировать производительность, избегая ненужных вычислений, особенно при работе с бесконечными структурами данных или при выполнении дорогостоящих операций.
- Преобразование (thunk) — особая техника, используемая для реализации ленивой оценки. По сути, это функция без аргументов, которая заключает в себе вычисления или выражения. Вычисления откладываются до явного вызова thunk.
15. Каноникализация (canonicalization): нормализация данных
Каноникализация — процесс преобразования данных в стандартную или нормализованную форму. Он часто используется в базах данных и URL для обеспечения согласованности.
http://example.com https://example.com http://www.example.com
Каноникализация гарантирует, что все они будут указывать на одну предпочтительную версию.
16. Побочный эффект (side effect): больше, чем вы ожидали
Побочный эффект возникает, когда функция или выражение модифицирует состояние вне своей локальной среды, например изменяет глобальные переменные, операции ввода-вывода или модифицирует входные аргументы.
def add_to_list(value, lst=[]):
lst.append(value)
return lst
print(add_to_list(1)) # [1]
print(add_to_list(2)) # [1, 2] (неожиданно!)
В этом примере функция модифицирует аргумент по умолчанию, вызывая непредвиденные побочные эффекты.
17. Поднятие (hoisting): перемещение объявлений вверх
В JavaScript на этапе компиляции поднятие перемещает объявление переменных и функций в верхнюю часть содержащей их области видимости.
console.log(x); // undefined var x = 5;
Несмотря на то, что x
объявляется после console.log
, JavaScript поднимает объявление вверх, делая x
доступным еще до его определения.
18. Моноид (monoid): последовательное объединение данных
Моноид — алгебраическая структура с бинарной операцией и нейтральным элементом, позволяющая объединять данные ассоциативным способом.
result = ''.join(['a', 'b', 'c']) print(result) # 'abc'
Здесь конкатенация строк образует моноид с ''
в качестве нейтрального элемента и +
в качестве бинарной операции.
Заключение
Эти продвинутые термины программирования поначалу могут показаться слишком сложными, но их понимание значительно улучшит ваш подход к написанию кода. Будь то оптимизация производительности, безопасности или читабельности, эти понятия дадут вам мощные инструменты для решения сложных проблем изящными способами.
Читайте также:
- 5 реальных способов достичь сбалансированности трудовой жизни
- Понимание шаблонов проектирования: шаблон “Строитель”
- Как обнаружить дублирование кода в проекте
Читайте нас в Telegram, VK и Дзен
Перевод статьи Rahul Beniwal: 18 Programming Concepts You’ve Never Heard of (But Should!)