"Объясняю каждую строчку" - Основы. Три блока, из которых можно составить любую программу

https://www.furaffinity.net/user/shadify/
https://www.furaffinity.net/user/shadify/

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

Обычно я занимаюсь тем, что запускаю стрим на своём ютуб-канале, открываю Visual Studio и делаю свою видеоигру, попутно объясняя что да как. Но какое-то время назад Microsoft умудрилась так удачно сломать мне мою любимую IDE, что всё встало раком на неделю, а откатиться на прошлую версию Community Edition не позволяет. Поэтому, чтобы не раздолбать голову об клавиатуру во время очередной (четвёртый раз за три месяца) паузы, я попытался нести доброе, разумное, вечное в ином формате. Сделать что-то, что позволить войти в это дело с абсолютного нуля. Мои стримы для этого подходят не очень, так что начну с пересказа школьных учебников информатики с поправкой на опыт, полученный в отрасли. А там, глядишь, и до более сложных концепций доживём.

Дисклеймеры:

  • Когда я говорю с абсолютного нуля, я имею в виду с абсолютного НУЛЯ.
  • Я сеньор-помидор в EPAM'е. С опытом где-то под десять лет. Не то, чтобы тяну на гуру, но об этих вещах я рассказать ещё могу.
  • Эти тексты language-agnostic. Это значит, что излагаемое не привязано ни к какому языку. Скорее всего, я буду приводить примеры на C# и Python. Первый — мой хлеб, второй — немного мне знаком и любим новичками. Почему так? Мастерство -> инструмент. Если ищете здесь туториал по языку, лучше копните документацию. Здесь то, что упростит освоение языков.
  • Это не то, что поможет вам устроится на работу завтра. Это то, что поможет вам понять как вообще пишутся эти программы. Эта серия текстов будет недостаточна, если ваш маршрут по этой жизни: "филфак -> макдак -> войти в айти, чтоб не откинуть коньки". Но это поможет лучше понять то, что вам впихивают на трёхмесячных курсах.
  • Есть только один язык, который должен знать каждый программирующий: английский. Эти тексты на русском, но желательно, чтобы попадающиеся в программах слова типа "if", "else", "while", "string", "integer" не приводили вас в ступор.
  • Писать буду, что называется, под настроение.

Что такое программа? Это инструкция для ЭВМ. Электронно-Вычислительная Машина. Да, я знаю, каким совковым вайбом веет от этого термина. Я бы написал, что для компьютера, но не знаю, можно ли назвать так микроволновки, холодильники, приставки, телефоны, фотоаппараты, телевизоры и весь тот зоопарк устройств в который нынче принято втыкать микросхемы. Инструкция для ЭВМ, естественно, должна быть написана на языке, который этой ЭВМ понятен. Языков — миллиарды, но идеи за ними более-менее схожи.

Одна из них провозглашена Никлаусом Виртом и звучит так: программа = алгоритм + структуры данных. Алгоритм - то, что мы делаем. Структуры данных - то, с чем мы это делаем. Мой план на первые статьи - говорить об каждой из этих половинок по очереди. Сегодня немножко поговорим про первое.

Алгоритм — слово из математики, очень старое. В честь арабского учёного 9 века. Если откинуть лишний формализм, то алгоритм — это пошаговая инструкция, которую исполнитель может понять и выполнить. Инструкция по сборке шкафа из Икеи. Объяснение как пройти в библиотеку. Если объясняющий трезв, конечно. Алгоритм решения квадратных уравнений. Рецепт жаркого на ютубе или в кулинарной книге. Рецепт жаркого, записанный в мультиварке. Алгоритм сортировки чисел. Алгоритм, определяющий что из найденного гуглом важнее. Он, кстати, сделал из гугла тот самый гугл в своё время. Алгоритм, накидывающий вам рекомендации на ютубе. Алгоритм, соотносящий ввод с геймпада и движения Ори. Надеюсь, идея понятна.

