Сложность В Простоте Go

Читая о языке Go, вы часто слышите слово «простота».

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

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



Сложность в простоте Go



О сложности.

Простота является противоположностью сложности.

Сложность разработки программного обеспечения – тема, давно волнующая умы инженеров и ученых, а один из наиболее концептуальных подходов к вопросу был сформулирован автором знаменитой книги «Мифический человеко-месяц».

Фредерик Брукс , в виде отдельного произведения - «Серебряной пули не существует» ( «Нет серебряной пули» ).

Эта работа была написана в 1987 году, но концептуальный взгляд на тему делает ее актуальной и 30 лет спустя.

В частности, Брукс делает важное разделение сложности на «врожденный» ( существенный ) И "принес в" (или «случайный» — случайный ).

Внутренняя сложность - это сложность, которая исходит из самой области проблемы, из ее природы.

Скажем, если вам нужно реализовать протокол FTP, неважно, какой язык или инструментарий вы для этого выберете, у вас все равно есть набор команд, действий, кодов возврата и логики, которые придется реализовать.

Невозможно упростить задачу до однострочной реализации.

Сложность вам дана как задана (в данном случае из спецификации протокола), и в целом у вас нет возможности повлиять на эту составляющую.

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

Это сложность, которую мы сами себе создаем.

Мы можем повлиять на него и уменьшить его.

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



Почему сложность — это плохо?

Все должно быть сделано максимально просто.

Но это не проще.

Альберт Эйнштейн

Ответ на вопрос «хорошо» или «плохо»? — лежит исключительно в области признания или непризнания хороших и плохих практик.

Не существует формального способа доказать, что, скажем, «глобальные переменные» хороши или плохи.

Рассматривая отдельные примеры, сторонники каждой стороны найдут для вас сотню убедительных аргументов как за, так и против.

Но собрав, хотя бы частично, опыт многих и многих разработчиков программного обеспечения, работающих с самыми разными программистами и языками, вы так или иначе услышите высказывания о «хороших практиках» или «плохих практиках».

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

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

при необходимости (рефакторинг), что, в свою очередь, создает стимул не вносить эти изменения, что, в свою очередь, приводит к тому, что разработчики начинают искать обходные пути и так далее.

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

Сложность убивает производительность, поэтому вся индустрия разработки движется в сторону снижения сложности.



При чем здесь языки программирования?

Управление сложностью — это квинтэссенция программирования.

Брайан Керниган

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

Сами языки программирования также являются инструментами снижения сложности разработки.

И каждый раунд их разработки так или иначе решает один из аспектов сложности разработки ПО, но тем самым привносит новые элементы сложности.

Вся история их развития – это история поиска более простого инструмента для реалий того времени.

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

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

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

Другими словами, это очень сложная махина.

Простого решения здесь нет и не может быть.

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

Некоторые практики и шаблоны («шаблоны — это отчет об ошибках на вашем языке»), навязанные языками, увеличивают общую сложность разработки, а другие уменьшают ее.

И мы, как инженеры, должны в конечном итоге стремиться избежать этой «внесенной сложности».



Сложность в Го

Go родился как ответ на возросшую сложность существующих языков.

По крайней мере, в той предметной области, которая волновала Google — разработка системного, сетевого и серверного ПО.

Его главной целью изначально было уменьшить эту сложность любой ценой.

Это было главным приоритетом с самого начала.

Немалую роль здесь сыграл огромный практический опыт авторов Go — Пайка, Томпсона и компании — людей, которые стояли у истоков Unix, языка C и UTF-8, а сейчас работают над ключевыми продуктами Google. Так или иначе, Go был своего рода радикальным языком, который качнул маятник сложности в другую сторону, пытаясь выровнять существующий ландшафт мира разработки программного обеспечения.

И это именно то, что подразумевается под термином «простота» в контексте Go. Уменьшение сложности.

Сокращение времени, необходимого среднестатистическому программисту для понимания среднестатистического проекта, написанного другими людьми.

Снижение риска ошибок.

Сокращение времени и затрат на «передовую практику».

Уменьшение шансов написать плохой и некрасивый код. Сокращение времени на освоение языка.

И так далее и тому подобное.



Числа

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

В комментариях к предыдущим статьям отсутствие «формальных доказательств» стало причиной жарких споров.

Скажу сразу, что понимаю сложность этой задачи.

Реальная оценка лежит в плоскости субъективного практического опыта и трудноизмеримых вероятностей.

Не существует простого способа свести все к одному числу и сказать: «сложность языка А больше, чем сложность языка Б».

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

