четверг, 17 декабря 2020 г.

Какие могут быть сложности после перехода из офиса на удаленку?

Перевели нас из офиса на удаленку (мы тут все программисты и все было очень быстро), поработали мы так полгода и наши менеджеры начали нас спрашивать: какие есть проблемы, что мешает работать?

среда, 25 ноября 2020 г.

Как названия переменных и методов делают сопровождение кода дороже?

    Да легко.

    Например очень запутывает код с такими элементами:


  • Несоответствие названий переменной и метода/свойства, из которого получают значение переменной:

    • var renderRequired = this._isInitializingRequired();

      Не понятно как необходимость 'initializing' может превратиться в необходимость 'render', под этими словами я понимаю совершенно разные алгоритмы/события/состояния/действия и при чтении кода с переменной renderRequired не буду связывать это условие с состоянием 'initializing', а при изучении метода _isInitializingRequired не буду предполагать его использование для алгоритма render.


    • this._isUpdateAllowed() && this._updateDOMComponent(renderRequired);

      Из названия флажка "разрешено обновление" я никогда не подумаю о его связи с операцией "обновить DOM компонент", ведь он влияет на 'update' всего объекта.


    •   endUpdate: function endUpdate() {
          var renderRequired = this._isInitializingRequired();
          this.callBase();
          this._isUpdateAllowed() && this._updateDOMComponent(renderRequired);
        },

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


    •   _updateDOMComponent: function _updateDOMComponent(renderRequired) {
          if (renderRequired) {
            this._renderComponent();
          } else if (this._requireRefresh) {
            this._requireRefresh = false;
            this._refresh();
          }
        },

      Из названия функции '_updateDOMComponent' никак не понять что она может выполнить или операцию 'render', или операцию 'refresh', или совсем ничего не сделать. Длят таких 'условных' операций я часто вижу в названии 'tryXXX' и сразу предполагаю вариант "ничего". 


    • <div class="dx-drawer-panel-content">
        <div id="content">content</div></div>

      Под буквами 'content' я понимаю "внутреннее содержимое" и стиль 'dx-drawer-panel-content' я ожидаю найти на внутреннем элементе, но вместо этого этот стиль накладывается на его родительский элемент.

    • const valueFields = descriptions.values;

      'values' - это массив значений. 'valueFields' - это массив имен (наверное свойства какого-то объекта), из которых будут браться значения. Но обе переменные возвращают одно и то же значение. Такое различие в названиях переменных сильно усложняет понимание алгоритма по коду.

    • const expressionArg = new SummaryCell(...);

      Из букв 'expressionArg' я никогда не догадаюсь что переменная ссылается на объект SummaryCell.


    • return {
          direction: drawer.calcTargetPosition(),
          $panel: $(drawer.content()),
          $content: $(drawer.viewContent()),
      };
      Здесь очень художественное передергивание: position становится direction'ом, content превращается в panel, а content'ом становится viewContent. Автор в этом может и не будет путаться, но наследникам кода придется непросто.

  • Присвоение в переменную значения другого типа:

    •     let isEmpty = item.isEmpty;
          if(isEmpty && isEmpty.length) {
              isEmpty = item.isEmpty.filter(function(isEmpty) { return isEmpty; }).length === isEmpty.length;
          }
      Переменная isEmpty возвращала Array, а стала возвращать Boolean

  • Несоответствие имени переменной/функции и возвращаемого значения:

    •     rowItem.isEmpty = [];
      От переменной/свойства с именем 'isEmpty' я ожидаю значение типа Boolean, а не массив.


    •     const cell = expressionArg.cell();
          const value = cell[i] = expression(expressionArg);
      'cell' - это ячейка. Одна ячейка. Ну какой там может быть массив?




    • Метод объекта Drawer называется 'content()' но возвращает элемент с классом 'drawer-panel-content' и в то же время рядом с этим элементом есть другой элемент с классом 'drawer-content', который я и ожидаю получить из метода 'content()'. Прямо наперсточники...




    • Слово 'content' авторы кода используют в двух смыслах: как название для внутренней деталюшки компонента которая содержит клиентский элемент и как название этого клиентского элемента. Такой выбор названия постоянно запутывает, не понятно что именно имеется ввиду в каждом конкретном месте: внутренняя запчасть или клиентский элемент? Обязательно нужно глянуть...

  • Использование '&&' вместо двухстрочных 'if':

    • rowOptions.watch && rowOptions.watch(() => rowOptions.rowIndex)

      Такой вызов метода очень легко пропустить даже когда специально ищешь именно его. А при "беглом проглядывании" алгоритма я очень часто пропускаю вызов в таком оформлении кода.

  • Несогласованность названия функции и реального кода внутри нее:

    •     _disposeDataSource: function() {
              const that = this;
              const dataSource = that._dataSource;

              if(dataSource) {
                  dataSource.off('changed'that._changedHandler);
                  that._dataSource = undefined;
              }
          },
      Буквы 'dispose' подразумевают безвозвратное освобождение/закрытие использованных ресурсов. После такого освобождения ресурсов объект надо создавать заново. Но этот код всего лишь убирает подписку на событие changed, хотя у объекта '_dataSource' есть метод 'dispose'. Это неожиданная реализация метода, которая не понятна из его названия.


вторник, 11 августа 2020 г.

Откуда берется "легкое сопровождение"?

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

вторник, 5 мая 2020 г.

ZeroBugs: "Баги в наших компонентах" или "Проблемы у клиентов в создании их приложений на наших компонентах"

ZeroBugs - очень хорошее правило, если в "баги" попадают именно проблемы клиентов в создании приложений: они не могут двигаться дальше, а замена решения очень дорога, или обходные решения есть, но довольно сложны, а сценарий по нашему мнению будет возникать у многих наших клиентов (например >10) или мы хотели что бы у них в этом сценарии сразу был другой результат. Но это на словах...

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