И в наших ЭВМ алгоритмы писались на языках, которые понятны этим ЭВМ конечно. И они их понимали, и добросовестно выполняли, но был нюанс. Понимаете, в чём дело. Одно дело, когда алгоритм выглядит так:

1) Попросить пользователя ввести число 2) Прочитать это число 3) Если оно меньше нуля или это вообще не число, переходим к шагу 6 4) Записываем наше неотрицательное число 5) Переходим к шагу 1 6) Теперь "самое большое число" - 0 7) Теперь "мы проверяем" число номер 1 8) Если номер "мы проверяем" больше количества записанных чисел, переходим к шагу 13 9) Смотрим, какое число записано под номером "мы проверяем" 10) Если оно больше "самого большого числа", то теперь "самое большое число" - число под номером "мы проверяем" 11) "Мы проверяем" увеличивается на 1 (чтоб проверять следующее число) 12) Переходим к шагу номер 9 13) Выводим на экран "самое большое число"

Это немного ломает мозг, но если вы это прочитаете внимательно, то поймёте: если проделать это шаг за шагом, на экране появится самое большое число из тех, что ввёл пользователь. И пока наш алгоритм состоит из 10-15 шагов это не проблема для профессионала, привычного ко всему. А вот когда шагов уже хотя бы 30-50, это со-о-о-овсе-е-ем другое дело:

12) Допустимая белиберда равна 5 ... 93) Увеличиваем координату X третьей сепульки в два раза 94) Если координата Х третьей сепульки больше правой границы поля, переходим к шагу номер 27 95) Уменьшаем координату Y третьей сепульки в четыре раза 96) Если координата Y третьей сепульки меньше нижней границы поля, переходим к шагу номер 35 ... 115) Нижняя граница поля вводится пользователем 116) Если пользователь ввёл белиберду, к счётчику белиберды прибавляем 1 117) Если пользователь ввёл число, переходим к шагу 120 118) Если счётчик белиберды больше допустимой белиберды, переходим к шагу 17 119) Переходим к шагу 115 120) Верхняя граница поля вводится пользователем 121) Если пользователь ввёл число, переходим к шагу 124 122) Если пользователь ввёл белиберду, к счётчику белиберды прибавляем 1 123) Если счётчик белиберды больше допустимой белиберды, переходим к шагу 17 ...

От одной попытки написать с десяток шагов так плавится мозг. Если шагов десятки, это превращается в так называемый «спагетти-код», когда схема порядка шагов похожа на вываленные в кастрюлю макароны. А ведь кто-то так составлял алгоритмы из сотен, тысяч и даже десятков тысяч шагов.

Прервал этот ужас голландский математик Эдгар Дейкстра, который ворвался в зарождающуюся отрасль, открыв дверь с ноги, и заявил приблизительно следующее: «ваши переходы между командами ересь, ад и ужас, мы должны запретить алгоритмы, в которых это есть, больше никаких «переходим к такому-то шагу», вообще никогда, ни при каких условиях, запретите так делать». Взамен предлагалась идея структурного программирования.

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

  • Линейное выполнение — выполняем команду 1, выполняем команду 2, выполняем команду 3, …, выполняем команду N
  • Ветвление — если какое-то условие истинно, выполняем команду 1, иначе выполняем команду 2
  • Цикл — пока какое-то условие истинно, выполняем команду 1

Демонстрация идей:

Попросить пользователя ввести число Пока то, что ввёл пользователь является числом и больше 0 Записать то, что ввёл пользователь Попросить пользователя ввести число Теперь "самое большое число" - 0 Теперь номер "мы проверяем" - 1 Пока "мы проверяем" меньше количества записанных чисел Если число номер "мы проверяем" больше "самого большого числа", то Теперь "самое большое число" - число номер "то, что мы сейчас проверяем" К "мы проверяем" добавляем 1 Выводим на экран "самое большое число"

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