Ваш мозг каким-то образом знает, как оценить и решить, какой язык сложнее.

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

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

Мы не рассматриваем такие экзотические вещи, как Brainfuck.

Способ 1.
Один из таких простейших методов — подсчет ключевых слов языка.

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

Оценка будет очень грубой, но вполне показательной и логичной.

Логично, потому что меньше знаний означает меньшую когнитивную нагрузку на мозг.

Вот что у нас есть:

Питон 2.7 31 docs.python.org/2.7/reference/lexical_anaанализ.

html

Питон 3 33 docs.python.org/3.4/reference/lexical_anaанализ.

html

Луа 21 www.lua.org/manual/5.1/manual.html
С (С99) 32 en.wikipedia.org/wiki/C_syntax#Reserved_keywords
С (С11) 37 en.wikipedia.org/wiki/C_syntax#Reserved_keywords
С++11 85 en.cppreference.com/w/cpp/keyword
Идти 25 golang.org/ref/spec
JS (ECMAScript 5.1) 41 www.ecma-international.org/ecma-262/5.1/#sec-7.6.1
Хаскелл 55 www.haskell.org/haskellwiki/Keywords
Джава 50 en.wikipedia.org/wiki/List_of_Java_keywords
С# 79 msdn.microsoft.com/en-us/library/x53a06bb.aspx
PHP 58 www.php.net/manual/en/reserved.keywords.php
Рубин 1.9 42 Ruby-doc.org/docs/keywords/1.9
Скала 41 www.scala-lang.org/files/archive/spec/2.11/01-lexical-syntax.html
Эрланг 27? erlang.org/doc/reference_manual/introduction.html
То же самое в виде графика:

Сложность в простоте Go



Способ 2
Вы можете попробовать оценить грамматики языка, многие из которых описываются с помощью Формы Бэкуса-Наура .

Грамматики в этом формате (BNF/EBNF) есть не для всех языков, но в Интернете довольно много разных грамматик, составленных полуавтоматически.

Например, я взял несколько грамматик отсюда: slps.github.io/zoo/index.html .

Я оценю количество правил, используя простые однострочники.

Например, для Go очень легко извлечь правила ENBF прямо со страницы спецификации официального языка:

   

$ curl -s http://golang.org/ref/spec | grep pre.*ebnf | wc -l

Хотя в других спецификациях подсчитать количество правил иногда не очень просто.

На всякий случай я приведу с собой команду, которой, как я думал, я являюсь.

Язык Количество правил
С 65
Идти 58
Питон 83
Хаскелл 78
JS (ECMAScript 5.1) 128
Руби (для 1.4) 37
Java (JRE 1.9) 216
С++ (2008 г.

)

159
С# 4.0 314
Луа 5.1 25
PHP 146
Ржавчина 115
Эрланг 219
Скала 143
Команды подсчета : С локон -s www.cs.man.ac.uk/~pjj/bnf/c_syntax.bnf | греп ": " | туалет -л Идти локон -s golang.org/ref/spec | grep pre.*ebnf | туалет -л Питон вручную скопировать текст из docs.python.org/2/reference/grammar.html , затем «cat py.bnf | грэп ": " | туалет-л" Хаскелл www.haskell.org/onlinereport/haskell2010/haskellch10.html#x17-17500010 JS (ECMAScript 5.1) локон -s www.ecma-international.org/ecma-262/5.1 | grep '.

*::'| тр -д ' ' | сортировка -у | туалет -л Руби (для 1.4) локон -s docs.huihoo.com/ruby/ruby-man-1.4/yacc.html | греп ": " | туалет -л Java (JRE 1.9) локон -s docs.oracle.com/javase/specs/jls/se8/html/jls-19.html | греп '' | туалет -л С++ (2008 г.

) локон -s slps.github.io/zoo/cpp/iso-n2723.bnf | egrep ":$" | туалет -л С# 4.0 локон -s slps.github.io/zoo/cs/csharp-msft-ls-4.0.bnf | egrep ":$" | туалет -л Луа 5.1 локон -s wiki.luajit.org/Extended-BNF | греп "::=" | туалет -л PHP локон -s slps.github.io/zoo/php/cordy.bnf | egrep ":$" | туалет -л Ржавчина локон -s doc.rust-lang.org/grammar.html | grep "[a-z_]* :" | туалет -л Эрланг локон -s raw.githubusercontent.com/ignatov/intellij-erlang/master/grammars/erlang.bnf | греп "::=" | туалет -л Скала локон -s www.scala-lang.org/files/archive/spec/2.11/13-syntax-summary.html | греп "::=" | туалет -л В виде графика:

