Это перевод статьи Артёма Чистякова "The language of programming", породившей интересные дискуссии на HackerNews и Reddit.
Я помню, как изучал свой первый язык программирования. Мы должны были освоить какой-то из диалектов BASIC в рамках обязательной школьной программы по информатике для второго класса. Скрючившись на своих партах под тусклыми флуоресцентными лампами, мы нетерпеливо поглядывали на жужжащие компьютеры IBM, расставленные вдоль стен душной классной комнаты. Это был 1997 год, Россия. Ни у кого из нас не было домашнего компьютера. На доске в меловых разводах учитель написала:
SCREEN 15, 0
PSET (100, 100)
DRAW "R20 D20 L20 U20"
END
Вместе с двадцатью парами таких же озадаченных глаз, моё восьмилетнее сознание недоверчиво глазело на представленную учителем "криптограмму". "Не пугайтесь," — заявила учительница своим мягким обнадёживающим тоном. Она заставляла нас рисовать блок-схемы несколько недель подряд, подводя к этому уроку. Мы уже были способны конструировать "алгоритмы" для чистки картошки и сборки лего. Но латинские символы, недоброжелательно поглядывающие на нас с доски, смотрелись чужеродно.
Учительница продолжила расшифровывать программу строчку за строчкой. Избегая перевода с английского, она присваивала каждой лексеме значение и мотивировала нас запоминать их. Спустя некоторое время, мы посмотрели на программу и интерпретировали её, как если бы она была написана эмоджи.
🔲
➡️ 100
⬇️ 100
🖌 "➡️ 20 ⬇️ 20 ⬅️ 20 ⬆️ 20"
🏁
Я всё ещё часто вспоминаю тот подход к обучению программированию и о том, как он избегает отношений с языком-оригиналом. Это же невероятно, как набор простых команд, которые задуманы быть самоописательными для тех, у кого английский — родной, оказывается серьёзной задачей для любых иноязычных кодеров. А мы были именно кодерами. Двадцать с лишним маленьких компиляторов.
Абстрактное программирование
Ещё десять лет, и я — студент, изучающий алгоритмы и структуры данных. Мы пишем на C/C++, и все в какой-то степени знаем английский. Но все наши конспекты на русском, а стандартные названия библиотечных функций представлены без каких-либо намёков на их оригинальные значения. На вступительной лекции профессор представляет "Hello, World!" и другие простые программы на С. Он произносит каждое название функции медленно, записывая его на доске. В его интерпретации getch() звучало как "гэт-чэ", а clrscr() — "ке-ле-эр-эс-хе-йер". Сейчас в это сложно поверить, но перед тем, как во мне что-то щёлкнуло и я увидел "get character" и "clear screen", прошло время. Потом я поделился тем, что заметил со своими однокурсниками, и они были так же удивлены.
Заглядывая в прошлое, я теперь понимаю, как порванная с языком-оригиналом связь лишила нас чего-то полезного. Хотя, такой метод изучения языка программирования — наглядный, потому что он очень близок к абстрактной математике. Это он побудил нас видеть char *strstr(const char *haystack, const char *needle) как Ω(x,y). Даже если функция имела запутывающее название, никто из нас не замечал, потому что оно не слишком отличалось от другой случайной лексемы, которую мы должны были запомнить. Когда вы программируете таким способом, документация — царь, а названия — просто ссылки на концепты, лежащие в основе.
Говоря о названиях, в своих собственных программах мы использовали математическую нотацию, смешанную с латинизированными русскими словами. Благодаря краткости и общей загадочности такого кода, профессиональные программисты в России называют это "говнокодом". Но так часто выглядели программы, написанные в академии. И назло профессионалам они работают точно так же, как "чистый" код.
Пример моего "говнокода" из 2006.
Некоторые мои университетские друзья, которые стали разработчиками, презирают способ преподавания программирования в российских школах. Из-за своих трудностей с именованием программных абстракций на правильном английском, они часто испытывают неприязнь к догмам в отношении английского, навязанным академически. Эта точка зрения интересует меня по двум причинам:
- Изучение иностранного языка — сложно. В противовес распространённому мнению, английский выучить нелегко.
- Связь программирования и присвоения имён очень сильна, даже в сравнении с другими сферами знаний.
Давайте рассмотрим каждую причину.
Английский — сложный
В заметке "Английский был для меня болезненной темой 15 лет" создатель Redis, Сальваторе Санфилиппо (Salvatore Sanfilippo) рассказывает о многолетней борьбе с попытками выражать мысли на английском. Пост написан человеком, который построил один из фундаментальных элементов современного комплекса технологий для веб:
...мы разрабатывали новые TCP/IP атаки, но не были способны, чёрт возьми, написать об этом пост на английском. Это было в 1998, и я уже чувствовал себя невероятно ограниченным тем, что не мог общаться, читать техническую документацию, написанную на английском и не убивать моральные силы процессом чтения… так что мой мозг использовал примерно 50% энергии только на чтение, а ещё меньше оставалось на понимание того, что я читаю.
Хорошо это или плохо, но нужно признать, что английский выиграл соревнование по международности. Беглое чтение на английском фактически стало требованием для серьёзной работы в программировании. А писать на иностранном языке — ещё более проблематично. С одной стороны, типичная программная задача не требует словаря, который нужен для написания сносной короткой истории. С другой — нужна содержательность и однозначность названий, а такое не приходит в голову естественным путём, если вы не достаточно владеете языком.
Я догадываюсь, что в среднем относительно крупный API, собранный носителем английского, будет более выразительным, чем такой же от не носителя со средним уровнем. Я практически убедился в этом, когда впервые столкнулся с Clojure. Рич Хики (Rich Hickey) известен своим продуманным использованием словаря. В Clojure простой *примитивный (simple) это не лёгкий *нетрудный (easy), коллекции (collections) это не последовательности (sequences), а функции с именами вроде reify или transduce — обычное дело.
Даже вооружившись тезаурусом или обратным словарём, носитель иностранного языка будет мучиться, чтобы соответствовать семантическому мастерству Рича. Но в реальности можно убедиться, что Google Translate и соглашения по именованию могут неплохо помочь и случайные ошибки, вроде isHided, visibles, unexisting — не критичны для звёздочной оценки на GitHub.
В целом, неанглоязычный может уверенно называть разные объекты на английском, но у него возникнут сложности с описанием специфического качества предмета, или с отчётливым присвоением конкретного типа взаимодействия. Представьте маленьких детей, которые учатся говорить. Они с лёгкостью назовут множество предметов в доме, но не будут использовать слова, вроде "сопоставлять" (juxtapose) или "перемежаться" (intersperse) для описания комплексного действия или называть что-то, что в случайном порядке включается и выключается словом "скачкообразный" (intermittent) (я правильно написал?..).
Имена на каждом шагу
Бородатая старая поговорка: "в компьютерных науках есть только две сложные вещи: "инвалидация кэша и именование". Не сложно понять, почему присвоение подходящего имени может быть трудозатратным. Программам часто приходится обрабатывать комплексные абстрактные структуры данных, что не слишком проецируется на "реальный мир".
Программисты могут всячески изощряться, когда дают названия разным объектам. Шеф (Chef) — фреймворк по управлению конфигурацией, использует целый набор кулинарных метафор: книга с рецептами, кухня, нож и другое. Шторм (Storm) — интерактивная вычислительная система, использует в работе такие сущности, как потоки, смерчи и молнии. С менее практичной стороны, Heroku (облачная платформа) развлекает всех сгенерированными серверными хостовыми названиями, вроде “flexile-sentry.heroku.com”. Некоторые спорят о том, на самом ли деле метафоры и забавные названия помогают разработчику совершенствоваться или просто запутывают лежащие в основе концепты, но это выходит за рамки темы этой статьи. Суть в том, что разработчики проводят много времени, придумывая имена разным штукам. Иногда, я бы сказал, это отрицательно влияет на их продуктивность.
Периодами я заглядываю на экран своей жены, когда она работает со сложным векторным изображением в Illustrator или макетом веб-страницы в Sketch. Почти все продвинутые векторные редакторы имеют небольшое окно со списком слоёв и объектов текущего документа. Если вы заглянете в официальную инструкцию Illustrator, конечно же найдёте рекомендации по скрупулёзному именованию каждого элемента в документе.
Из руководства “How to use layers in Illustrator”.
Но когда Джулия работает, её окно со слоями выглядит вообще не так, как в рекомендациях. Она, в первую очередь, полагается на автоматически сгенерированные названия слоёв и уверенно перемещается по очень сложным иллюстрациям без труда.
Джулия работает над иллюстрацией.
Illustrator не просит называть заранее файл и не ругается, когда у вас есть два слоя с одинаковыми именами. Начинаешь с названных автоматом элементов и переименовываешь их, когда потребуется. Теперь сравните это с генерацией свежего приложения в Ruby on Rails. Требуемое имя аргумента используется для модуля приложения, ключа сеанса и вставляется в сгенерированные шаблоны.
Если позже вы решите переименовать experiment-2 в SpaceElevator — удачи. Даже самый продвинутый IDE в Ruby, RubyMine, не может провернуть такой трюк как простое (казалось бы) переименование проекта. И это только верхушка айсберга. Если вы думаете, что "бриллианты вечны", вам никогда не приходилось объяснять схему 10-летней базы данных новому работнику. Худшие названия никогда не оставят вас в покое.
Ну вот, теперь всё наглядно: присваивать имена — сложно. Ещё сложнее на чужом языке. Менять названия позже — ещё хуже, а иногда практически невозможно. Как с этим справляться? Меня интересуют конкретно две проблемы:
- Давать возможность специалистам в своих узких областях использовать программирование, чтобы совершенствовать свою специализацию.
- Ликвидировать расхождения в коде, написанном носителями разных языков.
Меньше имен = меньше именований
Я уже говорил чуть раньше про Clojure, придирался к его усложнённому, почти элитарному подходу к именованию. Однако, у этого есть другая сторона. Функциональные языки программирования склонны требовать меньше уникальных названий для работы. Этому способствует несколько разных концептов:
- Структура функции
- Сокращённая форма синтаксиса для лямбда-функций.
- Соглашение о наименованиях и "математическая" нотация.
Взгляните на фрагмент Clojure ниже. В нём я показал функцию, которая возвращает только условия (слова), которые встречаются более чем заданное количество раз в данной строке.
Чтобы реализовать эту довольно сложную функцию, мне нужно было придумать единственное имя: имя функции. Я назвал вводную строку s, потому что есть соглашение, используемое всеми строковыми функциями в Clojure и, следуя другому общему соглашению, n обозначает единственное число, принимаемое функцией. Собирая несколько функций более высокого порядка, я избегаю явную итерацию и её побочные продукты: индексы и временные переменные. Даже когда я ввожу лямбда-функцию (#(when (> (val %) n) (key %))), синтаксис Clojure не требует назвать её аргумент, позволяя обращаться к нему с помощью символа % (к нескольким аргументам может быть доступ через %1, %2 и так далее).
Некоторые композиции функций очень сложно выразительно (наглядно) назвать. Математики избежали этой проблемы, встроив греческий алфавит в свою стандартную нотацию. Хоть я бы и не рекомендовал составлять свой API из греческих букв, локальная вспомогательная функция часто может обозначаться как f или g без особого ущерба, как в примере ниже.
Какого x?
Я считаю, что Clojure имеет почти идеальный баланс между лаконичностью и экспрессивностью, но должен признать: я был смущён этими "математическими" названиями не раз. Пока вы не познакомитесь с идиомами наименований в Clojure, понимать смысл определения функций может быть болезненным. Я бы всё же заменил s, n, и f на string, min-occurrences, и squared-sine, но ради эксперимента давайте рассмотрим, как ещё можно усовершенствовать удобное чтение, а не сдаться и просто дать всему кустарные названия.
Очевидный ответ — мы можем заложить мета-информацию. Возвращаясь к примеру в Illustrator: сгенерированные названия слоёв различны для разных типов объектов. В языках программирования эту роль могут (в какой-то степени) играть указания типов и аннотации. Давайте посмотрим на программу, написанную на Haskell:
Функция repeat принимает число n и значение x и возвращает список, содержащий n копий x. Haskell обычно не требует у вас уточнить типы, но вы можете решить добавить информацию о типах, чтобы описать свои предположения компилятору и другим людям, читающим ваш код. Описание типа данных для функции repeat может выглядеть так:
Эта сигнатура типа сообщает читающему, что n — это целое число, x — значение любого типа a, а возвращаемое значение — это список значений с типом a. Хотя существует бесконечное множество различных реализаций repeat, соответствующих этой сигнатуре типа (например, возврат a повторов n + k, где k ∈ ℕ), компилятор Haskell может поймать множество недопустимых реализаций. Например, при строковой x функция не сможет создать список кортежей или вернуть случайное значение (или считать возвращённое значение из файла). Всё это проверяется до запуска программы. На первый взгляд это может показаться беспроигрышной ситуацией, но реальность не чёрно-белая.
В теории, чем сильнее типовая система языка, тем больше информации доступно статически, а поэтому для такого языка можно создать более мощные инструменты рефакторинга и проверки кода. Конечно, инструменты Java, Scala и C#, встроенные в IDEA и Visual Studio, более надёжны, чем их Ruby-аналоги. В то же время парадокс в том, что разработчики на Haskell стараются воздерживаться от использования любых инструментов, кроме компилятора, а лисперы получают многие из тех же преимуществ (и некоторые другие), подключая свои редакторы к интерактивной среде (REPL). Система типов не делает магическим образом код в «математической» нотации самодокументированным. Хоть это и лучше «простого именования». Например, сравните следующее определение С-функции strstr, ищущей подстроку, с другой:
# 1.
char * strstr(const char *a, const char *b);
# 2.
char * strstr(const char *haystack, const char *needle)
Вариант 2 сразу делает порядок аргументов понятным любому англоговорящему, знакомому с идиомой “needle in a haystack” (иголка в стоге сена). В то же время, мы снова возвращаемся к проблеме, когда 1 и 2 одинаково озадачивают человека, не владеющего английским.
Ограничения обычного текста
Куда нас это приводит? Функциональное программирование и продвинутые системы типов безусловно сокращают количество наименований, которые нам нужно выдумывать и запоминать, чтобы создавать полезные программы. Но всегда существуют функции, вроде strstr, которые выглядят загадочно, если вы не знаете контекста естественной языковой семантики или невнимательно читаете документацию. Англоговорящий в этот момент, возможно, поинтересуется, почему бы этим несчастным иностранцам не написать языки программирования с их собственным словарём или алфавитом? Такое существует, но подобные попытки обречены на изоляцию в профессиональной сфере, построеной на интеграции идей.
Вместо этого, давайте я приведу другой пример. На скриншоте ниже — лист набранный в русской локали Microsoft Excel. Забавная штука в русскоязычном Excel — его встроенная библиотека функций так же была переведена, поэтому названия функций нужно набирать кириллицей.
Кириллические имена функций в формулах MS Excel
Не буду врать, это выглядит возмутительно даже для меня. Но не для моего отца, инженера-строителя, который ни слова не знает на английском. Он пугающе разборчив в формулах Excel и широко использует их в документах из сотни страниц, обросших фильтрами, условиями и пивот-таблицами. Позже по этим расчётам строятся дороги и мосты. Он не знает, что означает IF, но постоянно использует ЕСЛИ. Что круто, так это если он отправит вам одну из этих электронных таблиц, и вы откроете её в оригинальном MS Excel, каждая формула отобразится на английском и будет работать именно так, как было задумано отцом.
Теперь представьте, что получили кусок с тысячами строчек "говнокода", который я показывал выше. Вы вероятно захотите скомпилировать его, но удачи разобраться с API, собранным из латинизированных русских слов и греческого алфавита. Понятия не имею, как нам сравняться с космополитизмом Excel в масштабах "настоящего" языка программирования. Кажется, это один из тех случаев, когда ограничения текста без форматирования, как основного средства для написания и распространения программ, выходят на первый план. В Excel такое возможно, потому что они контролируют и формат и окружение для разработки.
Некоторые программисты встают в защитную позу, когда дело касается обсуждения альтернатив обычному тексту. В "библии" многих современных программистов, книге "Прагматичный программист" (The Pragmatic Programmer), которую я читаю и которой делал ревью в своём блоге, описанию простого текста, как сюрикэна прагматичных программистов, отведён целый раздел. Но чем больше распространяются продвинутые IDE (которые уже скрывают некоторые детали реализации) и всё шире адаптируются нетекстовые программные среды (вроде MIT Scratch или Unreal Blueprints), кажется, всё более и более правдоподобным, что такой практичный инструмент программирования для каждого, который объединит все эти идеи, уже не за горами.
Подытожим
Этот пост родился от моего отчаяния и бессилия перед названиями, как идентификаторами. А конкретно от негибкости однажды выбранных названий в таком пластичном мире, как разработка. Иногда меня просто заклинивает при выборе наглядного названия для нового проекта, функции или переменной. Частично это потому что именование — трудная штука, частично — потому что английский не мой родной язык. Но всё ещё остаётся область, где присваивать имена сложно из-за инструментов и методик программирования, которыми мы пользуемся сегодня.
Функциональное программирование сокращает количество уникальных названий в программе. Указания типов создают дополнительный слой смыслового содержания и позволяют использовать математическую нотацию без ущерба удобочитаемости. Статическая верификация типов и более строгие компиляторы упрощают создание более продвинутых инструментов для рефакторинга, что позволяет менять неудачные названия позже. В этом посте я попытался продемонстрировать, как такие направления и другие идеи могут сократить пробелы между разными культурами с помощью универсального языка вычислений.
Пожалуй, существенные изменения в этой области требуют выхода за рамки традиционных инструментов программирования (например, текстовых редакторов и CLI) и движение в сторону исключительно визуальных, интерактивных окружений. Как бы абсурдно это ни звучало, чтобы программирование стало "инструментом мышления", как его пропагандируют, оно должно учитывать уроки Excel и Illustrator, оно должно оставаться открытым к новым идеям, а не отвергать их как "непрактичные". Другими словами наши компьютеры должны обучаться универсальному языку — эмпатии.
Перевод: Наталия Басс
От редактора: Мы на Хекслете часто публикуем переводы статей. Важно помнить:
- Мнение автора статьи может отличаться от мнения администрации и сотрудников Хекслета.
- Цель перевода – показать мнение. Поэтому одна статья может визуально противоречить другой: это просто разные мнения. Мы оставляем на вашу ответственность возможность анализировать и делать выводы для себя.
<!DOCTYPE html>
<html class="h-100" data-bs-theme="light" data-mantine-color-scheme="light" lang="ru" prefix="og: https://ogp.me/ns#">
<head>
<meta content="width=device-width, initial-scale=1.0" name="viewport">
<meta content="IE=Edge" http-equiv="X-UA-Compatible">
<link crossorigin="true" href="https://cdn.hexlet.io" rel="preconnect">
<link href="https://mc.yandex.ru" rel="preconnect">
<meta content="aa2vrdtq64dub8knuf83lwywit311w" name="facebook-domain-verification">
<link href="/favicon.ico" rel="icon" sizes="any">
<link href="/favicon.svg" rel="icon" type="image/svg+xml">
<link href="/apple-touch-icon.png" rel="apple-touch-icon">
<link href="/manifest.webmanifest" rel="manifest">
<script>
//<![CDATA[
window.gon={};gon.ym_counter="25559621";gon.is_bot=true;gon.applications={};gon.current_user={"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26 20:33:40 UTC","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false};gon.token="ytFAXkr8ihYM1qkFzJ_54maR8z91akzwBJDRFdHWcMQlAItpuIIndrqVjZ3AkAmVppjelX1dslK5cEtBg9GXqg";gon.locale="ru";gon.language="ru";gon.theme="light";gon.rails_env="production";gon.mobile=false;gon.google={"analytics_key":"UA-1360700-51","optimize_key":"GTM-5QDVFPF"};gon.captcha={"google_v3_site_key":"6LenGbgZAAAAAM7HbrDbn5JlizCSzPcS767c9vaY","yandex_site_key":"ysc1_Vyob5ZPPUdPBsu0ykt8bVFdzsfpoVjQChLGl2b4g19647a89","verification_failed":null};gon.social_signin=false;gon.typoreporter_google_form_id="1FAIpQLSeibfGq-KvWQ2Fyru-zkFFRVTLBuzXAHAoEyN1p49FtDmNoNA";
//]]>
</script>
<meta charset="utf-8">
<title>Язык для программирования</title>
<meta name="description" content="Это перевод статьи Артёма Чистякова "The language of programming", породившей интересные дискуссии на HackerNews и Reddit.">
<link rel="canonical" href="https://ru.hexlet.io/blog/posts/the-language-of-programming">
<meta property="og:title" content="Язык для программирования">
<meta property="og:description" content="Это перевод статьи Артёма Чистякова "The language of programming", породившей интересные дискуссии на HackerNews и Reddit.">
<meta property="og:image" content="https://ru.hexlet.io/vite/assets/blog_post-7eTyeLLt.webp">
<meta name="csrf-param" content="authenticity_token" />
<meta name="csrf-token" content="1siQEKFqw7LveAoscW1psRQH3BUbAvRNJ1UpBWAe-5I5GVsnUxRu0lk7LrR9YpnG1A7xvxM1Cu-atbNRMhkc_A" />
<script src="/vite/assets/inertia-DfXos102.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/preload-helper-BJ4cLWpC.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-BrRXra1y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ahoy-DrlRQ-1D.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/analytics-cb8xch9l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Surface-DL2bpZA-.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/extends-C-EagtpE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/inheritsLoose-BBd-DCVI.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/objectWithoutPropertiesLoose-DRHXDhjp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/index.esm-DAqKOkZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Button-CGPUux8l.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/CloseButton-D1euiPao.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Group-BX48WcuU.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Loader-BQEY8g6v.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Modal-Cy3HByv7.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/OptionalPortal-1Hza5P2w.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Stack-CtjJzfw4.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Textarea-Ck64llAy.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/DirectionProvider-Dc9zdUke.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/events-DJQOhap0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-reduced-motion-D2owz4wa.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-disclosure-zKtK5W1r.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/use-hotkeys-Cnc_Rwkb.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/random-id-DOQyszCZ.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/exports-C_MrNx_T.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<link rel="stylesheet" href="/vite/assets/application-BqhCP46M.js" />
<script src="/vite/assets/application-Df9RExpe.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/autocomplete-VMNbxKGl.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/createPopper-C3aM9r1M.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/js.cookie-D1-O8zkX.js" as="script" crossorigin="anonymous"><link rel="stylesheet" href="/vite/assets/application-C8HjmMaq.css" media="screen" />
<script>
window.ym = function(){(ym.a=ym.a||[]).push(arguments)};
window.addEventListener('load', function() {
setTimeout(function() {
ym.l = 1*new Date();
ym(window.gon.ym_counter, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true,
webvisor: true
});
// Загружаем скрипт
var k = document.createElement('script');
k.async = 1;
k.src = 'https://mc.yandex.ru/metrika/tag.js';
document.head.appendChild(k);
ym(window.gon.ym_counter, 'getClientID', function(clientID) {
window.ymClientId = clientID;
});
}, 1500);
});
</script>
<!-- Google Tag Manager - deferred -->
<script>
// dataLayer stub сразу — пуши работают до загрузки скрипта
window.dataLayer = window.dataLayer || [];
// Сам скрипт — отложенно после load
window.addEventListener('load', function() {
setTimeout(function() {
dataLayer.push({'gtm.start': new Date().getTime(), event: 'gtm.js'});
var j = document.createElement('script');
j.async = true;
j.src = 'https://www.googletagmanager.com/gtm.js?id=GTM-WK88TH';
document.head.appendChild(j);
}, 1500);
});
</script>
<!-- End Google Tag Manager -->
</head>
<body>
<noscript>
<div>
<img alt="" src="https://mc.yandex.ru/watch/25559621" style="position:absolute; left:-9999px;">
</div>
</noscript>
<header class="sticky-top bg-body">
<nav class="navbar navbar-expand-lg">
<div class="container-xxl">
<a class="navbar-brand" href="/"><img alt="Логотип Хекслета" height="24" src="https://ru.hexlet.io/vite/assets/logo_ru_light-BpiEA1LT.svg" width="96">
</a><button aria-controls="collapsable" aria-expanded="false" aria-label="Меню" class="navbar-toggler border-0 mb-0 mt-1" data-bs-target="#collapsable" data-bs-toggle="collapse">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="collapsable">
<ul class="navbar-nav mb-lg-0 mt-lg-1">
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
Все курсы
<span class="bi bi-chevron-down align-middle ms-1"></span>
</button>
<ul class="dropdown-menu">
<li>
<a class="dropdown-item d-flex py-2" href="/courses"><div class="fw-bold me-auto">Все что есть</div>
<div class="text-muted">117</div>
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные категории</b>
</li>
<li>
<a class="dropdown-item py-2" href="/courses_devops">Курсы по DevOps
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_data_analytics">Курсы по аналитике данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_programming">Курсы по программированию
</a></li>
<li>
<a class="dropdown-item py-2" href="/courses_testing">Курсы по тестированию
</a></li>
<li>
<hr class="dropdown-divider">
</li>
<li class="dropdown-item">
<b>Популярные курсы</b>
</li>
<li>
<a class="dropdown-item py-2" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/go">Go-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/java">Java-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/python">Python-разработчик
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/qa-auto-engineer-java">Автоматизатор тестирования на Java
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/data-analytics">Аналитик данных
</a></li>
<li>
<a class="dropdown-item py-2" href="/programs/frontend">Фронтенд-разработчик
</a></li>
</ul>
</li>
<li class="nav-item dropdown">
<button aria-haspopup class="btn nav-link" data-bs-toggle="dropdown" type="button">
О Хекслете
<span class="bi bi-chevron-down align-middle"></span>
</button>
<ul class="dropdown-menu bg-body">
<li>
<a class="dropdown-item py-2" href="/pages/about">О нас
</a></li>
<li>
<a class="dropdown-item py-2" href="/blog">Блог
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/hse-research" role="button">Результаты (Исследование)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://career.hexlet.io" role="button">Хекслет Карьера
</span></li>
<li>
<a class="dropdown-item py-2" href="/testimonials">Отзывы студентов
</a></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://t.me/hexlet_help_bot" role="button">Поддержка (В ТГ)
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/referal-program/?promo_creative=priglasite-druzei&promo_name=referal-program&promo_position=promo_position&promo_start=010724&promo_type=link" role="button">Реферальная программа
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://special.hexlet.io/certificate" role="button">Подарочные сертификаты
</span></li>
<li>
<span class="dropdown-item py-2 external-link" data-href="https://hh.ru/employer/4307094" role="button">Вакансии
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://b2b.hexlet.io" data-target="_blank" role="button">Компаниям
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexly.ru/" data-target="_blank" role="button">Колледж
</span></li>
<li>
<span class="dropdown-item d-flex external-link" rel="noopener noreferrer nofollow" data-href="https://hexlyschool.ru/" data-target="_blank" role="button">Частная школа
</span></li>
</ul>
</li>
<li><a class="nav-link" href="/subscription/new">Подписка</a></li>
</ul>
<ul class="navbar-nav flex-lg-row align-items-lg-center gap-2 ms-auto">
<li>
<a class="nav-link" aria-label="Переключить тему" href="/theme/switch?new_theme=dark"><span aria-hidden="true" class="bi bi-moon"></span>
</a></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="/u/new" role="button"><span>Регистрация</span>
</span></li>
<li>
<span data-target="_self" class="nav-link external-link" data-href="https://ru.hexlet.io/session/new" role="button"><span>Вход</span>
</span></li>
</ul>
</div>
</div>
</nav>
</header>
<div class="x-container-xxxl">
</div>
<main class="mb-6 min-vh-100 h-100">
<link rel="preload" as="image" href="/vite/assets/blog_post-7eTyeLLt.webp"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MCwicHVyIjoiYmxvYl9pZCJ9fQ==--9348098e4053d798b6f34bee4ef66947540261e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc1OCwicHVyIjoiYmxvYl9pZCJ9fQ==--023ea18f500b1c4c91617fa96bbc52df8395da39/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Software%20engineer-bro.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDAxNiwicHVyIjoiYmxvYl9pZCJ9fQ==--eb66b9b5e26fafa32844ce0f4522c3ed84544040/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Hand%20coding-rafiki.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc1NywicHVyIjoiYmxvYl9pZCJ9fQ==--bd2826bc88b4074fdf555368020c1fc0ac0705c1/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png"/><link rel="preload" as="image" href="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzczMSwicHVyIjoiYmxvYl9pZCJ9fQ==--f5df4883f3f678321cb4fa96e9ce657bd5ee1adf/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Static%20website-cuate.png"/><link rel="preload" as="image" href="/vite/assets/development-BVihs_d5.png"/><div id="app" data-page="{"component":"web/blog/posts/show","props":{"errors":{},"locale":"ru","language":"ru","httpsHost":"https://ru.hexlet.io","host":"ru.hexlet.io","colorScheme":"light","auth":{"user":{"id":null,"last_viewed_notification_id":null,"email":null,"state":null,"first_name":"","last_name":"","created_at":"2026-02-26T20:33:40.757Z","current_program":null,"current_team":null,"full_name":"","guest":true,"can_use_paid_features":false,"is_hexlet_employee":false,"sanitized_phone_number":"","can_subscribe":true,"can_renew_education":false}},"cloudflareTurnstileSiteKey":"0x4AAAAAAA15KmeFXzd2H0Xo","vkIdClientId":"51586979","yandexIdClientId":"88d071f1d3384eb4bd1deb37910235c7","formAuthToken":"ea_A6xypBHcsOaUZOVbvNdtfs0Jl9HyF8-_X7exp9xOWfgvc7tepF5p6gYE1WR9CG1ae6G3DgidOD025vm4QfQ","post":{"model_name":"BlogPost","category":{"id":4,"name":"Код","slug":"code","state":"published","created_at":"2016-08-23T13:33:44.258Z"},"creator":{"public_name":"Natalia Bass","id":43585,"is_tutor":false},"tags":[{"id":1119,"slug":"bez-steka","name":"Без стека"}],"id":136,"title":"Язык для программирования","slug":"the-language-of-programming","state":"published","summary":"_Это перевод статьи Артёма Чистякова \"The language of programming\", породившей интересные дискуссии на HackerNews и Reddit._\r\n\r\nЯ помню, как изучал свой первый язык программирования. Мы должны были освоить какой-то из диалектов BASIC в рамках обязательной школьной программы по информатике для второго класса. Скрючившись на своих партах под тусклыми флуоресцентными лампами, мы нетерпеливо поглядывали на жужжащие компьютеры IBM, расставленные вдоль стен душной классной комнаты. Это был 1997 год, Россия. Ни у кого из нас не было домашнего компьютера. На доске в меловых разводах учитель написала:\r\n\r\n```\r\nSCREEN 15, 0\r\nPSET (100, 100)\r\nDRAW \"R20 D20 L20 U20\"\r\nEND\r\n```\r\n\r\n","votes_count":4,"created_at":"2017-07-19T11:43:05.330Z","published_at":"2017-07-19T11:45:41.720Z","body":"_Это перевод статьи Артёма Чистякова \"[The language of programming](https://temochka.com/blog/posts/2017/06/28/the-language-of-programming.html)\", породившей интересные дискуссии на HackerNews и Reddit._\r\n\r\nЯ помню, как изучал свой первый язык программирования. Мы должны были освоить какой-то из диалектов BASIC в рамках обязательной школьной программы по информатике для второго класса. Скрючившись на своих партах под тусклыми флуоресцентными лампами, мы нетерпеливо поглядывали на жужжащие компьютеры IBM, расставленные вдоль стен душной классной комнаты. Это был 1997 год, Россия. Ни у кого из нас не было домашнего компьютера. На доске в меловых разводах учитель написала:\r\n\r\n```\r\nSCREEN 15, 0\r\nPSET (100, 100)\r\nDRAW \"R20 D20 L20 U20\"\r\nEND\r\n```\r\n\r\n::programs\r\n\r\nВместе с двадцатью парами таких же озадаченных глаз, моё восьмилетнее сознание недоверчиво глазело на представленную учителем \"криптограмму\". \"Не пугайтесь,\" — заявила учительница своим мягким обнадёживающим тоном. Она заставляла нас рисовать блок-схемы несколько недель подряд, подводя к этому уроку. Мы уже были способны конструировать \"алгоритмы\" для чистки картошки и сборки лего. Но латинские символы, недоброжелательно поглядывающие на нас с доски, смотрелись чужеродно.\r\n\r\nУчительница продолжила расшифровывать программу строчку за строчкой. Избегая перевода с английского, она присваивала каждой лексеме значение и мотивировала нас запоминать их. Спустя некоторое время, мы посмотрели на программу и интерпретировали её, как если бы она была написана эмоджи.\r\n\r\n```\r\n🔲\r\n➡️ 100\r\n⬇️ 100\r\n🖌 \"➡️ 20 ⬇️ 20 ⬅️ 20 ⬆️ 20\"\r\n🏁\r\n```\r\n\r\nЯ всё ещё часто вспоминаю тот подход к обучению программированию и о том, как он избегает отношений с языком-оригиналом. Это же невероятно, как набор простых команд, которые задуманы быть самоописательными для тех, у кого английский — родной, оказывается серьёзной задачей для любых иноязычных кодеров. А мы были именно кодерами. Двадцать с лишним маленьких компиляторов.\r\n\r\n#### Абстрактное программирование\r\n\r\nЕщё десять лет, и я — студент, изучающий алгоритмы и структуры данных. Мы пишем на C/C++, и все в какой-то степени знаем английский. Но все наши конспекты на русском, а стандартные названия библиотечных функций представлены без каких-либо намёков на их оригинальные значения. На вступительной лекции профессор представляет \"Hello, World!\" и другие простые программы на С. Он произносит каждое название функции медленно, записывая его на доске. В его интерпретации getch() звучало как \"гэт-чэ\", а clrscr() — \"ке-ле-эр-эс-хе-йер\". Сейчас в это сложно поверить, но перед тем, как во мне что-то щёлкнуло и я увидел \"get character\" и \"clear screen\", прошло время. Потом я поделился тем, что заметил со своими однокурсниками, и они были так же удивлены.\r\n\r\nЗаглядывая в прошлое, я теперь понимаю, как порванная с языком-оригиналом связь лишила нас чего-то полезного. Хотя, такой метод изучения языка программирования — наглядный, потому что он очень близок к абстрактной математике. Это он побудил нас видеть `char *strstr(const char *haystack, const char *needle)` как `Ω(x,y)`. Даже если функция имела запутывающее название, никто из нас не замечал, потому что оно не слишком отличалось от другой случайной лексемы, которую мы должны были запомнить. Когда вы программируете таким способом, документация — царь, а названия — просто ссылки на концепты, лежащие в основе.\r\n\r\nГоворя о названиях, в своих собственных программах мы использовали математическую нотацию, смешанную с латинизированными русскими словами. Благодаря краткости и общей загадочности такого кода, профессиональные программисты в России называют это \"говнокодом\". Но так часто выглядели программы, написанные в академии. И назло профессионалам они работают точно так же, как \"чистый\" код.\r\n\r\n\r\n\r\n_Пример моего \"говнокода\" из 2006._\r\n\r\nНекоторые мои университетские друзья, которые стали разработчиками, презирают способ преподавания программирования в российских школах. Из-за своих трудностей с именованием программных абстракций на правильном английском, они часто испытывают неприязнь к догмам в отношении английского, навязанным академически. Эта точка зрения интересует меня по двум причинам:\r\n\r\n- Изучение иностранного языка — сложно. В противовес распространённому мнению, английский выучить нелегко.\r\n- Связь программирования и присвоения имён очень сильна, даже в сравнении с другими сферами знаний.\r\n\r\nДавайте рассмотрим каждую причину.\r\n\r\n#### Английский — сложный\r\n\r\nВ заметке \"[Английский был для меня болезненной темой 15 лет](http://antirez.com/news/61)\" создатель Redis, Сальваторе Санфилиппо (Salvatore Sanfilippo) рассказывает о многолетней борьбе с попытками выражать мысли на английском. Пост написан человеком, который построил один из фундаментальных элементов современного комплекса технологий для веб:\r\n\r\n> ...мы разрабатывали новые TCP/IP атаки, но не были способны, чёрт возьми, написать об этом пост на английском. Это было в 1998, и я уже чувствовал себя невероятно ограниченным тем, что не мог общаться, читать техническую документацию, написанную на английском и не убивать моральные силы процессом чтения… так что мой мозг использовал примерно 50% энергии только на чтение, а ещё меньше оставалось на понимание того, что я читаю.\r\n\r\nХорошо это или плохо, но нужно признать, что английский выиграл соревнование по международности. Беглое чтение на английском фактически стало требованием для серьёзной работы в программировании. А писать на иностранном языке — ещё более проблематично. С одной стороны, типичная программная задача не требует словаря, который нужен для написания сносной короткой истории. С другой — нужна содержательность и однозначность названий, а такое не приходит в голову естественным путём, если вы не достаточно владеете языком.\r\n\r\nЯ догадываюсь, что в среднем относительно крупный API, собранный носителем английского, будет более выразительным, чем такой же от не носителя со средним уровнем. Я практически убедился в этом, когда впервые столкнулся с Clojure. Рич Хики (Rich Hickey) известен своим продуманным использованием словаря. В Clojure *простой* \\*примитивный (simple) это не *лёгкий* \\*нетрудный (easy), *коллекции* (collections) это не *последовательности* (sequences), а функции с именами вроде `reify` или `transduce` — обычное дело.\r\n\r\nДаже вооружившись тезаурусом или [обратным словарём](http://www.onelook.com/thesaurus/), носитель иностранного языка будет мучиться, чтобы соответствовать семантическому мастерству Рича. Но в реальности можно убедиться, что Google Translate и соглашения по именованию могут неплохо помочь и случайные ошибки, вроде `isHided`, `visibles`, `unexisting` — не критичны для звёздочной оценки на GitHub.\r\n\r\nВ целом, неанглоязычный может уверенно называть разные *объекты* на английском, но у него возникнут сложности с описанием специфического качества предмета, или с отчётливым присвоением конкретного типа взаимодействия. Представьте маленьких детей, которые учатся говорить. Они с лёгкостью назовут множество предметов в доме, но не будут использовать слова, вроде \"сопоставлять\" (juxtapose) или \"перемежаться\" (intersperse) для описания комплексного действия или называть что-то, что в случайном порядке включается и выключается словом \"скачкообразный\" (intermittent) (я правильно написал?..).\r\n\r\n#### Имена на каждом шагу\r\n\r\nБородатая старая поговорка: \"в компьютерных науках есть только две сложные вещи: \"инвалидация кэша и именование\". Не сложно понять, почему присвоение подходящего имени может быть трудозатратным. Программам часто приходится обрабатывать комплексные абстрактные структуры данных, что не слишком проецируется на \"реальный мир\".\r\n\r\nПрограммисты могут всячески изощряться, когда дают названия разным объектам. Шеф (Chef) — фреймворк по управлению конфигурацией, использует целый набор кулинарных метафор: книга с рецептами, кухня, нож и другое. Шторм (Storm) — интерактивная вычислительная система, использует в работе такие сущности, как потоки, смерчи и молнии. С менее практичной стороны, Heroku (облачная платформа) развлекает всех сгенерированными серверными хостовыми названиями, вроде “flexile-sentry.heroku.com”. Некоторые спорят о том, на самом ли деле метафоры и забавные названия помогают разработчику совершенствоваться или просто запутывают лежащие в основе концепты, но это выходит за рамки темы этой статьи. Суть в том, что разработчики проводят много времени, придумывая имена разным штукам. Иногда, я бы сказал, это отрицательно влияет на их продуктивность.\r\n\r\nПериодами я заглядываю на экран своей жены, когда она работает со сложным векторным изображением в Illustrator или макетом веб-страницы в Sketch. Почти все продвинутые векторные редакторы имеют небольшое окно со списком слоёв и объектов текущего документа. Если вы заглянете в официальную инструкцию Illustrator, конечно же найдёте рекомендации по скрупулёзному именованию каждого элемента в документе.\r\n\r\n\r\n\r\n_Из руководства “[How to use layers in Illustrator](https://helpx.adobe.com/illustrator/using/layers.html)”._\r\n\r\nНо когда Джулия работает, её окно со слоями выглядит вообще не так, как в рекомендациях. Она, в первую очередь, полагается на автоматически сгенерированные названия слоёв и уверенно перемещается по очень сложным иллюстрациям без труда.\r\n\r\n\r\n\r\n_Джулия работает над иллюстрацией._\r\n\r\nIllustrator не просит называть заранее файл и не ругается, когда у вас есть два слоя с одинаковыми именами. Начинаешь с названных автоматом элементов и переименовываешь их, когда потребуется. Теперь сравните это с генерацией свежего приложения в Ruby on Rails. *Требуемое* имя аргумента используется для модуля приложения, ключа сеанса и вставляется в сгенерированные шаблоны.\r\n\r\n```bash\r\n$ rails new experiment-2\r\n...\r\n\r\n$ grep -r -i experiment .\r\n./app/views/layouts/application.html.erb: <title>Experiment2</title>\r\n./config/application.rb:module Experiment2\r\n./config/initializers/session_store.rb:Rails.application.config.session_store :cookie_store, key: '_experiment-2_session'\r\n```\r\n\r\nЕсли позже вы решите переименовать experiment-2 в SpaceElevator — удачи. Даже самый продвинутый IDE в Ruby, RubyMine, не может провернуть такой трюк как простое (казалось бы) переименование проекта. И это только верхушка айсберга. Если вы думаете, что \"бриллианты вечны\", вам никогда не приходилось объяснять схему 10-летней базы данных новому работнику. Худшие названия никогда не оставят вас в покое.\r\n\r\nНу вот, теперь всё наглядно: присваивать имена — сложно. Ещё сложнее на чужом языке. Менять названия позже — ещё хуже, а иногда практически невозможно. Как с этим справляться? Меня интересуют конкретно две проблемы:\r\n\r\n1. Давать возможность специалистам в своих узких областях использовать программирование, чтобы совершенствовать свою специализацию.\r\n2. Ликвидировать расхождения в коде, написанном носителями разных языков.\r\n\r\n#### Меньше имен = меньше именований\r\n\r\nЯ уже говорил чуть раньше про Clojure, придирался к его усложнённому, почти элитарному подходу к именованию. Однако, у этого есть другая сторона. Функциональные языки программирования склонны требовать меньше уникальных названий для работы. Этому способствует несколько разных концептов:\r\n\r\n1. Структура функции\r\n2. Сокращённая форма синтаксиса для лямбда-функций.\r\n3. Соглашение о наименованиях и \"математическая\" нотация.\r\n\r\nВзгляните на фрагмент Clojure ниже. В нём я показал функцию, которая возвращает только условия (слова), которые встречаются более чем заданное количество раз в данной строке.\r\n\r\n```clojure\r\n(defn frequent-terms\r\n \"Split s into a sequence of lower-case terms, remove articles\r\n and punctuation, return only terms that occur more than n times.\"\r\n [s n]\r\n (->> s\r\n clojure.string/lower-case\r\n (re-seq #\"\\w+\")\r\n (remove #{\"a\" \"an\" \"the\"})\r\n frequencies\r\n (keep #(when (> (val %) n) (key %)))))\r\n\r\n(frequent-terms\r\n \"How much wood would a woodchuck chuck if a woodchuck could chuck wood.\r\n As much wood as a woodchuck would if a woodchuck could chuck wood.\"\r\n 3)\r\n\r\n; => (\"woodchuck\" \"wood\")\r\n```\r\n\r\nЧтобы реализовать эту довольно сложную функцию, мне нужно было придумать единственное имя: имя функции. Я назвал вводную строку `s`, потому что есть соглашение, используемое всеми строковыми функциями в Clojure и, следуя другому общему соглашению, `n` обозначает единственное число, принимаемое функцией. Собирая несколько функций более высокого порядка, я избегаю явную итерацию и её побочные продукты: индексы и временные переменные. Даже когда я ввожу лямбда-функцию (`#(when (> (val %) n) (key %))`), синтаксис Clojure не требует назвать её аргумент, позволяя обращаться к нему с помощью символа `%` (к нескольким аргументам может быть доступ через `%1`, `%2` и так далее).\r\n\r\nНекоторые композиции функций очень сложно выразительно (наглядно) назвать. Математики избежали этой проблемы, встроив греческий алфавит в свою стандартную нотацию. Хоть я бы и не рекомендовал составлять свой API из греческих букв, локальная вспомогательная функция часто может обозначаться как *f* или *g* без особого ущерба, как в примере ниже.\r\n\r\n```clojure\r\n(letfn [(f [x] (Math/pow (Math/sin x) 2))]\r\n (f (transduce (map f) + [1 2 3 4 5])))\r\n```\r\n\r\n#### Какого *x*?\r\n\r\nЯ считаю, что Clojure имеет почти идеальный баланс между лаконичностью и экспрессивностью, но должен признать: я был смущён этими \"математическими\" названиями не раз. Пока вы не познакомитесь с идиомами наименований в Clojure, понимать смысл определения функций может быть болезненным. Я бы всё же заменил *s*, *n*, и *f* на `string`, `min-occurrences`, и `squared-sine`, но ради эксперимента давайте рассмотрим, как ещё можно усовершенствовать удобное чтение, а не сдаться и просто дать всему кустарные названия.\r\n\r\nОчевидный ответ — мы можем заложить мета-информацию. Возвращаясь к примеру в Illustrator: сгенерированные названия слоёв различны для разных типов объектов. В языках программирования эту роль могут (в какой-то степени) играть указания типов и аннотации. Давайте посмотрим на программу, написанную на Haskell:\r\n\r\n```haskell\r\nrepeat n x | n > 0 = x : repeat (n - 1) x\r\n | otherwise = []\r\n```\r\n\r\nФункция `repeat` принимает число *n* и значение *x* и возвращает список, содержащий *n* копий *x*. Haskell обычно не требует у вас уточнить типы, но вы можете решить добавить информацию о типах, чтобы описать свои предположения компилятору и другим людям, читающим ваш код. Описание типа данных для функции `repeat` может выглядеть так:\r\n\r\n```haskell\r\n; n x (return value)\r\nrepeat :: Int -> a -> [a]\r\n```\r\n\r\nЭта сигнатура типа сообщает читающему, что *n* — это целое число, *x* — значение любого типа *a*, а возвращаемое значение — это список значений с типом *a*. Хотя существует бесконечное множество различных реализаций `repeat`, соответствующих этой сигнатуре типа (например, возврат *a* повторов *n + k*, где *k ∈ ℕ*), компилятор Haskell может поймать множество недопустимых реализаций. Например, при строковой *x* функция не сможет создать список кортежей или вернуть случайное значение (или считать возвращённое значение из файла). Всё это проверяется до запуска программы. На первый взгляд это может показаться беспроигрышной ситуацией, но реальность не чёрно-белая.\r\n\r\nВ теории, чем сильнее типовая система языка, тем больше информации доступно статически, а поэтому для такого языка можно создать более мощные инструменты рефакторинга и проверки кода. Конечно, инструменты Java, Scala и C#, встроенные в IDEA и Visual Studio, более надёжны, чем их Ruby-аналоги. В то же время парадокс в том, что разработчики на Haskell стараются воздерживаться от использования любых инструментов, кроме компилятора, а лисперы получают многие из тех же преимуществ (и некоторые другие), подключая свои редакторы к интерактивной среде (REPL). Система типов не делает магическим образом код в «математической» нотации самодокументированным. Хоть это и лучше «простого именования». Например, сравните следующее определение С-функции `strstr`, ищущей подстроку, с другой:\r\n\r\n```\r\n# 1.\r\nchar * strstr(const char *a, const char *b);\r\n\r\n# 2.\r\nchar * strstr(const char *haystack, const char *needle)\r\n```\r\n\r\nВариант 2 сразу делает порядок аргументов понятным любому англоговорящему, знакомому с идиомой “needle in a haystack” (иголка в стоге сена). В то же время, мы снова возвращаемся к проблеме, когда 1 и 2 одинаково озадачивают человека, не владеющего английским.\r\n\r\n#### Ограничения обычного текста\r\n\r\nКуда нас это приводит? Функциональное программирование и продвинутые системы типов безусловно сокращают количество наименований, которые нам нужно выдумывать и запоминать, чтобы создавать полезные программы. Но всегда существуют функции, вроде `strstr`, которые выглядят загадочно, если вы не знаете контекста естественной языковой семантики или невнимательно читаете документацию. Англоговорящий в этот момент, возможно, поинтересуется, почему бы этим несчастным иностранцам не написать языки программирования с их собственным словарём или алфавитом? Такое [существует](https://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA%D0%B8_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81_%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%B2%D1%8B%D0%BC%D0%B8_%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D0%BC%D0%B8_%D0%BD%D0%B5_%D0%BD%D0%B0_%D0%B0%D0%BD%D0%B3%D0%BB%D0%B8%D0%B9%D1%81%D0%BA%D0%BE%D0%BC), но подобные попытки обречены на изоляцию в профессиональной сфере, построеной на интеграции идей.\r\n\r\nВместо этого, давайте я приведу другой пример. На скриншоте ниже — лист набранный в русской локали Microsoft Excel. Забавная штука в русскоязычном Excel — его встроенная библиотека функций так же была переведена, поэтому названия функций нужно набирать кириллицей.\r\n\r\n\r\n\r\n_Кириллические имена функций в формулах MS Excel_\r\n\r\nНе буду врать, это выглядит возмутительно даже для меня. Но не для моего отца, инженера-строителя, который ни слова не знает на английском. Он пугающе разборчив в формулах Excel и широко использует их в документах из сотни страниц, обросших фильтрами, условиями и пивот-таблицами. Позже по этим расчётам строятся дороги и мосты. Он не знает, что означает `IF`, но постоянно использует `ЕСЛИ`. Что круто, так это если он отправит вам одну из этих электронных таблиц, и вы откроете её в оригинальном MS Excel, каждая формула отобразится на английском и будет работать именно так, как было задумано отцом.\r\n\r\nТеперь представьте, что получили кусок с тысячами строчек \"говнокода\", который я показывал выше. Вы вероятно захотите скомпилировать его, но удачи разобраться с API, собранным из латинизированных русских слов и греческого алфавита. Понятия не имею, как нам сравняться с космополитизмом Excel в масштабах \"настоящего\" языка программирования. Кажется, это один из тех случаев, когда ограничения текста без форматирования, как основного средства для написания и распространения программ, выходят на первый план. В Excel такое возможно, потому что они контролируют и формат и окружение для разработки.\r\n\r\nНекоторые программисты встают в защитную позу, когда дело касается обсуждения альтернатив обычному тексту. В \"библии\" многих современных программистов, книге \"Прагматичный программист\" (The Pragmatic Programmer), которую я читаю и которой делал ревью в [своём блоге](https://temochka.com/blog/posts/2017/04/24/pragmatic-programmer.html), описанию простого текста, как сюрикэна прагматичных программистов, отведён целый раздел. Но чем больше распространяются продвинутые IDE (которые уже скрывают некоторые детали реализации) и всё шире адаптируются нетекстовые программные среды (вроде [MIT Scratch](https://scratch.mit.edu/) или [Unreal Blueprints](https://docs.unrealengine.com/latest/INT/Engine/Blueprints/GettingStarted/index.html)), кажется, всё более и более правдоподобным, что такой практичный инструмент программирования для каждого, который объединит все эти идеи, уже не за горами.\r\n\r\n#### Подытожим\r\n\r\nЭтот пост родился от моего отчаяния и бессилия перед названиями, как идентификаторами. А конкретно от негибкости однажды выбранных названий в таком пластичном мире, как разработка. Иногда меня просто заклинивает при выборе наглядного названия для нового проекта, функции или переменной. Частично это потому что именование — трудная штука, частично — потому что английский не мой родной язык. Но всё ещё остаётся область, где присваивать имена сложно из-за инструментов и методик программирования, которыми мы пользуемся сегодня.\r\n\r\nФункциональное программирование сокращает количество уникальных названий в программе. Указания типов создают дополнительный слой смыслового содержания и позволяют использовать математическую нотацию без ущерба удобочитаемости. Статическая верификация типов и более строгие компиляторы упрощают создание более продвинутых инструментов для рефакторинга, что позволяет менять неудачные названия позже. В этом посте я попытался продемонстрировать, как такие направления и другие идеи могут сократить пробелы между разными культурами с помощью универсального языка вычислений.\r\n\r\nПожалуй, существенные изменения в этой области требуют выхода за рамки традиционных инструментов программирования (например, текстовых редакторов и CLI) и движение в сторону исключительно визуальных, интерактивных окружений. Как бы абсурдно это ни звучало, чтобы программирование стало \"инструментом мышления\", как его пропагандируют, оно должно учитывать уроки Excel и Illustrator, оно должно оставаться открытым к новым идеям, а не отвергать их как \"непрактичные\". Другими словами наши компьютеры должны обучаться универсальному языку — эмпатии.\r\n\r\n- [Обсуждение на HackerNews](https://news.ycombinator.com/item?id=14720254)\r\n- [Обсуждение на Reddit](https://www.reddit.com/r/programming/comments/6lorwy/the_language_of_programming/?st=j4x7n3fh&sh=c9553c3c)\r\n\r\n_Перевод: [Наталия Басс](https://www.instagram.com/minotauria)_\r\n\r\n::posts\r\n\r\n---\r\n\r\n_От редактора:_ Мы на Хекслете часто публикуем переводы статей. Важно помнить:\r\n\r\n1. Мнение автора статьи может отличаться от мнения администрации и сотрудников Хекслета.\r\n2. Цель перевода – показать мнение. Поэтому одна статья может визуально противоречить другой: это просто разные мнения. Мы оставляем на вашу ответственность возможность анализировать и делать выводы для себя.\r\n","reading_time":10,"url":"https://ru.hexlet.io/blog/posts/the-language-of-programming","cover_thumb_variant":null,"cover_list_variant":"/vite/assets/blog_post-7eTyeLLt.webp","cover_main_variant":"/vite/assets/blog_post-7eTyeLLt.webp","related_stacks_count":5},"relatedPosts":[{"model_name":"BlogPost","id":12,"title":"Среды разработки: какие они бывают и чем отличаются друг от друга","slug":"environment","summary":"Сооснователь Хекслета Кирилл Мокевнин рассказывает, какие бывают среды разработки, как проводится контроль и испытание фичи и что такое интеграция.","created_at":"2016-08-23T14:10:57.533Z","published_at":"2023-03-21T13:40:16.878Z","cover_list_variant":"/vite/assets/blog_post-7eTyeLLt.webp"},{"model_name":"BlogPost","id":2,"title":"10 советов, как более эффективно учиться в Хекслете","slug":"10-sovetov-o-tom-kak-bolee-effectivno-uchitsya-na-hexlet","summary":"Делимся десятью лайфхаками, которые повысят эффективность обучения на Хекслете.","created_at":"2016-07-29T16:52:44.532Z","published_at":"2022-11-07T14:23:05.569Z","cover_list_variant":"/vite/assets/blog_post-7eTyeLLt.webp"},{"model_name":"BlogPost","id":129,"title":"Как работать с командной строкой эффективно: 6 советов от разработчика Дейва Керра","slug":"effective_shell_navigation","summary":"Чем больше программист работает в командной строке, тем сложнее ему ориентироваться в тексте и командах. Мы перевели статью разработчика Дейва Керра и узнали, как с помощью сочетаний клавиш (шорткатов) упростить навигацию и поиск в командной строке.","created_at":"2017-07-03T09:54:55.442Z","published_at":"2022-10-28T10:49:59.501Z","cover_list_variant":"/vite/assets/blog_post-7eTyeLLt.webp"}],"category":{"id":4,"name":"Код","slug":"code","state":"published","created_at":"2016-08-23T13:33:44.258Z"},"mainStackCategory":{"id":12,"name":"Курсы по JavaScript","slug":"javascript","short_name":"JavaScript","order":71,"state":"published","category_slug":"courses_javascript"},"categories":[{"id":6,"name":"Мотивация","slug":"motivation","state":"published","created_at":"2016-10-06T18:31:38.903Z"},{"id":3,"name":"Истории успеха","slug":"success","state":"published","created_at":"2016-07-30T12:57:18.308Z"},{"id":14,"name":"Дневник студента","slug":"student-diary","state":"published","created_at":"2019-02-25T13:27:09.471Z"},{"id":4,"name":"Код","slug":"code","state":"published","created_at":"2016-08-23T13:33:44.258Z"},{"id":12,"name":"Карьера","slug":"career","state":"published","created_at":"2017-07-21T15:42:21.481Z"}],"relatedLandings":[{"stack":{"id":20,"slug":"js-sicp","title":"СИКП на JS","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4050,"duration_in_months":1},"id":28,"slug":"js-sicp","title":"СИКП на JS","subtitle":"Навык понимать программы на фундаментальном уровне, уверенно проходить собеседования и решать сложные задачи","subtitle_for_lists":"Навык фундаментального программирования","locale":"ru","current":true,"duration_in_months_text":"1 месяц","stack_slug":"js-sicp","price_text":"от 3 900 ₽","duration_text":"1 месяц","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MCwicHVyIjoiYmxvYl9pZCJ9fQ==--9348098e4053d798b6f34bee4ef66947540261e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png"},{"stack":{"id":37,"slug":"python-sicp","title":"СИКП на Python","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4150,"duration_in_months":1},"id":62,"slug":"python-sicp","title":"СИКП на Python","subtitle":"Навык понимать код на фундаментальном уровне, уверенно проходить собеседования и решать сложные задачи","subtitle_for_lists":"Изучите Python на глубоком уровне для решения сложных задач","locale":"ru","current":true,"duration_in_months_text":"1 месяц","stack_slug":"python-sicp","price_text":"от 3 900 ₽","duration_text":"1 месяц","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc1OCwicHVyIjoiYmxvYl9pZCJ9fQ==--023ea18f500b1c4c91617fa96bbc52df8395da39/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Software%20engineer-bro.png"},{"stack":{"id":36,"slug":"java-sicp","title":"СИКП на Java","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":4100,"duration_in_months":1},"id":60,"slug":"java-sicp","title":"СИКП на Java","subtitle":"Навык понимать программы на фундаментальном уровне, уверенно проходить собеседования и решать сложные задачи","subtitle_for_lists":"Изучите фундаментальные принципы программирования на Java","locale":"ru","current":true,"duration_in_months_text":"1 месяц","stack_slug":"java-sicp","price_text":"от 3 900 ₽","duration_text":"1 месяц","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDAxNiwicHVyIjoiYmxvYl9pZCJ9fQ==--eb66b9b5e26fafa32844ce0f4522c3ed84544040/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Hand%20coding-rafiki.png"},{"stack":{"id":35,"slug":"ruby-sicp","title":"СИКП на Ruby","audience":"for_programmers","start_type":"anytime","pricing_model":"subscription","priority":"medium","kind":"track","state":"published","stack_state":"finished","order":null,"duration_in_months":1},"id":58,"slug":"ruby-sicp","title":"СИКП на Ruby","subtitle":"Навык понимания программ на фундаментальном уровне, помогающий уверенно проходить собеседования и увеличивать доход","subtitle_for_lists":"Изучите фундаментальные принципы программирования на Ruby ","locale":"ru","current":true,"duration_in_months_text":"1 месяц","stack_slug":"ruby-sicp","price_text":"от 3 900 ₽","duration_text":"1 месяц","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc1NywicHVyIjoiYmxvYl9pZCJ9fQ==--bd2826bc88b4074fdf555368020c1fc0ac0705c1/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png"},{"stack":{"id":7,"slug":"python","title":"Python-разработчик","audience":"for_beginners","start_type":"weekly","pricing_model":"purchase","priority":"high","kind":"profession","state":"published","stack_state":"finished","order":10,"duration_in_months":10},"id":7,"slug":"python","title":"Python-разработчик ","subtitle":"Изучите Python, Django, REST и Fast API для создания веб-приложений","subtitle_for_lists":"Изучите Python, Django, REST и Fast API для создания веб-приложений","locale":"ru","current":true,"duration_in_months_text":"10 месяцев","stack_slug":"python","price_text":"от 6 792 ₽","duration_text":"10 месяцев","cover_list_variant":"https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzczMSwicHVyIjoiYmxvYl9pZCJ9fQ==--f5df4883f3f678321cb4fa96e9ce657bd5ee1adf/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Static%20website-cuate.png"}]},"url":"/blog/posts/the-language-of-programming","version":"8f286f6358a90a7bef2263b3a6edf5a90a94fa42","encryptHistory":false,"clearHistory":false}"><style data-mantine-styles="true">:root, :host{--mantine-font-family: Arial, sans-serif;--mantine-font-family-headings: Arial, sans-serif;--mantine-heading-font-weight: normal;--mantine-radius-default: 0rem;--mantine-primary-color-filled: var(--mantine-color-indigo-filled);--mantine-primary-color-filled-hover: var(--mantine-color-indigo-filled-hover);--mantine-primary-color-light: var(--mantine-color-indigo-light);--mantine-primary-color-light-hover: var(--mantine-color-indigo-light-hover);--mantine-primary-color-light-color: var(--mantine-color-indigo-light-color);--mantine-spacing-xxl: calc(4rem * var(--mantine-scale));--mantine-font-size-xs: 12px;--mantine-font-size-sm: 14px;--mantine-font-size-md: 16px;--mantine-font-size-lg: clamp(16.0000px, calc(15.2727px + 0.2273vw), 18.0000px);--mantine-font-size-xl: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-display-3: clamp(32.0000px, calc(26.1818px + 1.8182vw), 48.0000px);--mantine-font-size-display-2: clamp(36.0000px, calc(25.8182px + 3.1818vw), 64.0000px);--mantine-font-size-display-1: clamp(40.0000px, calc(25.4545px + 4.5455vw), 80.0000px);--mantine-font-size-h1: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-font-size-h2: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-font-size-h3: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-font-size-h4: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-font-size-h5: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-font-size-h6: 1rem;--mantine-primary-color-0: var(--mantine-color-indigo-0);--mantine-primary-color-1: var(--mantine-color-indigo-1);--mantine-primary-color-2: var(--mantine-color-indigo-2);--mantine-primary-color-3: var(--mantine-color-indigo-3);--mantine-primary-color-4: var(--mantine-color-indigo-4);--mantine-primary-color-5: var(--mantine-color-indigo-5);--mantine-primary-color-6: var(--mantine-color-indigo-6);--mantine-primary-color-7: var(--mantine-color-indigo-7);--mantine-primary-color-8: var(--mantine-color-indigo-8);--mantine-primary-color-9: var(--mantine-color-indigo-9);--mantine-color-red-0: #ffeaea;--mantine-color-red-1: #fed4d4;--mantine-color-red-2: #f4a7a8;--mantine-color-red-3: #ec7878;--mantine-color-red-4: #e55050;--mantine-color-red-5: #e03131;--mantine-color-red-6: #e02829;--mantine-color-red-7: #c71a1c;--mantine-color-red-8: #b21218;--mantine-color-red-9: #9c0411;--mantine-color-violet-0: #fce9ff;--mantine-color-violet-1: #f1cfff;--mantine-color-violet-2: #e09bff;--mantine-color-violet-3: #d16fff;--mantine-color-violet-4: #be37fe;--mantine-color-violet-5: #b51afe;--mantine-color-violet-6: #b009ff;--mantine-color-violet-7: #9b00e4;--mantine-color-violet-8: #8a00cc;--mantine-color-violet-9: #7800b3;--mantine-color-indigo-0: #edecff;--mantine-color-indigo-1: #d6d5fe;--mantine-color-indigo-2: #aaa9f4;--mantine-color-indigo-3: #7b79eb;--mantine-color-indigo-4: #5451e4;--mantine-color-indigo-5: #3b37e0;--mantine-color-indigo-6: #2d2adf;--mantine-color-indigo-7: #1f1ec7;--mantine-color-indigo-8: #1819b2;--mantine-color-indigo-9: #0c149e;--mantine-color-cyan-0: #dffdff;--mantine-color-cyan-1: #caf5ff;--mantine-color-cyan-2: #99e8ff;--mantine-color-cyan-3: #64daff;--mantine-color-cyan-4: #3ccffe;--mantine-color-cyan-5: #24c8fe;--mantine-color-cyan-6: #00c2ff;--mantine-color-cyan-7: #00ade4;--mantine-color-cyan-8: #009acd;--mantine-color-cyan-9: #0085b5;--mantine-color-green-0: #e9fdec;--mantine-color-green-1: #d7f6dc;--mantine-color-green-2: #b0eab9;--mantine-color-green-3: #86df94;--mantine-color-green-4: #62d574;--mantine-color-green-5: #4ccf5f;--mantine-color-green-6: #3fcc54;--mantine-color-green-7: #2fb344;--mantine-color-green-8: #25a03b;--mantine-color-green-9: #138a2e;--mantine-color-yellow-0: #fff7e2;--mantine-color-yellow-1: #ffeecd;--mantine-color-yellow-2: #ffdc9c;--mantine-color-yellow-3: #ffc966;--mantine-color-yellow-4: #feb93a;--mantine-color-yellow-5: #feae1e;--mantine-color-yellow-6: #ffa90f;--mantine-color-yellow-8: #ca8200;--mantine-color-yellow-9: #af7000;--mantine-h1-font-size: clamp(28.0000px, calc(23.6364px + 1.3636vw), 40.0000px);--mantine-h1-font-weight: normal;--mantine-h2-font-size: clamp(24.0000px, calc(21.0909px + 0.9091vw), 32.0000px);--mantine-h2-font-weight: normal;--mantine-h3-font-size: clamp(20.0000px, calc(17.0909px + 0.9091vw), 28.0000px);--mantine-h3-font-weight: normal;--mantine-h4-font-size: clamp(16.0000px, calc(13.0909px + 0.9091vw), 24.0000px);--mantine-h4-font-weight: normal;--mantine-h5-font-size: clamp(16.0000px, calc(14.5455px + 0.4545vw), 20.0000px);--mantine-h5-font-weight: normal;--mantine-h6-font-size: 1rem;--mantine-h6-font-weight: normal;}
:root[data-mantine-color-scheme="dark"], :host([data-mantine-color-scheme="dark"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-dark-filled: var(--mantine-color-dark-5);--mantine-color-dark-filled-hover: var(--mantine-color-dark-6);--mantine-color-dark-light: rgba(105, 105, 105, 0.15);--mantine-color-dark-light-hover: rgba(105, 105, 105, 0.2);--mantine-color-dark-light-color: var(--mantine-color-dark-0);--mantine-color-dark-outline: var(--mantine-color-dark-1);--mantine-color-dark-outline-hover: rgba(184, 184, 184, 0.05);--mantine-color-gray-filled: var(--mantine-color-gray-5);--mantine-color-gray-filled-hover: var(--mantine-color-gray-6);--mantine-color-gray-light: rgba(222, 226, 230, 0.15);--mantine-color-gray-light-hover: rgba(222, 226, 230, 0.2);--mantine-color-gray-light-color: var(--mantine-color-gray-0);--mantine-color-gray-outline: var(--mantine-color-gray-1);--mantine-color-gray-outline-hover: rgba(241, 243, 245, 0.05);--mantine-color-red-filled: var(--mantine-color-red-5);--mantine-color-red-filled-hover: var(--mantine-color-red-6);--mantine-color-red-light: rgba(236, 120, 120, 0.15);--mantine-color-red-light-hover: rgba(236, 120, 120, 0.2);--mantine-color-red-light-color: var(--mantine-color-red-0);--mantine-color-red-outline: var(--mantine-color-red-1);--mantine-color-red-outline-hover: rgba(254, 212, 212, 0.05);--mantine-color-pink-filled: var(--mantine-color-pink-5);--mantine-color-pink-filled-hover: var(--mantine-color-pink-6);--mantine-color-pink-light: rgba(250, 162, 193, 0.15);--mantine-color-pink-light-hover: rgba(250, 162, 193, 0.2);--mantine-color-pink-light-color: var(--mantine-color-pink-0);--mantine-color-pink-outline: var(--mantine-color-pink-1);--mantine-color-pink-outline-hover: rgba(255, 222, 235, 0.05);--mantine-color-grape-filled: var(--mantine-color-grape-5);--mantine-color-grape-filled-hover: var(--mantine-color-grape-6);--mantine-color-grape-light: rgba(229, 153, 247, 0.15);--mantine-color-grape-light-hover: rgba(229, 153, 247, 0.2);--mantine-color-grape-light-color: var(--mantine-color-grape-0);--mantine-color-grape-outline: var(--mantine-color-grape-1);--mantine-color-grape-outline-hover: rgba(243, 217, 250, 0.05);--mantine-color-violet-filled: var(--mantine-color-violet-5);--mantine-color-violet-filled-hover: var(--mantine-color-violet-6);--mantine-color-violet-light: rgba(209, 111, 255, 0.15);--mantine-color-violet-light-hover: rgba(209, 111, 255, 0.2);--mantine-color-violet-light-color: var(--mantine-color-violet-0);--mantine-color-violet-outline: var(--mantine-color-violet-1);--mantine-color-violet-outline-hover: rgba(241, 207, 255, 0.05);--mantine-color-indigo-filled: var(--mantine-color-indigo-5);--mantine-color-indigo-filled-hover: var(--mantine-color-indigo-6);--mantine-color-indigo-light: rgba(123, 121, 235, 0.15);--mantine-color-indigo-light-hover: rgba(123, 121, 235, 0.2);--mantine-color-indigo-light-color: var(--mantine-color-indigo-0);--mantine-color-indigo-outline: var(--mantine-color-indigo-1);--mantine-color-indigo-outline-hover: rgba(214, 213, 254, 0.05);--mantine-color-blue-filled: var(--mantine-color-blue-5);--mantine-color-blue-filled-hover: var(--mantine-color-blue-6);--mantine-color-blue-light: rgba(116, 192, 252, 0.15);--mantine-color-blue-light-hover: rgba(116, 192, 252, 0.2);--mantine-color-blue-light-color: var(--mantine-color-blue-0);--mantine-color-blue-outline: var(--mantine-color-blue-1);--mantine-color-blue-outline-hover: rgba(208, 235, 255, 0.05);--mantine-color-cyan-filled: var(--mantine-color-cyan-5);--mantine-color-cyan-filled-hover: var(--mantine-color-cyan-6);--mantine-color-cyan-light: rgba(100, 218, 255, 0.15);--mantine-color-cyan-light-hover: rgba(100, 218, 255, 0.2);--mantine-color-cyan-light-color: var(--mantine-color-cyan-0);--mantine-color-cyan-outline: var(--mantine-color-cyan-1);--mantine-color-cyan-outline-hover: rgba(202, 245, 255, 0.05);--mantine-color-teal-filled: var(--mantine-color-teal-5);--mantine-color-teal-filled-hover: var(--mantine-color-teal-6);--mantine-color-teal-light: rgba(99, 230, 190, 0.15);--mantine-color-teal-light-hover: rgba(99, 230, 190, 0.2);--mantine-color-teal-light-color: var(--mantine-color-teal-0);--mantine-color-teal-outline: var(--mantine-color-teal-1);--mantine-color-teal-outline-hover: rgba(195, 250, 232, 0.05);--mantine-color-green-filled: var(--mantine-color-green-5);--mantine-color-green-filled-hover: var(--mantine-color-green-6);--mantine-color-green-light: rgba(134, 223, 148, 0.15);--mantine-color-green-light-hover: rgba(134, 223, 148, 0.2);--mantine-color-green-light-color: var(--mantine-color-green-0);--mantine-color-green-outline: var(--mantine-color-green-1);--mantine-color-green-outline-hover: rgba(215, 246, 220, 0.05);--mantine-color-lime-filled: var(--mantine-color-lime-5);--mantine-color-lime-filled-hover: var(--mantine-color-lime-6);--mantine-color-lime-light: rgba(192, 235, 117, 0.15);--mantine-color-lime-light-hover: rgba(192, 235, 117, 0.2);--mantine-color-lime-light-color: var(--mantine-color-lime-0);--mantine-color-lime-outline: var(--mantine-color-lime-1);--mantine-color-lime-outline-hover: rgba(233, 250, 200, 0.05);--mantine-color-yellow-filled: var(--mantine-color-yellow-5);--mantine-color-yellow-filled-hover: var(--mantine-color-yellow-6);--mantine-color-yellow-light: rgba(255, 201, 102, 0.15);--mantine-color-yellow-light-hover: rgba(255, 201, 102, 0.2);--mantine-color-yellow-light-color: var(--mantine-color-yellow-0);--mantine-color-yellow-outline: var(--mantine-color-yellow-1);--mantine-color-yellow-outline-hover: rgba(255, 238, 205, 0.05);--mantine-color-orange-filled: var(--mantine-color-orange-5);--mantine-color-orange-filled-hover: var(--mantine-color-orange-6);--mantine-color-orange-light: rgba(255, 192, 120, 0.15);--mantine-color-orange-light-hover: rgba(255, 192, 120, 0.2);--mantine-color-orange-light-color: var(--mantine-color-orange-0);--mantine-color-orange-outline: var(--mantine-color-orange-1);--mantine-color-orange-outline-hover: rgba(255, 232, 204, 0.05);--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-9) 0%, var(--mantine-color-cyan-7) 100%);--app-color-surface: #2e2e2e;}
:root[data-mantine-color-scheme="light"], :host([data-mantine-color-scheme="light"]){--mantine-color-anchor: var(--mantine-color-text);--mantine-color-dimmed: #495057;--mantine-color-red-light: rgba(224, 40, 41, 0.1);--mantine-color-red-light-hover: rgba(224, 40, 41, 0.12);--mantine-color-red-outline-hover: rgba(224, 40, 41, 0.05);--mantine-color-violet-light: rgba(176, 9, 255, 0.1);--mantine-color-violet-light-hover: rgba(176, 9, 255, 0.12);--mantine-color-violet-outline-hover: rgba(176, 9, 255, 0.05);--mantine-color-indigo-light: rgba(45, 42, 223, 0.1);--mantine-color-indigo-light-hover: rgba(45, 42, 223, 0.12);--mantine-color-indigo-outline-hover: rgba(45, 42, 223, 0.05);--mantine-color-cyan-light: rgba(0, 194, 255, 0.1);--mantine-color-cyan-light-hover: rgba(0, 194, 255, 0.12);--mantine-color-cyan-outline-hover: rgba(0, 194, 255, 0.05);--mantine-color-green-light: rgba(63, 204, 84, 0.1);--mantine-color-green-light-hover: rgba(63, 204, 84, 0.12);--mantine-color-green-outline-hover: rgba(63, 204, 84, 0.05);--mantine-color-yellow-light: rgba(255, 169, 15, 0.1);--mantine-color-yellow-light-hover: rgba(255, 169, 15, 0.12);--mantine-color-yellow-outline-hover: rgba(255, 169, 15, 0.05);--app-color-surface: #f1f3f5;--app-cta-gradient: linear-gradient(90deg, var(--mantine-color-blue-filled) 0%, var(--mantine-color-cyan-5) 100%);}</style><style data-mantine-styles="classes">@media (max-width: 35.99375em) {.mantine-visible-from-xs {display: none !important;}}@media (min-width: 36em) {.mantine-hidden-from-xs {display: none !important;}}@media (max-width: 47.99375em) {.mantine-visible-from-sm {display: none !important;}}@media (min-width: 48em) {.mantine-hidden-from-sm {display: none !important;}}@media (max-width: 61.99375em) {.mantine-visible-from-md {display: none !important;}}@media (min-width: 62em) {.mantine-hidden-from-md {display: none !important;}}@media (max-width: 74.99375em) {.mantine-visible-from-lg {display: none !important;}}@media (min-width: 75em) {.mantine-hidden-from-lg {display: none !important;}}@media (max-width: 87.99375em) {.mantine-visible-from-xl {display: none !important;}}@media (min-width: 88em) {.mantine-hidden-from-xl {display: none !important;}}</style><script type="application/ld+json">{"@context":"https://schema.org","@type":"Article","author":"Natalia Bass","name":"Язык для программирования","datePublished":"2017-07-19T11:45:41.720Z","headline":"_Это перевод статьи Артёма Чистякова "The language of programming", породившей интересные дискуссии на HackerNews и Reddit._\r\n\r\nЯ помню, как изучал свой первый язык программирования. Мы должны были освоить какой-то из диалектов BASIC в рамках обязательной школьной программы по информатике для второго класса. Скрючившись на своих партах под тусклыми флуоресцентными лампами, мы нетерпеливо поглядывали на жужжащие компьютеры IBM, расставленные вдоль стен душной классной комнаты. Это был 1997 год, Россия. Ни у кого из нас не было домашнего компьютера. На доске в меловых разводах учитель написала:\r\n\r\n```\r\nSCREEN 15, 0\r\nPSET (100, 100)\r\nDRAW "R20 D20 L20 U20"\r\nEND\r\n```\r\n\r\n","image":"/vite/assets/blog_post-7eTyeLLt.webp","interactionStatistic":[{"@type":"InteractionCounter","interactionType":{"@type":"LikeAction"},"userInteractionCount":4}]}</script><div style="--container-size:var(--container-size-lg);margin-top:var(--mantine-spacing-xl);height:100%" class="m_7485cace mantine-Container-root" data-size="lg" data-strategy="block"><script type="application/ld+json">{"@context":"https://schema.org","@type":"BreadcrumbList","itemListElement":[{"position":1,"@type":"ListItem","item":{"@id":"/blog","name":"Блог Хекслета"}},{"position":2,"@type":"ListItem","item":{"@id":"/blog/categories/code","name":"Код"}},{"position":3,"@type":"ListItem","item":{"@id":"/blog/posts/the-language-of-programming","name":"Язык для программирования"}}]}</script><div style="margin-bottom:var(--mantine-spacing-xs)" class="m_8b3717df mantine-Breadcrumbs-root"><a style="--text-fz:var(--mantine-font-size-sm);--text-lh:var(--mantine-line-height-sm);white-space:normal;color:inherit" class="mantine-focus-auto m_849cf0da m_f678d540 mantine-Breadcrumbs-breadcrumb m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-size="sm" data-underline="hover" href="/"><div style="color:inherit" class="m_4451eb3a mantine-Center-root"><svg xmlns="http://www.w3.org/2000/svg" width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-home-link "><path d="M20.085 11.085l-8.085 -8.085l-9 9h2v7a2 2 0 0 0 2 2h4.5"></path><path d="M9 21v-6a2 2 0 0 1 2 -2h2a2 2 0 0 1 1.807 1.143"></path><path d="M20 21a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path><path d="M20 16a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path><path d="M15 19a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path><path d="M21 16l-5 3l5 2"></path></svg></div></a><div class="m_3b8f2208 mantine-Breadcrumbs-separator">/</div><a style="--text-fz:var(--mantine-font-size-sm);--text-lh:var(--mantine-line-height-sm);white-space:normal;color:inherit" class="mantine-focus-auto m_849cf0da m_f678d540 mantine-Breadcrumbs-breadcrumb m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-size="sm" data-underline="hover" href="/blog">Блог Хекслета</a><div class="m_3b8f2208 mantine-Breadcrumbs-separator">/</div><a style="--text-fz:var(--mantine-font-size-sm);--text-lh:var(--mantine-line-height-sm);white-space:normal;color:inherit" class="mantine-focus-auto m_849cf0da m_f678d540 mantine-Breadcrumbs-breadcrumb m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-size="sm" data-underline="hover" href="/blog/categories/code">Код</a><div class="m_3b8f2208 mantine-Breadcrumbs-separator">/</div><p style="--text-fz:var(--mantine-font-size-sm);--text-lh:var(--mantine-line-height-sm);white-space:normal;color:var(--mantine-color-dimmed)" class="mantine-focus-auto m_f678d540 mantine-Breadcrumbs-breadcrumb m_b6d8b162 mantine-Text-root" data-size="sm">Язык для программирования</p></div><style data-mantine-styles="inline">.__m__-_R_eub_{margin-bottom:var(--mantine-spacing-xs);}@media(min-width: 36em){.__m__-_R_eub_{margin-bottom:var(--mantine-spacing-xs);}}</style><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root __m__-_R_eub_"><style data-mantine-styles="inline">.__m__-_R_deub_{width:100%;}@media(min-width: 36em){.__m__-_R_deub_{width:70%;}}@media(min-width: 75em){.__m__-_R_deub_{width:75%;}}</style><div class="__m__-_R_deub_"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><h1 style="--title-fw:var(--mantine-h1-font-weight);--title-lh:var(--mantine-h1-line-height);--title-fz:var(--mantine-h1-font-size)" class="m_8a5d1357 mantine-Title-root" data-order="1">Язык для программирования</h1></div></div></div><div style="position:absolute;top:calc(18.75rem * var(--mantine-scale))" class=""></div><style data-mantine-styles="inline">.__m__-_R_2iub_{--grid-gutter:var(--mantine-spacing-xl);}</style><div class="m_410352e9 mantine-Grid-root __m__-_R_2iub_"><div class="m_dee7bd2f mantine-Grid-inner"><style data-mantine-styles="inline">.__m__-_R_dmiub_{--col-flex-grow:auto;--col-flex-basis:100%;--col-max-width:100%;}@media(min-width: 48em){.__m__-_R_dmiub_{--col-flex-grow:auto;--col-flex-basis:83.33333333333334%;--col-max-width:83.33333333333334%;}}@media(min-width: 62em){.__m__-_R_dmiub_{--col-flex-grow:auto;--col-flex-basis:66.66666666666667%;--col-max-width:66.66666666666667%;}}</style><div class="m_96bdd299 mantine-Grid-col __m__-_R_dmiub_"><div style="--stack-gap:var(--mantine-spacing-md);--stack-align:stretch;--stack-justify:flex-start;margin-bottom:var(--mantine-spacing-xl)" class="m_6d731127 mantine-Stack-root"><div class=""><div style="--group-gap:var(--mantine-spacing-xs);--group-align:center;--group-justify:flex-start;--group-wrap:wrap;margin-bottom:var(--mantine-spacing-xl)" class="m_4081bf90 mantine-Group-root"><button style="--badge-height:var(--badge-height-sm);--badge-padding-x:var(--badge-padding-x-sm);--badge-fz:var(--badge-fz-sm);--badge-bg:var(--mantine-color-default);--badge-color:var(--mantine-color-default-color);--badge-bd:calc(0.0625rem * var(--mantine-scale)) solid var(--mantine-color-default-border);cursor:pointer;color:inherit" class="m_347db0ec mantine-Badge-root" data-variant="default" data-size="sm" type="button" aria-label="Без стека"><span class="m_5add502a mantine-Badge-label">Без стека</span></button></div><div style="--group-gap:calc(0.625rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:wrap;margin-bottom:var(--mantine-spacing-sm);color:var(--mantine-color-gray-text)" class="m_4081bf90 mantine-Group-root"><div style="--group-gap:calc(0.1875rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:wrap;margin-inline-end:var(--mantine-spacing-lg)" class="m_4081bf90 mantine-Group-root">19 июля 2017 г.</div><div style="--group-gap:calc(0.1875rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-clock "><path d="M3 12a9 9 0 1 0 18 0a9 9 0 0 0 -18 0"></path><path d="M12 7v5l3 3"></path></svg></div>10 минут</div><div style="--group-gap:calc(0.1875rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-thumb-up "><path d="M7 11v8a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-7a1 1 0 0 1 1 -1h3a4 4 0 0 0 4 -4v-1a2 2 0 0 1 4 0v5h3a2 2 0 0 1 2 2l-1 5a2 3 0 0 1 -2 2h-7a3 3 0 0 1 -3 -3"></path></svg></div>4</div></div><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img style="--image-radius:var(--mantine-radius-md);--image-object-fit:cover;width:100%;height:100%" class="m_9e117634 mantine-Image-root" src="/vite/assets/blog_post-7eTyeLLt.webp" alt="Язык для программирования"/></div></div><div role="link" tabindex="0" style="cursor:pointer"><button style="display:block;width:100%" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Присоединяйтесь к нашему Telegram-сообществу"><div style="background-color:light-dark(var(--mantine-color-gray-1), var(--mantine-color-dark-6))" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root"><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:flex-start;--group-wrap:wrap" class="m_4081bf90 mantine-Group-root"><div style="--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:auto;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-brand-telegram "><path d="M15 10l-4 4l6 6l4 -16l-18 7l4 2l2 6l3 -4"></path></svg></div>Присоединяйтесь к нашему Telegram-сообществу</div></div></button></div><div style="margin-bottom:var(--mantine-spacing-xl)" class="m_d08caa0 mantine-Typography-root"><p><em>Это перевод статьи Артёма Чистякова "<a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://temochka.com/blog/posts/2017/06/28/the-language-of-programming.html" rel="noopener noreferrer" target="_blank">The language of programming</a>", породившей интересные дискуссии на HackerNews и Reddit.</em></p>
<p>Я помню, как изучал свой первый язык программирования. Мы должны были освоить какой-то из диалектов BASIC в рамках обязательной школьной программы по информатике для второго класса. Скрючившись на своих партах под тусклыми флуоресцентными лампами, мы нетерпеливо поглядывали на жужжащие компьютеры IBM, расставленные вдоль стен душной классной комнаты. Это был 1997 год, Россия. Ни у кого из нас не было домашнего компьютера. На доске в меловых разводах учитель написала:</p>
<code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">SCREEN 15, 0
PSET (100, 100)
DRAW "R20 D20 L20 U20"
END</code>
<style data-mantine-styles="inline">.__m__-_R_7derddmiub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:70%;}@media(min-width: 36em){.__m__-_R_7derddmiub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_7derddmiub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/js-sicp?promo_name=programs_list&promo_position=blog_post&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">1 месяц</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Для продвинутых</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">СИКП на JS</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Навык фундаментального программирования</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc2MCwicHVyIjoiYmxvYl9pZCJ9fQ==--9348098e4053d798b6f34bee4ef66947540261e4/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png" alt="СИКП на JS" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 3 900 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/python-sicp?promo_name=programs_list&promo_position=blog_post&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">1 месяц</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Для продвинутых</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">СИКП на Python</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите Python на глубоком уровне для решения сложных задач</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc1OCwicHVyIjoiYmxvYl9pZCJ9fQ==--023ea18f500b1c4c91617fa96bbc52df8395da39/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Software%20engineer-bro.png" alt="СИКП на Python" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 3 900 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/java-sicp?promo_name=programs_list&promo_position=blog_post&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">1 месяц</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Для продвинутых</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">СИКП на Java</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите фундаментальные принципы программирования на Java</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6NDAxNiwicHVyIjoiYmxvYl9pZCJ9fQ==--eb66b9b5e26fafa32844ce0f4522c3ed84544040/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Hand%20coding-rafiki.png" alt="СИКП на Java" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 3 900 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/ruby-sicp?promo_name=programs_list&promo_position=blog_post&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">1 месяц</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Для продвинутых</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">СИКП на Ruby</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите фундаментальные принципы программирования на Ruby </p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6Mzc1NywicHVyIjoiYmxvYl9pZCJ9fQ==--bd2826bc88b4074fdf555368020c1fc0ac0705c1/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Low%20code%20development-rafiki.png" alt="СИКП на Ruby" loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 3 900 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/programs/python?promo_name=programs_list&promo_position=blog_post&promo_creative=catalog_card&promo_type=card" target="_blank"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="--group-gap:calc(0.25rem * var(--mantine-scale));--group-align:center;--group-justify:flex-start;--group-wrap:nowrap" class="m_4081bf90 mantine-Group-root"><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">10 месяцев</span><span class="mantine-focus-auto m_b6d8b162 mantine-Text-root">·</span><span style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">С нуля</span></div><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h5);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Python-разработчик </p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Изучите Python, Django, REST и Fast API для создания веб-приложений</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="https://hexlet.io/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MzczMSwicHVyIjoiYmxvYl9pZCJ9fQ==--f5df4883f3f678321cb4fa96e9ce657bd5ee1adf/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbNDAwLDQwMF0sInNhdmVyIjp7InF1YWxpdHkiOjg1fX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--5b6f46dacd1af664f27558553a58076185091823/Static%20website-cuate.png" alt="Python-разработчик " loading="eager"/></div><div style="--group-gap:var(--mantine-spacing-md);--group-align:end;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-xs)" class="m_4081bf90 mantine-Group-root"><p style="font-size:var(--mantine-font-size-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">от 6 792 ₽</p><p style="font-size:var(--mantine-font-size-sm)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses?promo_name=programs_list&promo_position=blog_post&promo_creative=catalog_card&promo_type=card"><div style="height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><h2 style="--title-fw:var(--mantine-h2-font-weight);--title-lh:var(--mantine-h2-line-height);--title-fz:var(--mantine-h2-font-size);margin-bottom:var(--mantine-spacing-md);font-size:var(--mantine-font-size-h3)" class="m_8a5d1357 mantine-Title-root" data-order="2" data-responsive="true">Каталог</h2><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Полный список доступных курсов по разным направлениям</p><div style="margin-top:auto" class=""><div class="m_4451eb3a mantine-Center-root"><img style="opacity:0.8;width:70%" class="m_9e117634 mantine-Image-root mantine-visible-from-xs" src="/vite/assets/development-BVihs_d5.png" alt="Orientation"/></div></div></div></a></div></div></div></div></div>
<p>Вместе с двадцатью парами таких же озадаченных глаз, моё восьмилетнее сознание недоверчиво глазело на представленную учителем "криптограмму". "Не пугайтесь," — заявила учительница своим мягким обнадёживающим тоном. Она заставляла нас рисовать блок-схемы несколько недель подряд, подводя к этому уроку. Мы уже были способны конструировать "алгоритмы" для чистки картошки и сборки лего. Но латинские символы, недоброжелательно поглядывающие на нас с доски, смотрелись чужеродно.</p>
<p>Учительница продолжила расшифровывать программу строчку за строчкой. Избегая перевода с английского, она присваивала каждой лексеме значение и мотивировала нас запоминать их. Спустя некоторое время, мы посмотрели на программу и интерпретировали её, как если бы она была написана эмоджи.</p>
<code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">🔲
➡️ 100
⬇️ 100
🖌 "➡️ 20 ⬇️ 20 ⬅️ 20 ⬆️ 20"
🏁</code>
<p>Я всё ещё часто вспоминаю тот подход к обучению программированию и о том, как он избегает отношений с языком-оригиналом. Это же невероятно, как набор простых команд, которые задуманы быть самоописательными для тех, у кого английский — родной, оказывается серьёзной задачей для любых иноязычных кодеров. А мы были именно кодерами. Двадцать с лишним маленьких компиляторов.</p>
<h4 id="heading-4-1">Абстрактное программирование</h4>
<p>Ещё десять лет, и я — студент, изучающий алгоритмы и структуры данных. Мы пишем на C/C++, и все в какой-то степени знаем английский. Но все наши конспекты на русском, а стандартные названия библиотечных функций представлены без каких-либо намёков на их оригинальные значения. На вступительной лекции профессор представляет "Hello, World!" и другие простые программы на С. Он произносит каждое название функции медленно, записывая его на доске. В его интерпретации getch() звучало как "гэт-чэ", а clrscr() — "ке-ле-эр-эс-хе-йер". Сейчас в это сложно поверить, но перед тем, как во мне что-то щёлкнуло и я увидел "get character" и "clear screen", прошло время. Потом я поделился тем, что заметил со своими однокурсниками, и они были так же удивлены.</p>
<p>Заглядывая в прошлое, я теперь понимаю, как порванная с языком-оригиналом связь лишила нас чего-то полезного. Хотя, такой метод изучения языка программирования — наглядный, потому что он очень близок к абстрактной математике. Это он побудил нас видеть <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">char *strstr(const char *haystack, const char *needle)</code> как <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">Ω(x,y)</code>. Даже если функция имела запутывающее название, никто из нас не замечал, потому что оно не слишком отличалось от другой случайной лексемы, которую мы должны были запомнить. Когда вы программируете таким способом, документация — царь, а названия — просто ссылки на концепты, лежащие в основе.</p>
<p>Говоря о названиях, в своих собственных программах мы использовали математическую нотацию, смешанную с латинизированными русскими словами. Благодаря краткости и общей загадочности такого кода, профессиональные программисты в России называют это "говнокодом". Но так часто выглядели программы, написанные в академии. И назло профессионалам они работают точно так же, как "чистый" код.</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="https://i.imgur.com/uz7B9kn.png" alt="говнокод из 2006 года" loading="lazy"/></p>
<p><em>Пример моего "говнокода" из 2006.</em></p>
<p>Некоторые мои университетские друзья, которые стали разработчиками, презирают способ преподавания программирования в российских школах. Из-за своих трудностей с именованием программных абстракций на правильном английском, они часто испытывают неприязнь к догмам в отношении английского, навязанным академически. Эта точка зрения интересует меня по двум причинам:</p>
<ul>
<li>Изучение иностранного языка — сложно. В противовес распространённому мнению, английский выучить нелегко.</li>
<li>Связь программирования и присвоения имён очень сильна, даже в сравнении с другими сферами знаний.</li>
</ul>
<p>Давайте рассмотрим каждую причину.</p>
<h4 id="heading-4-2">Английский — сложный</h4>
<p>В заметке "<a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="http://antirez.com/news/61" rel="noopener noreferrer" target="_blank">Английский был для меня болезненной темой 15 лет</a>" создатель Redis, Сальваторе Санфилиппо (Salvatore Sanfilippo) рассказывает о многолетней борьбе с попытками выражать мысли на английском. Пост написан человеком, который построил один из фундаментальных элементов современного комплекса технологий для веб:</p>
<blockquote>
<p>...мы разрабатывали новые TCP/IP атаки, но не были способны, чёрт возьми, написать об этом пост на английском. Это было в 1998, и я уже чувствовал себя невероятно ограниченным тем, что не мог общаться, читать техническую документацию, написанную на английском и не убивать моральные силы процессом чтения… так что мой мозг использовал примерно 50% энергии только на чтение, а ещё меньше оставалось на понимание того, что я читаю.</p>
</blockquote>
<p>Хорошо это или плохо, но нужно признать, что английский выиграл соревнование по международности. Беглое чтение на английском фактически стало требованием для серьёзной работы в программировании. А писать на иностранном языке — ещё более проблематично. С одной стороны, типичная программная задача не требует словаря, который нужен для написания сносной короткой истории. С другой — нужна содержательность и однозначность названий, а такое не приходит в голову естественным путём, если вы не достаточно владеете языком.</p>
<p>Я догадываюсь, что в среднем относительно крупный API, собранный носителем английского, будет более выразительным, чем такой же от не носителя со средним уровнем. Я практически убедился в этом, когда впервые столкнулся с Clojure. Рич Хики (Rich Hickey) известен своим продуманным использованием словаря. В Clojure <em>простой</em> *примитивный (simple) это не <em>лёгкий</em> *нетрудный (easy), <em>коллекции</em> (collections) это не <em>последовательности</em> (sequences), а функции с именами вроде <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">reify</code> или <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">transduce</code> — обычное дело.</p>
<p>Даже вооружившись тезаурусом или <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="http://www.onelook.com/thesaurus/" rel="noopener noreferrer" target="_blank">обратным словарём</a>, носитель иностранного языка будет мучиться, чтобы соответствовать семантическому мастерству Рича. Но в реальности можно убедиться, что Google Translate и соглашения по именованию могут неплохо помочь и случайные ошибки, вроде <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">isHided</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">visibles</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">unexisting</code> — не критичны для звёздочной оценки на GitHub.</p>
<p>В целом, неанглоязычный может уверенно называть разные <em>объекты</em> на английском, но у него возникнут сложности с описанием специфического качества предмета, или с отчётливым присвоением конкретного типа взаимодействия. Представьте маленьких детей, которые учатся говорить. Они с лёгкостью назовут множество предметов в доме, но не будут использовать слова, вроде "сопоставлять" (juxtapose) или "перемежаться" (intersperse) для описания комплексного действия или называть что-то, что в случайном порядке включается и выключается словом "скачкообразный" (intermittent) (я правильно написал?..).</p>
<h4 id="heading-4-3">Имена на каждом шагу</h4>
<p>Бородатая старая поговорка: "в компьютерных науках есть только две сложные вещи: "инвалидация кэша и именование". Не сложно понять, почему присвоение подходящего имени может быть трудозатратным. Программам часто приходится обрабатывать комплексные абстрактные структуры данных, что не слишком проецируется на "реальный мир".</p>
<p>Программисты могут всячески изощряться, когда дают названия разным объектам. Шеф (Chef) — фреймворк по управлению конфигурацией, использует целый набор кулинарных метафор: книга с рецептами, кухня, нож и другое. Шторм (Storm) — интерактивная вычислительная система, использует в работе такие сущности, как потоки, смерчи и молнии. С менее практичной стороны, Heroku (облачная платформа) развлекает всех сгенерированными серверными хостовыми названиями, вроде “flexile-sentry.heroku.com”. Некоторые спорят о том, на самом ли деле метафоры и забавные названия помогают разработчику совершенствоваться или просто запутывают лежащие в основе концепты, но это выходит за рамки темы этой статьи. Суть в том, что разработчики проводят много времени, придумывая имена разным штукам. Иногда, я бы сказал, это отрицательно влияет на их продуктивность.</p>
<p>Периодами я заглядываю на экран своей жены, когда она работает со сложным векторным изображением в Illustrator или макетом веб-страницы в Sketch. Почти все продвинутые векторные редакторы имеют небольшое окно со списком слоёв и объектов текущего документа. Если вы заглянете в официальную инструкцию Illustrator, конечно же найдёте рекомендации по скрупулёзному именованию каждого элемента в документе.</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="https://i.imgur.com/H5Magmb.png" alt="How to use layers in Illustrator" loading="lazy"/></p>
<p><em>Из руководства “<a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://helpx.adobe.com/illustrator/using/layers.html" rel="noopener noreferrer" target="_blank">How to use layers in Illustrator</a>”.</em></p>
<p>Но когда Джулия работает, её окно со слоями выглядит вообще не так, как в рекомендациях. Она, в первую очередь, полагается на автоматически сгенерированные названия слоёв и уверенно перемещается по очень сложным иллюстрациям без труда.</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="https://i.imgur.com/RiL0fap.png" alt="работа над иллюстрацией" loading="lazy"/></p>
<p><em>Джулия работает над иллюстрацией.</em></p>
<p>Illustrator не просит называть заранее файл и не ругается, когда у вас есть два слоя с одинаковыми именами. Начинаешь с названных автоматом элементов и переименовываешь их, когда потребуется. Теперь сравните это с генерацией свежего приложения в Ruby on Rails. <em>Требуемое</em> имя аргумента используется для модуля приложения, ключа сеанса и вставляется в сгенерированные шаблоны.</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">$ rails new experiment-2
...
$ grep -r -i experiment .
./app/views/layouts/application.html.erb: <title>Experiment2</title>
./config/application.rb:module Experiment2
./config/initializers/session_store.rb:Rails.application.config.session_store :cookie_store, key: '_experiment-2_session'</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Если позже вы решите переименовать experiment-2 в SpaceElevator — удачи. Даже самый продвинутый IDE в Ruby, RubyMine, не может провернуть такой трюк как простое (казалось бы) переименование проекта. И это только верхушка айсберга. Если вы думаете, что "бриллианты вечны", вам никогда не приходилось объяснять схему 10-летней базы данных новому работнику. Худшие названия никогда не оставят вас в покое.</p>
<p>Ну вот, теперь всё наглядно: присваивать имена — сложно. Ещё сложнее на чужом языке. Менять названия позже — ещё хуже, а иногда практически невозможно. Как с этим справляться? Меня интересуют конкретно две проблемы:</p>
<ol>
<li>Давать возможность специалистам в своих узких областях использовать программирование, чтобы совершенствовать свою специализацию.</li>
<li>Ликвидировать расхождения в коде, написанном носителями разных языков.</li>
</ol>
<h4 id="heading-4-4">Меньше имен = меньше именований</h4>
<p>Я уже говорил чуть раньше про Clojure, придирался к его усложнённому, почти элитарному подходу к именованию. Однако, у этого есть другая сторона. Функциональные языки программирования склонны требовать меньше уникальных названий для работы. Этому способствует несколько разных концептов:</p>
<ol>
<li>Структура функции</li>
<li>Сокращённая форма синтаксиса для лямбда-функций.</li>
<li>Соглашение о наименованиях и "математическая" нотация.</li>
</ol>
<p>Взгляните на фрагмент Clojure ниже. В нём я показал функцию, которая возвращает только условия (слова), которые встречаются более чем заданное количество раз в данной строке.</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">(defn frequent-terms
"Split s into a sequence of lower-case terms, remove articles
and punctuation, return only terms that occur more than n times."
[s n]
(->> s
clojure.string/lower-case
(re-seq #"\w+")
(remove #{"a" "an" "the"})
frequencies
(keep #(when (> (val %) n) (key %)))))
(frequent-terms
"How much wood would a woodchuck chuck if a woodchuck could chuck wood.
As much wood as a woodchuck would if a woodchuck could chuck wood."
3)
; => ("woodchuck" "wood")</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Чтобы реализовать эту довольно сложную функцию, мне нужно было придумать единственное имя: имя функции. Я назвал вводную строку <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">s</code>, потому что есть соглашение, используемое всеми строковыми функциями в Clojure и, следуя другому общему соглашению, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">n</code> обозначает единственное число, принимаемое функцией. Собирая несколько функций более высокого порядка, я избегаю явную итерацию и её побочные продукты: индексы и временные переменные. Даже когда я ввожу лямбда-функцию (<code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">#(when (> (val %) n) (key %))</code>), синтаксис Clojure не требует назвать её аргумент, позволяя обращаться к нему с помощью символа <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">%</code> (к нескольким аргументам может быть доступ через <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">%1</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">%2</code> и так далее).</p>
<p>Некоторые композиции функций очень сложно выразительно (наглядно) назвать. Математики избежали этой проблемы, встроив греческий алфавит в свою стандартную нотацию. Хоть я бы и не рекомендовал составлять свой API из греческих букв, локальная вспомогательная функция часто может обозначаться как <em>f</em> или <em>g</em> без особого ущерба, как в примере ниже.</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">(letfn [(f [x] (Math/pow (Math/sin x) 2))]
(f (transduce (map f) + [1 2 3 4 5])))</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<h4 id="heading-4-5">Какого <em>x</em>?</h4>
<p>Я считаю, что Clojure имеет почти идеальный баланс между лаконичностью и экспрессивностью, но должен признать: я был смущён этими "математическими" названиями не раз. Пока вы не познакомитесь с идиомами наименований в Clojure, понимать смысл определения функций может быть болезненным. Я бы всё же заменил <em>s</em>, <em>n</em>, и <em>f</em> на <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">string</code>, <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">min-occurrences</code>, и <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">squared-sine</code>, но ради эксперимента давайте рассмотрим, как ещё можно усовершенствовать удобное чтение, а не сдаться и просто дать всему кустарные названия.</p>
<p>Очевидный ответ — мы можем заложить мета-информацию. Возвращаясь к примеру в Illustrator: сгенерированные названия слоёв различны для разных типов объектов. В языках программирования эту роль могут (в какой-то степени) играть указания типов и аннотации. Давайте посмотрим на программу, написанную на Haskell:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">repeat n x | n > 0 = x : repeat (n - 1) x
| otherwise = []</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Функция <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">repeat</code> принимает число <em>n</em> и значение <em>x</em> и возвращает список, содержащий <em>n</em> копий <em>x</em>. Haskell обычно не требует у вас уточнить типы, но вы можете решить добавить информацию о типах, чтобы описать свои предположения компилятору и другим людям, читающим ваш код. Описание типа данных для функции <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">repeat</code> может выглядеть так:</p>
<div style="margin-bottom:var(--mantine-spacing-lg)" class="m_e597c321 mantine-CodeHighlight-codeHighlight" dir="ltr"><div class="m_be7e9c9c mantine-CodeHighlight-controls"><button style="--ai-bg:transparent;--ai-hover:transparent;--ai-color:inherit;--ai-bd:none" class="mantine-focus-auto mantine-active m_d498bab7 mantine-CodeHighlight-control m_8d3f4000 mantine-ActionIcon-root m_87cf2631 mantine-UnstyledButton-root" data-variant="none" type="button" aria-label="Copy code"><span class="m_8d3afb97 mantine-ActionIcon-icon"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><path stroke="none" d="M0 0h24v24H0z" fill="none"></path><path d="M8 8m0 2a2 2 0 0 1 2 -2h8a2 2 0 0 1 2 2v8a2 2 0 0 1 -2 2h-8a2 2 0 0 1 -2 -2z"></path><path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path></svg></span></button></div><div style="--scrollarea-scrollbar-size:calc(0.25rem * var(--mantine-scale));--sa-corner-width:0px;--sa-corner-height:0px" class="m_f744fd40 mantine-CodeHighlight-scrollarea m_d57069b5 mantine-ScrollArea-root" dir="ltr"><div style="overflow-x:hidden;overflow-y:hidden;overscroll-behavior-inline:none" class="m_c0783ff9 mantine-ScrollArea-viewport" data-scrollbars="xy"><div class="m_b1336c6 mantine-ScrollArea-content"><pre class="m_2c47c4fd mantine-CodeHighlight-pre" style="padding:0"><code class="m_5caae6d3 mantine-CodeHighlight-code">; n x (return value)
repeat :: Int -> a -> [a]</code></pre></div></div></div><button class="mantine-focus-auto m_c9378bc2 mantine-CodeHighlight-showCodeButton m_87cf2631 mantine-UnstyledButton-root" data-hidden="true" type="button">Expand code</button></div>
<p>Эта сигнатура типа сообщает читающему, что <em>n</em> — это целое число, <em>x</em> — значение любого типа <em>a</em>, а возвращаемое значение — это список значений с типом <em>a</em>. Хотя существует бесконечное множество различных реализаций <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">repeat</code>, соответствующих этой сигнатуре типа (например, возврат <em>a</em> повторов <em>n + k</em>, где <em>k ∈ ℕ</em>), компилятор Haskell может поймать множество недопустимых реализаций. Например, при строковой <em>x</em> функция не сможет создать список кортежей или вернуть случайное значение (или считать возвращённое значение из файла). Всё это проверяется до запуска программы. На первый взгляд это может показаться беспроигрышной ситуацией, но реальность не чёрно-белая.</p>
<p>В теории, чем сильнее типовая система языка, тем больше информации доступно статически, а поэтому для такого языка можно создать более мощные инструменты рефакторинга и проверки кода. Конечно, инструменты Java, Scala и C#, встроенные в IDEA и Visual Studio, более надёжны, чем их Ruby-аналоги. В то же время парадокс в том, что разработчики на Haskell стараются воздерживаться от использования любых инструментов, кроме компилятора, а лисперы получают многие из тех же преимуществ (и некоторые другие), подключая свои редакторы к интерактивной среде (REPL). Система типов не делает магическим образом код в «математической» нотации самодокументированным. Хоть это и лучше «простого именования». Например, сравните следующее определение С-функции <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">strstr</code>, ищущей подстроку, с другой:</p>
<code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight"># 1.
char * strstr(const char *a, const char *b);
# 2.
char * strstr(const char *haystack, const char *needle)</code>
<p>Вариант 2 сразу делает порядок аргументов понятным любому англоговорящему, знакомому с идиомой “needle in a haystack” (иголка в стоге сена). В то же время, мы снова возвращаемся к проблеме, когда 1 и 2 одинаково озадачивают человека, не владеющего английским.</p>
<h4 id="heading-4-6">Ограничения обычного текста</h4>
<p>Куда нас это приводит? Функциональное программирование и продвинутые системы типов безусловно сокращают количество наименований, которые нам нужно выдумывать и запоминать, чтобы создавать полезные программы. Но всегда существуют функции, вроде <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">strstr</code>, которые выглядят загадочно, если вы не знаете контекста естественной языковой семантики или невнимательно читаете документацию. Англоговорящий в этот момент, возможно, поинтересуется, почему бы этим несчастным иностранцам не написать языки программирования с их собственным словарём или алфавитом? Такое <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://ru.wikipedia.org/wiki/%D0%AF%D0%B7%D1%8B%D0%BA%D0%B8_%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D1%8F_%D1%81_%D0%BA%D0%BB%D1%8E%D1%87%D0%B5%D0%B2%D1%8B%D0%BC%D0%B8_%D1%81%D0%BB%D0%BE%D0%B2%D0%B0%D0%BC%D0%B8_%D0%BD%D0%B5_%D0%BD%D0%B0_%D0%B0%D0%BD%D0%B3%D0%BB%D0%B8%D0%B9%D1%81%D0%BA%D0%BE%D0%BC" rel="noopener noreferrer" target="_blank">существует</a>, но подобные попытки обречены на изоляцию в профессиональной сфере, построеной на интеграции идей.</p>
<p>Вместо этого, давайте я приведу другой пример. На скриншоте ниже — лист набранный в русской локали Microsoft Excel. Забавная штука в русскоязычном Excel — его встроенная библиотека функций так же была переведена, поэтому названия функций нужно набирать кириллицей.</p>
<p><img style="--image-object-fit:contain;width:auto" class="m_9e117634 mantine-Image-root" src="https://i.imgur.com/CQjyUpB.png" alt="имена функций кириллицей" loading="lazy"/></p>
<p><em>Кириллические имена функций в формулах MS Excel</em></p>
<p>Не буду врать, это выглядит возмутительно даже для меня. Но не для моего отца, инженера-строителя, который ни слова не знает на английском. Он пугающе разборчив в формулах Excel и широко использует их в документах из сотни страниц, обросших фильтрами, условиями и пивот-таблицами. Позже по этим расчётам строятся дороги и мосты. Он не знает, что означает <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">IF</code>, но постоянно использует <code style="margin-bottom:var(--mantine-spacing-lg)" class="m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight m_e597c321 mantine-CodeHighlight-codeHighlight m_dfe9c588 mantine-InlineCodeHighlight-inlineCodeHighlight">ЕСЛИ</code>. Что круто, так это если он отправит вам одну из этих электронных таблиц, и вы откроете её в оригинальном MS Excel, каждая формула отобразится на английском и будет работать именно так, как было задумано отцом.</p>
<p>Теперь представьте, что получили кусок с тысячами строчек "говнокода", который я показывал выше. Вы вероятно захотите скомпилировать его, но удачи разобраться с API, собранным из латинизированных русских слов и греческого алфавита. Понятия не имею, как нам сравняться с космополитизмом Excel в масштабах "настоящего" языка программирования. Кажется, это один из тех случаев, когда ограничения текста без форматирования, как основного средства для написания и распространения программ, выходят на первый план. В Excel такое возможно, потому что они контролируют и формат и окружение для разработки.</p>
<p>Некоторые программисты встают в защитную позу, когда дело касается обсуждения альтернатив обычному тексту. В "библии" многих современных программистов, книге "Прагматичный программист" (The Pragmatic Programmer), которую я читаю и которой делал ревью в <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://temochka.com/blog/posts/2017/04/24/pragmatic-programmer.html" rel="noopener noreferrer" target="_blank">своём блоге</a>, описанию простого текста, как сюрикэна прагматичных программистов, отведён целый раздел. Но чем больше распространяются продвинутые IDE (которые уже скрывают некоторые детали реализации) и всё шире адаптируются нетекстовые программные среды (вроде <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://scratch.mit.edu/" rel="noopener noreferrer" target="_blank">MIT Scratch</a> или <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://docs.unrealengine.com/latest/INT/Engine/Blueprints/GettingStarted/index.html" rel="noopener noreferrer" target="_blank">Unreal Blueprints</a>), кажется, всё более и более правдоподобным, что такой практичный инструмент программирования для каждого, который объединит все эти идеи, уже не за горами.</p>
<h4 id="heading-4-7">Подытожим</h4>
<p>Этот пост родился от моего отчаяния и бессилия перед названиями, как идентификаторами. А конкретно от негибкости однажды выбранных названий в таком пластичном мире, как разработка. Иногда меня просто заклинивает при выборе наглядного названия для нового проекта, функции или переменной. Частично это потому что именование — трудная штука, частично — потому что английский не мой родной язык. Но всё ещё остаётся область, где присваивать имена сложно из-за инструментов и методик программирования, которыми мы пользуемся сегодня.</p>
<p>Функциональное программирование сокращает количество уникальных названий в программе. Указания типов создают дополнительный слой смыслового содержания и позволяют использовать математическую нотацию без ущерба удобочитаемости. Статическая верификация типов и более строгие компиляторы упрощают создание более продвинутых инструментов для рефакторинга, что позволяет менять неудачные названия позже. В этом посте я попытался продемонстрировать, как такие направления и другие идеи могут сократить пробелы между разными культурами с помощью универсального языка вычислений.</p>
<p>Пожалуй, существенные изменения в этой области требуют выхода за рамки традиционных инструментов программирования (например, текстовых редакторов и CLI) и движение в сторону исключительно визуальных, интерактивных окружений. Как бы абсурдно это ни звучало, чтобы программирование стало "инструментом мышления", как его пропагандируют, оно должно учитывать уроки Excel и Illustrator, оно должно оставаться открытым к новым идеям, а не отвергать их как "непрактичные". Другими словами наши компьютеры должны обучаться универсальному языку — эмпатии.</p>
<ul>
<li><a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://news.ycombinator.com/item?id=14720254" rel="noopener noreferrer" target="_blank">Обсуждение на HackerNews</a></li>
<li><a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://www.reddit.com/r/programming/comments/6lorwy/the_language_of_programming/?st=j4x7n3fh&sh=c9553c3c" rel="noopener noreferrer" target="_blank">Обсуждение на Reddit</a></li>
</ul>
<p><em>Перевод: <a style="text-decoration:underline" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="https://www.instagram.com/minotauria" rel="noopener noreferrer" target="_blank">Наталия Басс</a></em></p>
<style data-mantine-styles="inline">.__m__-_R_4dderddmiub_{--carousel-slide-gap:var(--mantine-spacing-xs);--carousel-slide-size:80%;}@media(min-width: 36em){.__m__-_R_4dderddmiub_{--carousel-slide-gap:var(--mantine-spacing-xl);--carousel-slide-size:50%;}}</style><div style="--carousel-control-size:calc(2.5rem * var(--mantine-scale));--carousel-controls-offset:var(--mantine-spacing-sm);margin-bottom:var(--mantine-spacing-lg);padding-block:var(--mantine-spacing-sm);background:var(--app-color-surface)" class="m_17884d0f mantine-Carousel-root responsiveClassName" data-orientation="horizontal" data-include-gap-in-size="true"><div class="m_39bc3463 mantine-Carousel-controls" data-orientation="horizontal"><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="previous" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button><button class="mantine-focus-auto m_64f58e10 mantine-Carousel-control m_87cf2631 mantine-UnstyledButton-root" type="button" data-inactive="true" data-type="next" tabindex="-1"><svg viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg" style="transform:rotate(-90deg);width:calc(1rem * var(--mantine-scale));height:calc(1rem * var(--mantine-scale));display:block"><path d="M3.13523 6.15803C3.3241 5.95657 3.64052 5.94637 3.84197 6.13523L7.5 9.56464L11.158 6.13523C11.3595 5.94637 11.6759 5.95657 11.8648 6.15803C12.0536 6.35949 12.0434 6.67591 11.842 6.86477L7.84197 10.6148C7.64964 10.7951 7.35036 10.7951 7.15803 10.6148L3.15803 6.86477C2.95657 6.67591 2.94637 6.35949 3.13523 6.15803Z" fill="currentColor" fill-rule="evenodd" clip-rule="evenodd"></path></svg></button></div><div class="m_a2dae653 mantine-Carousel-viewport" data-type="media"><div class="m_fcd81474 mantine-Carousel-container __m__-_R_4dderddmiub_" data-orientation="horizontal"><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/environment"><div style="padding-top:0rem;height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="margin-bottom:var(--mantine-spacing-sm)" class="m_599a2148 mantine-Card-section" data-first-section="true"><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img class="m_9e117634 mantine-Image-root" src="/vite/assets/blog_post-7eTyeLLt.webp" loading="lazy" alt="Среды разработки: какие они бывают и чем отличаются друг от друга"/></div></div><p style="margin-bottom:var(--mantine-spacing-xs);font-size:var(--mantine-font-size-lg);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Среды разработки: какие они бывают и чем отличаются друг от друга</p><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Сооснователь Хекслета Кирилл Мокевнин рассказывает, какие бывают среды разработки, как проводится...</p><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-sm)" class="m_4081bf90 mantine-Group-root">21 марта 2023 г.<p style="font-size:inherit" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/10-sovetov-o-tom-kak-bolee-effectivno-uchitsya-na-hexlet"><div style="padding-top:0rem;height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="margin-bottom:var(--mantine-spacing-sm)" class="m_599a2148 mantine-Card-section" data-first-section="true"><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img class="m_9e117634 mantine-Image-root" src="/vite/assets/blog_post-7eTyeLLt.webp" loading="lazy" alt="10 советов, как более эффективно учиться в Хекслете"/></div></div><p style="margin-bottom:var(--mantine-spacing-xs);font-size:var(--mantine-font-size-lg);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">10 советов, как более эффективно учиться в Хекслете</p><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Делимся десятью лайфхаками, которые повысят эффективность обучения на Хекслете.</p><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-sm)" class="m_4081bf90 mantine-Group-root">7 ноября 2022 г.<p style="font-size:inherit" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></a></div></div><div class="m_d98df724 mantine-Carousel-slide" data-orientation="horizontal"><div tabindex="0" style="cursor:pointer;height:100%"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/effective_shell_navigation"><div style="padding-top:0rem;height:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root" data-with-border="true"><div style="margin-bottom:var(--mantine-spacing-sm)" class="m_599a2148 mantine-Card-section" data-first-section="true"><div style="--ar-ratio:2" class="m_71ac47fc mantine-AspectRatio-root"><img class="m_9e117634 mantine-Image-root" src="/vite/assets/blog_post-7eTyeLLt.webp" loading="lazy" alt="Как работать с командной строкой эффективно: 6 советов от разработчика Дейва Керра"/></div></div><p style="margin-bottom:var(--mantine-spacing-xs);font-size:var(--mantine-font-size-lg);font-weight:bold" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Как работать с командной строкой эффективно: 6 советов от разработчика Дейва Керра</p><p style="margin-bottom:auto" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Чем больше программист работает в командной строке, тем сложнее ему ориентироваться в тексте и ко...</p><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-top:var(--mantine-spacing-lg);font-size:var(--mantine-font-size-sm)" class="m_4081bf90 mantine-Group-root">28 октября 2022 г.<p style="font-size:inherit" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></div></a></div></div></div></div></div>
<hr/>
<p><em>От редактора:</em> Мы на Хекслете часто публикуем переводы статей. Важно помнить:</p>
<ol>
<li>Мнение автора статьи может отличаться от мнения администрации и сотрудников Хекслета.</li>
<li>Цель перевода – показать мнение. Поэтому одна статья может визуально противоречить другой: это просто разные мнения. Мы оставляем на вашу ответственность возможность анализировать и делать выводы для себя.</li>
</ol></div><div class=""><div style="--group-gap:var(--mantine-spacing-md);--group-align:center;--group-justify:space-between;--group-wrap:wrap;margin-bottom:var(--mantine-spacing-lg)" class="m_4081bf90 mantine-Group-root"><div class="m_4451eb3a mantine-Center-root" data-inline="true"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:var(--mantine-spacing-xs);color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-user "><path d="M8 7a4 4 0 1 0 8 0a4 4 0 0 0 -8 0"></path><path d="M6 21v-2a4 4 0 0 1 4 -4h4a4 4 0 0 1 4 4v2"></path></svg></div><p style="margin-inline-end:var(--mantine-spacing-xl)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Natalia Bass</p><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">9 лет назад</p></div><div style="align-items:center" class="m_8bffd616 mantine-Flex-root __m__-_R_5dirddmiub_"><a style="display:inline-flex" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/the-language-of-programming/votes"><div style="--ti-size:var(--ti-size-sm);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-inline-end:var(--mantine-spacing-xs);color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="sm"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-thumb-up "><path d="M7 11v8a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-7a1 1 0 0 1 1 -1h3a4 4 0 0 0 4 -4v-1a2 2 0 0 1 4 0v5h3a2 2 0 0 1 2 2l-1 5a2 3 0 0 1 -2 2h-7a3 3 0 0 1 -3 -3"></path></svg></div></a><p class="mantine-focus-auto m_b6d8b162 mantine-Text-root">4</p></div></div></div><div style="background-color:var(--mantine-color-indigo-light);border:calc(0.0625rem * var(--mantine-scale)) solid transparent;padding:var(--mantine-spacing-xl)" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root"><p style="margin-bottom:var(--mantine-spacing-sm);font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Читайте также:</p><ul style="margin-inline-start:var(--mantine-spacing-lg)" class="m_abbac491 mantine-List-root"><li style="margin-bottom:var(--mantine-spacing-sm)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><a style="color:inherit" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/environment">Среды разработки: какие они бывают и чем отличаются друг от друга</a></span></div></li><li style="margin-bottom:var(--mantine-spacing-sm)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><a style="color:inherit" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/10-sovetov-o-tom-kak-bolee-effectivno-uchitsya-na-hexlet">10 советов, как более эффективно учиться в Хекслете</a></span></div></li><li style="margin-bottom:var(--mantine-spacing-sm)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><a style="color:inherit" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/blog/posts/effective_shell_navigation">Как работать с командной строкой эффективно: 6 советов от разработчика Дейва Керра</a></span></div></li></ul></div><div style="margin-block:var(--mantine-spacing-xl)" class="m_3eebeb36 mantine-Divider-root" data-orientation="horizontal" role="separator"></div></div><div></div></div><style data-mantine-styles="inline">.__m__-_R_lmiub_{--col-flex-grow:auto;--col-flex-basis:100%;--col-max-width:100%;}@media(min-width: 48em){.__m__-_R_lmiub_{--col-flex-grow:auto;--col-flex-basis:16.666666666666668%;--col-max-width:16.666666666666668%;}}@media(min-width: 62em){.__m__-_R_lmiub_{--col-flex-grow:auto;--col-flex-basis:33.333333333333336%;--col-max-width:33.333333333333336%;}}</style><div class="m_96bdd299 mantine-Grid-col __m__-_R_lmiub_ mantine-visible-from-md"><div style="background-color:var(--mantine-color-indigo-light);border:calc(0.0625rem * var(--mantine-scale)) solid transparent;margin-bottom:var(--mantine-spacing-xl);padding:var(--mantine-spacing-xl);width:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root"><div style="margin-bottom:var(--mantine-spacing-md)" class="m_4451eb3a mantine-Center-root" data-inline="true"><p style="font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Категории</p></div><ul class="m_abbac491 mantine-List-root"><li style="margin-bottom:var(--mantine-spacing-xs)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><button style="color:inherit;text-decoration:underline" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Мотивация">Мотивация</button></span></div></li><li style="margin-bottom:var(--mantine-spacing-xs)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><button style="color:inherit;text-decoration:underline" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Истории успеха">Истории успеха</button></span></div></li><li style="margin-bottom:var(--mantine-spacing-xs)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><button style="color:inherit;text-decoration:underline" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Дневник студента">Дневник студента</button></span></div></li><li style="margin-bottom:var(--mantine-spacing-xs)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><button style="color:inherit;text-decoration:underline" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Код">Код</button></span></div></li><li style="margin-bottom:var(--mantine-spacing-xs)" class="m_abb6bec2 mantine-List-item" data-with-icon="true"><div class="m_75cd9f71 mantine-List-itemWrapper"><span class="m_60f83e5b mantine-List-itemIcon"><div class="m_4451eb3a mantine-Center-root"><div style="--ti-size:var(--ti-size-xs);--ti-bg:transparent;--ti-color:var(--mantine-color-indigo-light-color);--ti-bd:calc(0.0625rem * var(--mantine-scale)) solid transparent;color:inherit" class="m_7341320d mantine-ThemeIcon-root" data-variant="transparent" data-size="xs"><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.2" stroke-linecap="round" stroke-linejoin="round" class="tabler-icon tabler-icon-chevron-compact-right "><path d="M11 4l3 8l-3 8"></path></svg></div></div></span><span class="mantine-List-itemLabel"><button style="color:inherit;text-decoration:underline" class="mantine-focus-auto m_87cf2631 mantine-UnstyledButton-root" type="button" aria-label="Карьера">Карьера</button></span></div></li></ul></div><div style="justify-content:end;margin-top:0rem;position:sticky;top:calc(5rem * var(--mantine-scale))" class="m_8bffd616 mantine-Flex-root __m__-_R_5dlmiub_"><div tabindex="0" style="cursor:pointer"><a style="text-decoration:none" class="mantine-focus-auto m_849cf0da m_b6d8b162 mantine-Text-root mantine-Anchor-root" data-underline="hover" href="/courses_javascript?promo_name=program_category&promo_position=blog_post&promo_creative=card&promo_type=card"><div style="background-color:var(--mantine-color-default);border:calc(0.0625rem * var(--mantine-scale)) solid var(--mantine-color-default-border);padding-inline:var(--mantine-spacing-xl);padding-top:var(--mantine-spacing-xl);padding-bottom:var(--mantine-spacing-xs);width:100%" class="m_e615b15f mantine-Card-root m_1b7284a3 mantine-Paper-root"><div class="m_4451eb3a mantine-Center-root" data-inline="true"><p style="font-size:var(--mantine-font-size-h4)" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Курсы по JavaScript</p></div><img class="m_9e117634 mantine-Image-root" src="/vite/assets/development-BVihs_d5.png"/><p style="margin-bottom:var(--mantine-spacing-xs);text-align:right" class="mantine-focus-auto m_b6d8b162 mantine-Text-root">Посмотреть →</p></div></a></div></div></div></div></div></div></div>
</main>
<footer class="bg-dark fw-light text-light px-3 py-5">
<div class="row small">
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 mb-3">Хекслет</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/about">О нас</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/testimonials">Отзывы</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://b2b.hexlet.io" role="button">Корпоративное обучение</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/blog">Блог</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/qna">Вопросы и ответы</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/glossary">Глоссарий</a>
</li>
<li>
<span class="nav-link link-light py-1 ps-0 external-link" data-href="https://help.hexlet.io" data-target="_blank" role="button">Справка</span>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" target="_blank" rel="noopener noreferrer" href="/map">Карта сайта</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5 fw-normal mb-3">Направления</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_devops">DevOps
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_data_analytics">Аналитика
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_backend_development">Бэкенд
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_programming">Программирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_testing">Тестирование
</a></li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/courses_front_end_dev">Фронтенд
</a></li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Профессии</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/devops-engineer-from-scratch">DevOps-инженер с нуля</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/go">Go-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/java">Java-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python">Python-разработчик </a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/data-analytics">Аналитик данных</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/qa-engineer">Инженер по ручному тестированию</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php">РНР-разработчик</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/frontend">Фронтенд-разработчик</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-6 col-md-3">
<div class="h5">Навыки</div>
<ul class="list-unstyled">
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/python-django-developer">Django</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/docker">Docker</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/php-laravel-developer">Laravel</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/postman">Postman</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-react-developer">React</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/js-rest-api">REST API в Node.js</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/spring-boot">Spring Boot</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/programs/typescript">Typescript</a>
</li>
</ul>
</div>
</div>
<hr>
<div class="row">
<div class="col-12 col-sm-4 col-md-2">
<div class="fs-4">
<ul class="list-unstyled d-flex">
<li class="me-3">
<a aria-label="Telegram" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://t.me/hexlet_ru"><span class="bi bi-telegram"></span>
</a></li>
<li>
<a aria-label="Youtube" target="_blank" class="link-light" rel="noopener noreferrer nofollow" href="https://www.youtube.com/user/HexletUniversity"><span class="bi bi-youtube"></span>
</a></li>
</ul>
</div>
<div class="mb-2 d-flex flex-column">
<a class="link-light text-decoration-none" rel="nofollow" href="mailto:support@hexlet.io">support@hexlet.io</a>
<a class="link-light text-decoration-none py-2" target="_blank" href="https://t.me/hexlet_help_bot">t.me/hexlet_help_bot</a>
</div>
<ul class="list-unstyled d-flex">
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://hexlet.io/locale/switch?new_locale=en" data-target="_self" role="button"><span class="my-auto">EN</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 opacity-100 external-link" rel="nofollow" data-href="https://ru.hexlet.io/locale/switch?new_locale=ru" data-target="_self" role="button"><span class="my-auto">RU</span>
</span></li>
<li class="me-3">
<span class="link-light text-decoration-none opacity-50 x-font-size-18 external-link" rel="nofollow" data-href="https://kz.hexlet.io/locale/switch?new_locale=kz" data-target="_self" role="button"><span class="my-auto">KZ</span>
</span></li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<ul class="list-unstyled fs-4">
<li class="mb-3">
<a class="link-light text-decoration-none" href="tel:8%20800%20100%2022%2047">8 800 100 22 47</a>
<span class="d-block opacity-50 small">бесплатно по РФ</span>
</li>
<li>
<a class="link-light text-decoration-none" href="tel:%2B7%20495%20085%2021%2062">+7 495 085 21 62</a>
<span class="d-block opacity-50 small">бесплатно по Москве</span>
</li>
</ul>
</div>
<div class="col-12 col-sm-4 col-md-3">
<div class="small mb-3">Образовательные услуги оказываются на основании Л035-01298-77/01989008 от 14.03.2025</div>
<ul class="list-unstyled small">
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/legal">Правовая информация</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/offer">Оферта</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/license">Лицензия</a>
</li>
<li>
<a class="nav-link link-light py-1 ps-0" href="/pages/contacts">Контакты</a>
</li>
</ul>
</div>
<div class="col-12 col-sm-12 col-md-4 small">
<div class="mb-2">
<div>ООО «<a href="/" class="text-decoration-none link-light">Хекслет Рус</a>»</div>
<div>108813 г. Москва, вн.тер.г. поселение Московский,</div>
<div>г. Московский, ул. Солнечная, д. 3А, стр. 1, помещ. 20Б/3</div>
<div>ОГРН 1217300010476</div>
<div>ИНН 7325174845</div>
</div>
<hr>
<div>АНО ДПО «<a href="/" class="text-decoration-none link-light">Учебный центр «Хекслет</a>»</div>
<div>119331 г. Москва, вн. тер. г. муниципальный округ</div>
<div>Ломоносовский, пр-кт Вернадского, д. 29</div>
<div>ОГРН 1247700712390</div>
<div>ИНН 7736364948</div>
</div>
</div>
</footer>
<div id="root-assistant-offcanvas"></div>
<script src="/vite/assets/assistant-Bukl1lYy.js" crossorigin="anonymous" type="module"></script><link rel="modulepreload" href="/vite/assets/chunk-DsPFFUou.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/init-BrRXra1y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/ErrorFallbackBlock-naDSYSy9.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/MarkdownBlock-DbyKWoR_.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/gon-D3e4yh1x.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/mantine-CGMYrt2Y.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/shiki-V011pkdv.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/utils-DRqSHbQE.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/routes-CCH8ilKF.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-XR8Qr8kR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dist-GCHh59xr.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/Box-B5-OOzBf.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/notifications.store-C-3AFSMn.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useIsomorphicEffect-HJ6VK0D3.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/lib-KSp6QbZ0.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/axios-BEvgo0ym.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/classnames-l6ipYlLR.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/dayjs.min-BkKovM-s.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/debounce-jMQ_Cf4f.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/i18next-BlSq9s7B.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/client-U9M77rxp.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-dom-DaLxUz_h.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/useTranslation-Bx1Cdrkz.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/compiler-runtime-6XxiPFnt.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/jsx-runtime-CwjcCKJi.js" as="script" crossorigin="anonymous">
<link rel="modulepreload" href="/vite/assets/react-CkL4ZRHB.js" as="script" crossorigin="anonymous">
<script defer src="https://static.cloudflareinsights.com/beacon.min.js/v67327c56f0bb4ef8b305cae61679db8f1769101564043" integrity="sha512-rdcWY47ByXd76cbCFzznIcEaCN71jqkWBBqlwhF1SY7KubdLKZiEGeP7AyieKZlGP9hbY/MhGrwXzJC/HulNyg==" data-cf-beacon='{"version":"2024.11.0","token":"d11015b65d11429ea6b4a2ef37dd7e0b","server_timing":{"name":{"cfCacheStatus":true,"cfEdge":true,"cfExtPri":true,"cfL4":true,"cfOrigin":true,"cfSpeedBrain":true},"location_startswith":null}}' crossorigin="anonymous"></script>
</body>
</html>