Ещё один важный нюанс — отступы. Отступы — это важно. Команды постоянно «вкладываются» и без отступов вы не поймёте, что куда вложено. Например, в Python программа откажется выполняться, если вы обходитесь с отступами абы как. В других языках вас побьют после код-ревью. Такая визуализация, объясняющая, что во что входит, необходима. Именно поэтому программный код всегда пишется моноширинным шрифтом. Без специальной функции «код» в редакторе постов DTF эти туториалы были бы невозможны.

Теперь примеры на настоящих языках.

// Это C#. После двойного слэша идут комментарии для программиста. ЭВМ это проигнорирует var numbers = new List<int>(); var user_input = Console.ReadLine(); while (int.TryParse(user_input, out var number) && number >= 0) { numbers.Add(number); user_input = Console.ReadLine(); } var maximum = 0; var checking_now = 0; // По сложившейся традиции, почти во всех современных языках программирования // В списках чисел нумерация начинается с нуля. // То есть, четыре числа будут иметь номера от 0 до 3 // О том, откуда эта традиция пошла, я могу отдельную статью запилить while (checking_now < numbers.Count) { if (numbers[checking_now] > maximum) maximum = numbers[checking_now]; checking_now += 1; } Console.WriteLine($"Самое большое число - {maximum}");

Обратите внимание на фигурные скобки. Это наследие языка C, который застал ещё Холодную войну. Они означают "объединить несколько команд в одну". Те самые "линии" из нескольких команд. Очень удобно для компилятора. Многие языки имеют такие конструкции. Да, вы можете записать код в одну строчку, но захочется ли вам так писать? Вам же потом это поддерживать.

Теперь пример на Python.

user_input = input("I need a number: ") numbers = [] while user_input.isdigit() and int(user_input) >= 0: numbers.append(int(user_input)) user_input = input("I need more numbers: ") checking_now = 0 maximum = 0 while checking_now < len(numbers): if numbers[checking_now] > maximum: maximum = numbers[checking_now] checking_now += 1 print("our biggest number is", maximum)

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

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

Линейное выполнение

Тут всё просто. Команды перечисляются одна за другой. Чаще всего их разделяют точкой с запятой. Иногда просто пишут на отдельной строчке. И почти всегда есть способ сказать ЭВМ "следующая команда — выполнить эти несколько команд по порядку". С помощью те же фигурных скобок. Дальше я иногда буду называть команды операторами, ладно?

Ветвление

Вы уже видели классический if. На всякий случай, покажу как выглядит классический if в его полной форме.

if numbers[checking_now] > maximum: maximum = numbers[checking_now] else: print("Nope, not this one")
if (numbers[checking_now] > maximum) maximum = numbers[checking_now]; else Console.WriteLine("Nope, not this one");

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

А теперь примеры. Частая ситуация на языке C#:

var day = Console.ReadLine(); if (day == "Monday") Console.WriteLine("Kill me, please"); else if (day == "Tuesday") Console.WriteLine("Meh"); else if (day == "Wednesday") Console.WriteLine("It's wednesday, my dudes"); else if (day == "Thursday") Console.WriteLine("Heh"); else if (day == "Friday") Console.WriteLine("Party"); else if (day == "Saturday") Console.WriteLine("Party!"); else if (day == "Sunday") Console.WriteLine("Party!!!"); else Console.WriteLine("???");

Да, мы нарушили здесь правило отступов. Потому что иначе последняя команда, которая "вложена" в другие команды на восьмом, что ли уровне, уедет за другой край экрана. А ведь в каждой ветке может быть что-то посложнее, чем "текст на экране". Специально для таких случаев в python (помним, что там с отступами всё предельно серьёзно) пришлось придумать свой "многоветочный» if. Вот как выглядит та же ситуация на этом языке (elif — это сокращение от else if) :

day = input() if day == "Monday": print("Kill me, please") elif day == "Tuesday": print("Meh") elif day == "Wednesday": print("It's wednesday, my dudes") elif day == "Thursday": print("Heh") elif day == "Friday": print("Party") elif day == "Saturday": print("Party!") elif day == "Sunday": print("Party!!!") else: print("???")

Так вот, python единственный известный мне язык, где возникла необходимость в "многоветочном" if. Для чего нам нужно ветвление? Чтобы наш алгоритм мог принять решение. И классический if позволяет принять решение, исходя из "истина/ложь". Но иногда нам надо принять решение на основе числа или строки, или каких-то данных сложнее, чем "0/1". И вот для этого почти во всех известных мне языках есть оператор выбора. Как обычно, сначала C#, потом python.

//К моему сожалению, оператор выбора в C# уродлив //Тяжёлое наследство прадедушки C. //Границы веток определяются оператором break switch (day) { case "Monday": Console.WriteLine("Kill me, please"); break; case "Tuesday": Console.WriteLine("Meh"); break; case "Wednesday": Console.WriteLine("It's wednesday, my dudes"); break; case "Thursday": Console.WriteLine("Heh"); break; case "Friday": Console.WriteLine("Party"); break; case "Saturday": Console.WriteLine("Party!"); break; case "Sunday": Console.WriteLine("Party!!!"); break; default: Console.WriteLine("???"); break; } //Иногда лучше написать вот так, конечно: switch (day) { case "Monday": Console.WriteLine("Kill me, please"); break; case "Tuesday": Console.WriteLine("Meh"); break; case "Wednesday": Console.WriteLine("It's wednesday, my dudes"); break; case "Thursday": Console.WriteLine("Heh"); break; case "Friday": Console.WriteLine("Party"); break; case "Saturday": Console.WriteLine("Party!"); break; case "Sunday": Console.WriteLine("Party!!!"); break; default: Console.WriteLine("???"); break; } //Но только если у вас на проекте так можно //и вся команда это одобрила на код-ревью
#Моя память сыграла со мной злую шутку #Оказывается, оператор выбора в его классическом виде #Добавили в python вот прям щас #Гвидо Ван Россум, видно, в своё время решил #Раз уж нам пришлось ввести elif, то его и хватит #Кстати, НИКОГДА не пренебрегайте никакими возможностями #Сделать вашу программу понятнее. Даже если это порядок ветвей match day: case "Tuesday": print("Meh") case "Wednesday": print("It's wednesday, my dudes") case "Thursday": print("Heh") case "Friday": print("Party") case "Saturday": print("Party!") case "Sunday": print("Party!!!") case "Monday": print("Kill me, please") case default: print("???")

Резюмируем. Оператор ветвления нам нужен, чтобы в какой-то поворотный момент принять решение, что делать дальше. Для случаев, когда параметр для принятия решения сложнее, чем "да/нет", вводятся операторы ветвления сложнее. Это ок, потому что их можно свести к класическим "if" и они упрощают программы.

Цикл

Сначала классический цикл на python. Просто делаем что-то, пока не сделаем это на все сто процентов. Простая идея.

done_work = 0 while done_work < 100: portion_of_work = do_some_work() done_work += portion_of_work

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

Во многих языках есть штуки типа break, continue и прочих. Итак, ещё одна частая, не слишком удобная ситуация. Пускай, на python.

done_work = 0 something_bad_happened = False while done_work < 100 and not something_bad_happened: portion_of_work, something_bad_happened = do_some_work() done_work += portion_of_work #Ага, в Python можно написать такое. #Представим, что у нас тут больше двух строчек if not something_bad_happened: portion_of_work, something_bad_happened = do_another_work() done_work += portion_of_work if not something_bad_happened: portion_of_work = do_more_work() print("Woo-hoo! We're done!") if something_bad_happened: print("Well, almost done...")

Бывают у нас ситуации, когда мы заранее понимаем, что дальше цикл продолжать смысла нет никакого. Вообще. И вот в таких ситуациях у нас получается не очень удобный код. Для ситуаций вида "мы должны закончить этот цикл прям щас" во многих языках существует оператор break. Он означает "всё, закончили". Цикл прерывается сразу.