Сложность в простоте Go

Опять же, эти методы не дают объективной картины и цифр, но дают приблизительную оценку одного из факторов сложности языка.



Способ 3.
Третий метод оценки практической сложности языка будет основан на статистических данных — количестве вопросов на StackOverflow с учетом коэффициента популярности языка.

Предвижу критику, что методика спорная, но на самом деле она имеет смысл, и ребята из RedMonk уже некоторое время даже ведут такую статистику: redmonk.com/sogrady/2015/01/14/language-rankings-1-15 StackOverflow хорош тем, что благодаря модерации теги по языкам расставлены довольно аккуратно, и это, как ни крути, теперь место, куда многие люди ходят с вопросами даже раньше, чем на официальный сайт - там даже придумали термин - SODD, Разработка, управляемая переполнением стека.

Поэтому логично предположить, что чем больше вопросов, тем непонятнее, тем сложнее (хотя факторов, влияющих, конечно, еще очень много).

StackOverflow удобно предоставляет количество вопросов по тегам здесь: stackoverflow.com/tagsЭpage=2&tab=popular В этом случае, конечно, нужно учитывать абсолютное количество людей, пишущих на том или ином языке, и для этого я возьму рейтинг репозиториев GitHub за последний квартал 2014 года, доступный в чудесном виде здесь: githut.info и я буду рассматривать количество активных репозиториев как коррелирующий показатель количества людей, активно использующих язык.

А дальше схема проста — количество вопросов на StackOverflow делим на количество активных репозиториев на Github. Чем выше число, тем сложнее язык.

Вот что происходит:

Язык Репозитории на GitHub Вопросы по СО Соотношение
Идти 22264 10272 0,46
Рубин 132848 136920 1,03
Луа 8123 8502 1,04
Ржавчина 4383 2478 1,76
С 73075 184984 2,53
Хаскелл 8789 22930 2,60
Питон 2.7 164852 439994 2,66
JS 323938 880188 2,71
Джава 222852 879064 3,94
С++ 86505 377834 4,36
PHP 138771 768018 5,53
С# 56062 811952 14,48
Эрланг 2961 5571 1,88
Скала 10853 38302 3,52
Расписание:

Сложность в простоте Go



выводы

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

Ошибка здесь может быть очень большой (например, грамматика Ruby здесь проще, чем грамматика Go, но этот однострочный скрипт считает только количество правил, но не их сложность — и весь синтаксический сахар Ruby, который добавляет довольно небольшая сложность, здесь не учитывается).

Если у кого-то есть еще идеи, как объективно оценить сложность языков программирования, пишите, буду рад услышать и обсудить.

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

Меня немного удивил результат Rust на последнем графике — ведь Rust отнюдь не простой язык: скорее всего этот результат связан с молодостью языка (версия 1.0 вышла пару месяцев назад) , и, как следствие, высокая средняя квалификация разработчиков ржавчины — отсюда и низкая относительная активность на Stack Overflow. В целом эти цифры подтверждаются моими личными наблюдениями, по крайней мере, на тех языках, которые знаю лично я.

А тех, кого я не знаю, я оцениваю достаточно внимательно.

Предвижу критику вышеизложенных методов и заявления об их неадекватности.

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

Хоть статья и посвящена простоте Go, это далеко не единственная причина его успеха, хотя и одна из важных.

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



Заключение

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

Это было задумано вопреки распространенному мнению – «чем сложнее, тем лучше» – и принесло ожидаемый эффект. Число людей и проектов, подхвативших Go, растёт быстрыми темпами (сегодня нет графиков, ссор)), и многие делают упор на это «освежающее» качество Go — его простоту.

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

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

Возможно, вы все еще помните то веселье, когда писали свои первые программы.

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

Но при этом вы пишете не Hello, World, а качественный современный софт, быстрый, кроссплатформенный, многопоточный и безопасный.

У каждого языка есть своя ниша, свои компромиссы, свои плюсы и минусы.

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



Ссылки

Нет серебряной пули - факультет.salisbury.edu/~xswang/Research/Papers/SERelated/no-silver-bullet.pdf Меньше значит экспоненциально больше — Commandcenter.blogspot.com/2012/06/less-is-exponentially-more.html Меньше - больше - лямбда-the-ultimate.org/node/4852 Теги: #Go #complexity #complexity #brooks #complexity #Разработка сайтов #программирование #Системное программирование #Go
Вместе с данным постом часто просматривают: