В моей жизни был период когда я только начинал заниматься программированием. Я тогда думал: «Программировать так просто… Зачем люди специально ходят учиться этому?», но с опытом и образованием пришло понимание, что программирование — дело трудное.

image

То ли программирование — это легко, то ли я просто ничего не понимаю. MemeGenerator.net

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

Кодинг, программирование и стучание по клавишам


Большую часть времени на своей первой работе в сфере технологий я посвящал HTML, CSS и JavaScript. Я делал так, чтобы элементы вели себя тем или иным образом или плел с их помощью визуальные сюжеты. В то время я не думал о себе как о программисте, да и не хотел им тогда становиться. Лишь некоторое время спустя, когда я понял как делать другие вещи в NodeJS, PHP и MySQL, я начал рассматривать себя в этом качестве. Мешая в голове мысли о всем великом, что есть в программировании, я получил свою первую работу с «программистским» названием «инженер-разработчик ПО», в рамках которой я ежедневно и активно решал те или иные задачи.

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

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

Размышляя о данных


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

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

К примеру, реализовать стек на Ruby можно с помощью вот такого простого кода:

class Stack
  # init stack 
  def initialize
    @set = Array.new() 
  end
  # put a new item at the end of the stack 
  def push(x)
    @set.push x
  end
  # get the last item in the stack
  def grab
    @set.pop
  end
  # is the set empty true false bool 
  def empty?
    @set.empty?
  end
end
# implemented stack 
s = Stack.new
s.push 'a' 
s.push 'b'
s.push 'c' 
s.inspect #<Stack:0x48b66454 @set=["a", "b", "c"]> 
puts s.grab # "c" 
puts s.grab # "b" 
puts s.grab # "a" 
s.grab.inspect # nil

С очередями все примерно также в плане типов создаваемых данных. Вдобавок к этому в Ruby есть свой класс для очередей:

# ruby Queue Class 
q = Queue.new
q << 'a' 
q << 'b'
# Tests Examples using Queue 
puts q.length  # prints 2 
puts q.pop # prints a
puts q.length # prints 1 
puts q.pop # prints b 
puts q.length #prints 0

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

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


Удобство сопровождения


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

image

Плохой дизайн порождает спагетти-код. Спагетти код порождает страдания

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

print " <h3> Display Weekdays: </h3> ";
// Looping in a view ... should have been factored diff
foreach($imageRecords["display"] as $ => $displayRecords) {         
     // WTF is this a nested foreach 
     foreach($displayRecords as $value => $dispRecord){
       $tempWeekdayValuesArray = array();
          if($value === "weekdays" && !isnull($dispRecord)) {
             // 3rd nested foreach WTF!
             foreach($dispRecord as $weekday => $weekbool) {
                 // :( condition foreach day ::SHAME::
                 if($weekday == "monday" && $weekbool == 1) {
                    // logic removed 
                  }
              }
              
           }
      }
}

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

Со временем я стал по-настоящему ценить текстовые редакторы и экономию времени, которую они обеспечивают, анализируя потенциальные ошибки в коде по мере его написания. Но, кроме того, я также начал ценить и другие более мелкие, связанные с программирование подробности. Хорошо написанная кодовая база, следующая стандартам документации, четким требованиям и руководству по стилевому оформлению читается также бегло и просто как электронное письмо или интернет-статья (при условии, что иногда используемый язык программирования сам по себе этому способствует). В целом я также понял, что мне очень нравятся многие принципы, описанные в книге Clean Code A Handbook of Agile Software Craftsmanship Роберта Мартина и других авторов.

Разработка посредством тестирования


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

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

Разработка через тестирование помогает мне упорядочить мысли до начала написания методов или объектов. В случаях написания более комплексных фич, она помогает мне разбить ее на минимальный набор элементов, который необходим для ее корректной работы. Часто она напоминает мне о полезности написания псевдо-кода, поскольку текущие тесты рано или поздно теряют свою полезность и нуждаются в изменениях по мере развития самого кода. Однако в целом пограничные случаи есть пограничные случаи: продумывать их заранее во время создания кода гораздо сложнее. В сухом остатке я считаю, что разработка посредством тестирования помогает мне как программисту расти.

image
Поделиться с друзьями
-->

Комментарии (28)


  1. madfly
    27.07.2017 14:57

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


    1. Tenebrius
      27.07.2017 15:16

      Ну, например, я бы сформулировал так:

      Кодинг — умение воплотить алгоритм, используя определенный язык.
      Программирование — умение создать алгоритм.

      Кодить довольно просто — запомнил синтаксис, и вперед.
      Программировать сложнее. Нужно думать не только, как достичь результата, но и сделать это оптимальным образом (зависит от обстоятельств).


      1. Hellsy22
        27.07.2017 15:35
        +1

        А где в вашей схеме находятся:

        1. Умение соблюдать соглашения по коду, комментировать код, коммиты, писать юнит-тесты и т.д.
        2. Умение создавать читаемый код и работать в команде.
        3. Знание типовых проблем и стоимости их решения.
        4. Владение навыками защитного программирования.
        5. Просто широкий кругозор — знания из смежных областей.
        6. Умение пересматривать свой опыт.


      1. madfly
        27.07.2017 17:35
        +1

        Запомнил синтаксис и вперед — вот это как раз и есть джуниор. Опыта набраться шансов пока не было, но начинать с чего-то надо. То, что отдельные личности застревают на этом уровне на всю жизнь, не превращает кодинг в какое-то отдельное направление разработки.
        Между джуниором и действительно высококлассным программистом существует градиент промежуточных стадий. Что дает потенциальную возможность презрительно отзываться о тех, кто находится на более низких уровнях профессионального развития, как о «кодерах». Но это уже не про программирование, а про почесывание самомнения.


    1. boblenin
      27.07.2017 15:50

      Нанимал пачку джуниоров и синьоров — иные синьоры хуже иных джуниоров. Так что это никак не относится к опыту.


      1. madfly
        27.07.2017 16:59

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


        1. boblenin
          27.07.2017 22:09

          Смогли бы вы ответить на вопрос: «Чем список отличается от массива?»


          1. Crafter2012
            28.07.2017 09:51

            Вот никогда не понимал, почему вопросы такого типа являются безусловным маркером уровня программиста. Загуглить ответ — 5 минут, прочесть и понять, ну пусть еще час. При наличии опытного товарища, ответ на вопрос займет 15 минут. И что спрашивается, показывает если соискатель ответил? и что знание ответа на этот вопрос дает? Книжку Кормена прочел два с половиной года назад, за два этих года ну ни разу, кроме как на собеседованиях, это сакральное знание не понадобилось.
            И предвещая вопрос, я примерно мидл в фулстак разработке.


            1. Hellsy22
              28.07.2017 11:06

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


              1. Crafter2012
                28.07.2017 11:16

                Хотел бы я поучится в школе где это школьная программа=) Думаю по снг с пару-тройку десятков будет.
                Но, в принципе, с такой позицией согласен.


            1. boblenin
              28.07.2017 17:09

              Отсутствие ответа на этот вопрос — индикатор того, что знания структур данных у человека нулевые.
              Senior Developer должен иметь представление о том что это такое.

              Наличие ответа — не индикатор ничего. Всего лишь возможность продолжить дискуссию.


            1. alex_zzzz
              28.07.2017 22:02

              > Вот никогда не понимал, почему вопросы такого типа являются безусловным маркером уровня программиста. Загуглить ответ — 5 минут, прочесть и понять, ну пусть еще час. При наличии опытного товарища, ответ на вопрос займет 15 минут.

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


          1. Mikluho
            28.07.2017 14:55

            На каком языке и в каком контексте? :)


            1. boblenin
              28.07.2017 17:09

              Безотносительно языка.


              1. Mikluho
                28.07.2017 17:17

                Как так-то?
                Если вообще… То мне придётся вспомнить то, что изучал более 20 лет назад в чистом виде, без привязки к языку и контексту никогда не использовал. И не уверен, что вспомню что-то похоже на ту правильную формулировку, которую ожидает вопрошающий. Меня такой вопрос на собеседовании напряжёт, и даст понять, что меня тут заранее не уважают.

                Но всё же, мой ответ был бы в духе «список — структура с последовательным доступом, а массив с произвольным», хотя я точно знаю, что в C# внутри List лежит Array…


                1. boblenin
                  28.07.2017 17:21

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

                  Огромное множество кандидатов с 15 или 20 годами опыта вообще не представляют что это такое.


                  1. Mikluho
                    29.07.2017 01:16

                    Ну значит, тут бы повезло :)
                    Но реально, часто задают такие вопросы ожидая ровно одного «правильного» ответа :(


                    1. boblenin
                      31.07.2017 16:31

                      Увы зачастую собеседующие не понимают в чем их задача состоит и используют возможность просто чтобы продемонстрировать свое превосходство. Если от вас ждут одного «правильного» ответа — смотрите по ситуации. Насколько вам нужна работа. И насколько вам нужна именно эта работа.


              1. alex_zzzz
                29.07.2017 00:38

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


                1. Mikluho
                  29.07.2017 01:20

                  А вот тут я бы поспорил…
                  Я не вспомню «чистое» определение, но, насколько я помню, и то и то может иметь динамический размер и разница у них в организации доступа и добавления элементов.
                  В том же курсе, вроде как, рассматриваются очереди и стэки…
                  А ещё можно повспоминать про сложность обращения к элементу и сложность вставки/удаления…
                  А список бывает ещё и связный и кольцевой…
                  Эх, с понимающим кандидатом есть что обсудить ;)


    1. KAW
      29.07.2017 11:57

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


  1. boblenin
    27.07.2017 15:48

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


  1. Mikluho
    28.07.2017 09:51

    Ну вот опять, набежали комментаторы :), которые путают сложность решаемых задач с качеством подхода к работе.
    Если не делать разделение на кодеров и программистов, то да, рулит именно самосознание и самодисциплина… Но профит-то не в том.
    И дело даже не джниорах и сеньорах, ибо деление чаще всего только по опыту и желаемой зарплате.
    Просто у кодера и программиста разные задачи. Если нужно превратить в код тонну более или менее качественного ТЗ — это работа кодера, и программист загнётся со скуки.
    А если в ТЗ преимущественно «сделай мне красиво» :) — то для программиста, ибо кодер просто не будет знать, что делать.


  1. hexploy
    28.07.2017 09:52

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

    Например, если взять определения с вики

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

    Но если человек пишет код плохо и его ненавидят те кто поддерживает код, то тут уже можно посмотреть на определение с лурка...
    Быдлокодер (aka погромист, горе-программист, индус; англ. Code Monkey) — это человек, который считает рекурсию мемом башорга и не знает основных алгоритмов и тонкостей языка, на котором пишет.


    1. wataru
      28.07.2017 14:17

      С этой точки зрения даже и все олипиадники — кодеры.

      Вот тут я с Вами абсолютно не согласен. ТЗ — это не только, что сделать, но и как. Уровень детализации качественно другой. А задачи олимпиадные как раз и расчитаны на то, чтобы придумать, как сделать. В этом вся их суть. Поэтому любой олимпиадник может выполнять работу кодера (но загнется от скуки), но далеко не каждый сможет решить даже простенькую задачку, даже если есть распечатка кода всех алгоритмов и структур данных.


      1. Hellsy22
        28.07.2017 14:28

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


        1. wataru
          28.07.2017 14:33

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


          1. Hellsy22
            29.07.2017 16:20

            Задет или не задет мозг — тоже мнение сугубо субъективное, опирающееся на опыт.

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

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

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

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