done_work = 0 something_bad_happened = False while done_work < 100: portion_of_work, something_bad_happened = do_some_work() done_work += portion_of_work #Ага, в Python можно написать такое. #Представим, что у нас тут больше двух строчек if something_bad_happened: break portion_of_work, something_bad_happened = do_another_work() done_work += portion_of_work if something_bad_happened: break portion_of_work = do_more_work() print("Woo-hoo! We're done!") if something_bad_happened: print("Well, almost done...")

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

Но если break ещё относительно нечастое явление, то вот следующая штука, о которой я хочу рассказать — ваш самый верный друг и товарищ. И это шаблон «итератор»! Вам он, скорее всего, известен, как цикл foreach (он же цикл for в python).

Вернёмся к этим ребятам.

while (checking_now < numbers.Count) { if (numbers[checking_now] > maximum) maximum = numbers[checking_now]; checking_now += 1; }
checking_now = 0 maximum = 0 while checking_now < len(numbers): if numbers[checking_now] > maximum: maximum = numbers[checking_now] checking_now += 1

Так вот, 99 процентов использования цикл именно так и выглядят. "Возьми кучу чисел или ещё чего-нибудь, перебери её по одной штучке и сделай с каждой штучкой из кучки что-нибудь". Когда я говорю "99 процентов" я не шучу. Максимум, преувеличиваю. Пусть 97 процентов, окей. Поэтому под это во всех современных языках появился отдельный тип команды. Встречайте тот же самый цикл, но записанный иначе.

var maximum = 0; foreach (var number in numbers) { if (number > maximum) maximum = number; }
maximum = 0 for number in numbers: if number > maximum: maximum = number

Думаю, теперь видно, что код стал намного проще. Во-первых, исчезло из поля зрения условие. Вам не надо думать, что значит "numbers[checking_now] < numbers.Count". Вы глянули на слово "foreach" и сразу поняли, когда этот цикл кончится. Когда переберём все numbers по одному. Во-вторых, переменная checking_now исчезла из поля зрения. В-третьих, внутри цикла мы работаем с number, не вспоминая о numbers. Работаем с отдельной штучкой без надобности смотреть на всю кучку. number выглядит как-то понятнее, чем numbers[checking_now]. Одним словом, удобненько. И не обязательно речь идёт о числах.

foreach (var potato in potatoes) { if (!IsRotten(potato)) ediblePotato.Add(potato); else rottenPotato.Add(potato); }

Когда это превращается в программу, понятную компьютеру, оно подставит вместо нашего красивого foreach/for обычный цикл while. Сводится к нашим трём кирпичам + делает программы понятнее.

Те, кому в этой жизни мало хардкора, могут почитать очень подробно с задротскими деталями о том, как работает этот цикл практически во всех языках, в легендарной книге "Банды четырёх". Книга называется "Приёмы объектно-ориентированного проектирования. Паттерны проектирования". Авторы: Эрих Гамма, Ричард Хелм, Ральф Джонсон, Джон Влиссидес. Открываете паттерн "итератор" (шаблон "перечислятор", бережём корни русского языка) , и читаете тот раздел. Но это, повторяю, для тех, кто хочет сломать себе мозг о профессиональные детали.

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

И как из этого делать алгоритмы?

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

Первое - требования.

Задайте себе вопрос: А вы чего хотите добиться? Самые страшные и разрушительные ошибки в программирование - это когда вы не поняли, что нужно получить в итоге. И если у вас очень смутное представление о том, что должно получиться в итоге, то ваши шансы составить понятную инструкцию для ЭВМ - нулевые.

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

Второе - псевдокод.

Тут легко. Не можешь написать на python, C# или Javascript? Напиши на русском. Не можешь написать на русском? Што ш, смотри пункт первый. Или обрисуй хотя бы в общих чертах, что именно ЭВМ должна делать.

Почему это упрощает дело? В человеческом мозгу всё плохо с оперативной памятью (правило "5+-2" как раз о том), зато всё хорошо с видеокартой. И вещи, которые обрабатываются глазами, уже не занимают место в оперативке. Так что текст перед глазами с вашими мыслями разгружает ваш мозг от этих самых мыслей. Отсюда следующий совет.

Третье - визуализируй.

Если даже текстом не идёт, нарисуй! Что именно? Всё, что поможет как-то выкристаллизовать решение. Блок-схемы, тракты данных, диаграммы, способов слишком много, чтобы дать хоть чуть-чуть деталей. Люди разные, но в норме на рабочем месте программиста тетрадь и ручка имеются как раз для таких зарисовок. Ладно, дам чуть-чуть примеров:

  • Блок-схема, где нарисованы все команды и стрелочками показано что за чем выполняется
  • "Тракт данных" - можно в общих чертах нарисовать что происходит с данными между "пользователь ввёл" и "пользователю показали результат"
  • Тайм-лайн. Чертите вдоль линии, изображающей время, какая часть программы в какой момент что делает.
  • Диаграммы взаимодействия. Если ваша программа зачем-то лазает в интернет, в базы данных, в файлик на дисках, можно зарисовать куда и зачем оно лазает.

Четвёртое - разделяй и властвуй.

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

Попросить пользователя ввести числа Выбрать из них самое большое Вывести его на экран

Что нам это даёт. Мы можем думать над каждой частью по отдельности. Сначала подумаем над тем, как вводить числа, а потом, когда у нас уже есть числа, можем спокойно подумать, как найти самое большое из них.

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

Как делить программы на части? К сожалению, это искусство, которое осваиваешь с опытом. Да, тут есть что посоветовать, но это "есть что" так объёмно, что об этом можно писать отдельный трёхтомник. Если доберёмся до подпрограмм, обязательно обсудим.

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

N.B. Об этом есть немного в "Совершенном коде" Макконела. А целиком об этом есть небольшая книжка Джона Остерхаута "Philosophy of Software Design". Обе рекомендую прочитать сразу же, как только хоть что-то узнаете об объектах.

Пятое - итерируй.

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

Всякий Agile не просто так набрал популярность. Разработка постоянно связана с переделками. Поэтому всё делается небольшими порциями, чтобы вопрос "а не говно ли я делаю?" никого не застал вас врасплох.

Да, всегда надо спрашивать себя "а не говно ли я делаю?". И, само собой, надо всегда быть готовым к ответу "да". Эта работа, к сожалению, требует высокой самооценки.

В следующей серии, если доживём

В этот раз мы начали разбираться с той частью "алгоритмы + структуры данных", которая про "алгоритмы". В следующий раз попробуем чуть-чуть поговорить про "структуры данных". Про самые простые из них, пока что, даже не доходя до массивов. Там есть о чём рассказать.

Ссылки

Канал на ютубе

Паблик вк

Дискорд-сервер

Иллюстрация нарисована этим художником:

146146
29 комментариев

Как написано в книге Стивена Хоккина - если в книге есть хоть одна формула, то число тех, кто ее прочитает, резко уменьшается. Не думаю, что тут кто-то будет в это вникать, тут читают более легкий контент

3
Ответить

Ну не на Хабр же это тащить =)

9
Ответить

Несмотря на то, что Стивен Хоккинг не писал о том, что "если в книге есть картинки с голыми сиськами, то число тех, кто ее прочитает, резко увеличивается", это именно так ;))

Ответить

К моему сожалению, оператор выбора в C# уродлив Тяжёлое наследство прадедушки C. Границы веток определяются оператором break

a switch expression для кого и pattern matching? давно не уродливо, если следить за развитием языка.

Вот так не красиво разве?

5
Ответить

Ваша правда, запамятовал, красиво. Но это один оператор, а не полноценное ветвление + pattern matching это не то, с чем ты будешь знакомить людей в первую очередь.

Ответить

Класс

4
Ответить

Комментарий недоступен

1
Ответить