Показаны сообщения с ярлыком code. Показать все сообщения
Показаны сообщения с ярлыком code. Показать все сообщения

вторник, 3 декабря 2019 г.

Глобалы

Глобальными модулями в группе разработки продуктов компании ConquestSS называются такие компоненты трёх смежных приложений, код которых равнозначно применим в каждой программе. Например, самостоятельная библиотека OSD.DLL с полноценным интерфейсом и функционалом, интерфейсное окно ABOUT с информацией о продукте, текстовый парсер для сбора данных анализатора кода. Соответственно задачи, которые касаются только таких модулей, а не их внедрения в продукт, называются "глобалами". Для удобства фильтрации такие задачи объединены были в отдельный "продукт в BTS".
SQLDetective, ClearSQL, ClearDB - интерфейсные продукты, написанные в основном на Delphi. Но поскольку была внедрена система LFT, то многие стандартные элементы не могли удовлетворить требования, выработанные этой командой. Поэтому программисты ConquestSS вынуждены были дописывать или переделывать интерфейсные компоненты. Например, для выставления своих фонтов и отступов в ckeck-box, radio-button, list-view, плавное расцвечивание в progress-bar и многое другое. Переработка компонента оформлялась как глобал, а его внедрение в определённый продукт - задачей на конкретное приложение и его модуль. Но в большинстве своём задачи по внедрению в конкретный продукт игнорировались, не оформлялись, подразумевая процесс внедрения в рамках одной задачи-глобала.
Со временем появилась необходимость вести версионность некоторых глобальных модулей. До сих пор сохранилось отображение версии только для анализатора кода. Её номер вы можете увидеть в комментариях к отформатированному коду. Парсер кода - часто меняющийся в последнее время модуль, поскольку обязан поддерживать все новшества базы данных Oracle. Поэтому все три продукта вполне могут выпускаться регулярно, обновляя лишь один глобальный модуль - анализатор кода. А вот версионность другого глобала - OSD.DLL - помогла лишь однажды, когда он кардинально был переработан для работы отладчика. Но, к сожалению, не все старые версии смогли на лету сработаться с библиотекой, поэтому простое копирование файла в рабочую папку приложения не спасало положение, и для полноценной отладки приходилось пересобирать весь продукт с изменённой библиотекой. Не так давно OSD переместили в core продуктов и его версионность отжила свою надобность. У всех остальных модулей-глобалов вообще не велась версионность, достаточно было версий основных продуктов, в которые внедрялись эти глобалы. А при закрытии задач в BTS эти их внутренние версии вообще никогда не имели смысла.
Исходники продуктов, как и положено, хранятся в системе контроля версий (VCS), каждый в своей ветке. Для глобальных модулей была выделена самостоятельная ветка. При этом сборка каждого продукта, автоматизированная со временем, выбирала файлы не только из своей продуктовой ветки, но и мониторила обновления по дате редактирования ветку глобалов. Когда dev-ops реализовал полезняшку (подкинутую мной идею о добавлении комментариев в задачи Jira с номером билда, в который вошёл фикс), то это значительно упростило работу тестировщика, часто сомневавшегося "стоит ли начинать тест? перебилден ли продукт с требуемой версией глобала?". VCS Perforce связана с Jira через FishEye, а сборщик билдов написан на Python, поэтому кроме нотификаций в Slack о готовом билде, dev-ops легко реализовывал и многие другие важные для команды разработки напоминания и уведомления. Да, пока сборка велась в ручном режиме слишком силён был человеческий фактор и часто забывали включить в билд нужную версию глобала, либо ошибались с датами фиксов и накладывали старые баги на новый функционал. И тогда мы получали весьма жуткие временные баги от корявой сборки.
Конечно, такой вынос одинакового кода и интерфейса в отдельную папку VCS был весьма удобен программистам. Ведь у них значительно поубавилось работы. Код не приходилось триплить во все продукты, а лишь сделать одну правку. Но, к сожалению, не всегда задачи в BTS оформлялись на каждый конкретный продукт. Поэтому тестировщику приходилось в каждом из трёх продуктов проводить одни и теже тесты, да ещё удваивать (а то и утраивать) их из-за необходимости поддерживать несколько версий продукта (опубликованный, предыдущий опубликованный, разрабатываемый по спец.заказу или общий будущий). Программист комментировал свои фиксы только в VCS, по которым собирались внутренние Release Notes, то есть единожды. А тестировщик обязан был отметить фиксы в каждом продукте и его версиях. Поэтому пришлось в самописной BTS создать дополнительную таблицу (child для основной таблицы задач)  для таких отметок. Самописную BTS вполне удавалось заполнять в SmartDataset гриде своего же продукта SQLDetective, поскольку в основном это были обычные таблицы с набором справочников. Но для отметок глобалов в SD не сгодилась даже утилита DataDependencyAnalyzer. И после недолгих упрашиваний dev-ops смастерил мне формочку на пару гридов (parent - all_bugs, child - global_checks) со справочником версий продуктов. Да, такой дополнительный список усложнял сбор Release Notes для пользователей, поскольку РМ раньше фильтровал только общую таблицу задач, а теперь ему приходилось частенько припоминать о глобалах.
Когда же самописную BTS сменили на Jira, то систему глобалов не упразднили. Самостоятельный продукт Global Modules (GM) так и продолжил своё существование, но его ни минули пара революций. Команда разработки росла и новым тестировщикам тяжко было как понять систему глобалов, так и поддерживать её в актуальном состоянии. Некоторые модули имели реализацию только в определённых продуктах. Например, CRUD2 матрица или браузерный отчёт анализатора (CS Project Report, CDB Docu), которые формируются сразу для нескольких объектов базы, а потому не приемлемы для единичных объектов в SD. Участились отвлекания старожилов на разъяснения, поскольку даже пояснения к модулям, которое возможно заполнить в справочниках Jira, не отображается для выбираемых компонентов в процессе оформления задачи. Так что моя одноразовая акция по проставлению в комментариях каждого компонента продукта GM списка поддерживаемых продуктов не сильно помогла. Пришлось проводить проверку каждой новой задачи GM на применимость в продуктах и дописывать в Description важные примечания для разработчиков и тестировщиков, если фикс не должен был быть в каком-то из продуктов или его реализация имела продуктовые особенности. Тех.писательница, собиравшая Release Notes, тоже постоянно забывала упомянуть об изменениях за счёт глобалов, либо добавляла лишние пункты, не применимые в продукте, либо текст по опечатке содержал упоминание соседнего продукта. В продукте GM приходилось админу Jira дублировать версии конкретных продуктов после каждой сборки. Тогда ещё не был полноценно дописан авто-билдер, поэтому добавление производилось вручную после публикации, а поскольку не редки были случаи забывчивости, то чек-лист публикации пришлось пополнить отдельным пунктом для админа Jira. Даже РМ, собиравший бэклог публикации в Jira Structure, не всегда вспоминал, что стоит добавить и уже закрытую по другим продуктам GM-задачу, но ещё не внедрённую по текущему спринту. Эти неудобства послужили аргументом к прекращению поддержки GM. Несколько месяцев трёх тестировщиков было потрачено на перенесение имевшихся GM-задач в конкретные продукты. Спасибо, в Jira есть фичи клонирования и переноса задач из одного продукта в соседний, поэтому имевшиеся задачи разносились более менее быстро. А вот новые иногда забывались клонироваться. По окончании этой работы взвыли программисты, которые забывали открыть в Jira слинкованные одноимённые задачи, сменить им статус и отметить затраченное время, забывали в VCS упомянуть авто-фиксы по всем продуктам. Но те проггеры, которые не забывали про лишние телодвижения, были рады резкому скачку их производительности, ведь она утроилась по времени и количеству задач! Итак, тестировщики обрадовались конкретике, тех.писательница успокоилась при сборе Release Notes из-за уменьшения фильтра, но РМ в большей степени прислушивался к мнению программистов, которые ленились отмечать свою работу в клонированных задачах. Из-за этого РМ вопреки мнению большинства своим "царским указом" возобновил поддержку в Jira глобалов. Да притом изменил путь статусов на жёсткую схему, и один статус TESTING был разбит на несколько (сначала три, а потом и четыре) по количеству разрабатываемых продуктов TESTING_Prod1, TESTING_Prod2, TESTING_Prod3, TESTING_Prod4. Статусы можно было сменить только в обозначенном порядке, что очень осложнило работу тестировщикам, которые были закреплены за конкретными продуктами. Но РМ на это неудобство ответил распоряжением самоуправца и закрепил глобалы за одним тестировщиком из числа новичков. Юный тестировщик не возражал, так как не знал, что столкнётся с более сложной проблемой. На тот момент продукт ежедневно собирался при наличии фиксов в своей ветке, а поскольку какие-то из продуктов были "заморожены", то тестировщик не мог закрыть проверенную в продуктах 1 и 4 задачу, не имевшую реализации в продуктах 2 и 3 ввиду отсутствия нужного билда. Dev-ops-у пришлось опять менять авто-билдер, чтобы даже временно отложенные продукты всё равно ежедневно собирались, но лишь для тестирования. И РМ-у было наплевать на то, что некоторым задачам абсолютно не нужно было проходить хоть какую-то проверку в определённых продуктах, то есть авто-билдер гонялся впустую, тестировщик безрезультатно искал исполнения в пустом продукте, а тех.писательница опять стала ошибочно вносить "чужие" фиксы в Release Notes.
Из обеих революций для большинства членов команды разработки был вынесен единый вывод: "Глобалы - это зло!", но поскольку мнение ленивых и приближённых к РМ-у программистов перевешивало демократизм, то о каком бы-то ни было компромиссе мечтать не стоит. Кое-как соглашусь, что в VCS глобалы есть смысл сопровождать в собственной ветке, но и здесь не мало проблем с внутренней и общей версионностью. А в BTS никак не стоит объединять глобалы, поскольку они первые в числе забываемых. Если у вас Jira, то клонирование и перенос задач между продуктами легко снимут с вас проблемы актуализации багов и фич. Кабы в нашей старой самописной BTS была фича клонирования багов и разработок в другие продукты (SmartDataset в SD может дублировать строки только в одной таблице, а значит не давал полноценного клонирования по справочникам, да и не видно было потом линкованного исходника для клонов), то моя идея глобальных модулей ограничилась бы только VCS и в BTS не отразилась.

вторник, 12 февраля 2019 г.

Comments in Loop

Качество продукта начинается с красивых метрик кода. О том, что комментарии к коду только повышают его эффективность, уже говорилось в нескольких моих статьях ("Easy white-box testing", "Качество кода одним числом", "Документор кода или псевдокод"). Хотелось бы их подкрепить результатами исследований. Надеюсь, чарты сильнее убедят ваших программистов вставлять пояснения в код.

Для исследования были взяты две процедуры (с комментариями в цикле cmt_in loop и идентичная без комментариев cmt_no_loop) на PL/SQL Oracle:
  PROCEDURE cmts_in_loop
  IS
    t1 timestamp;
    t2 timestamp;
    l  varchar2(50);
  BEGIN
    t1 := SYSTIMESTAMP;
    FOR i IN 1..1000000 LOOP
      -- 1-st comment line in loop
      l := 'one command line in loop with comments';
      -- 2-nd comment line in loop
    END LOOP;
    t2 := SYSTIMESTAMP;
    dbms_output.put_line('timestamp for mln-loop with 2 comments: ' || to_char(t2 - t1, 'MI:SS.FF5'));
  END;
/
  PROCEDURE cmts_no_in_loop
  IS
    t2 timestamp;
    t3 timestamp;
    l  varchar2(50);
  BEGIN
    t2 := SYSTIMESTAMP;
    FOR i IN 1..1000000 LOOP
      l := 'one command line in loop without comments';
    END LOOP;
    t3 := SYSTIMESTAMP;
    dbms_output.put_line('timestamp for mln-loop without comments: ' || to_char(t3 - t2, 'MI:SS.FF5'));
  END;
/


Визуализируем и вычислим метрики кода в специализированном продукте ClearSQL:
Flowchart - cmts_in_loop
Flowchart - cmts_no_loop
По диаграммам Flowchart видно, что в обеих процедурах одинаковое количество узлов и рёбер, то есть наличие или отсутствие комментариев не влияет на цикломатическую сложность.

Измерение метрик кода дали следующие цифры:
 
Различные цифры в разрезе процедур подсвечены мной красным цветом. За счёт наличия строк-комментариев в первой процедуре вырос Maintainability Index - важная величина кода, которая чем выше, тем лучше код (подробные исследования функции смотрите в "Качество кода одним числом").
Да, идентичная программа с комментариями стоит дороже при изготовлении и поддержке, так как вместе с правкой значимых строк необходимо актуализировать и их примечания. Но это только по меркам компании Conquest Software Solutions, которая "с потолка" взяла формулу и коэффициенты для исчисления Technical Dept.
Описание Technical Dept
А теперь ударный аргумент - время на исполнение цикла.
Дельта выполнений первой и второй процедур 26 раз
Собрав результаты от пары дюжин выполнений, на график была выведена разница времени исполнения цикла с комментариями (cmt_in_loop) и времени выполнения аналогичного цикла, но без строк комментариев (cmt_no_loop). Да, по этому небольшому расхождению слегка заметно, что комментарии затягивают цикл. Но эта гипотеза была разрушена уже на второй сотне экспериментов:
Дельта выполнений первой и второй процедур 201 раз
То есть циклы без комментированных строк крутились дольше! Казалось бы - нонсенс, что увеличение строк в цикле убыстряет его ход, но видимо даже компилятору полезнее иметь код с пояснениями, а не только новичку программисту, правящему легаси.

Так что, решающим аргументом для добавления разъяснений в код стоит рассматривать следующее:
- комментарии не загружают текст, а наоборот помогают читать его;
- блок-схемы процедур "с" и "без" комментариев идентичны;
- комментарии никак не влияют на цикломатическую сложность;
- за счёт строк комментариев легко и быстро увеличить MI, то есть улучшить качество;
- комментарии даже в цикле не замедляют исполнение, а ускоряют его.

О том, сколько строк рабочих и вспомогательных оптимально (3/1) должно быть в коде, читайте в статье "Качество кода одним числом". Метрики кода могут показать общее количество и пропорцию строк, а настраиваемые правила для автоматической проверки выявят места с недоработками. В ClearSQL это называется Code Review Rule Editor, с помощью которого можно добавить пользовательские правила и проверять их в том же автоматическом режиме наряду со встроенными (~200штук).
О том, как проще добавлять пояснения в код, читайте в "Документор кода или псевдокод".

пятница, 19 октября 2018 г.

Cheat sheet for Oracle Table

Тест таблицы делится на две части: структура и использование.
Если имеется ТЗ, то структуру можно всего лишь сравнить с ним. Иначе, придётся подключить знания DDL, оценить связанные таблицы и построенные индексы.
Данные в базе Oracle можно редактировать тремя способами: вручную (SQL*Plus, SQL Developer, или ином приложении типа TOAD и SQLDetective), автоматически через триггеры этой таблицы, механически через хранимые подпрограммы и элементы приложения типа Oracle Forms.
Из этого списка формируется и чек-лист по версиям Oracle DB в разрезе DDL, DML и PL/SQL. Сочетание структуры таблицы и её использование в триггерах и хранимых процедурах удобно проверять через Call Tree и ERD диаграммы, CRUD матрицы. Можете воспользоваться утилитами ClearSQL (аудитор кода PL/SQL) и ClearDB (аудитор базы Oracle).
Когда CRUD матрица даст вам список связанных таблиц и хранимых процедур, то чек-лист расширится типами хранимых подпрограмм: standalone procedure, standalone function, package procedure, package function, type object, type procedure, type function, job/sched.job/sched.program. Call Tree диаграммы дадут список триггеров и синонимов, особенно полезных для выявления мутаций данных. 
К функциональной части тестирования относится Explain Plan, применённый ко всем DML командам в хранимых подпрограммах, триггерах и модулях приложения.
Безопасность проверяется по привилегиям на таблицу и её части.
В негативные тесты включите команду truncate.

пятница, 29 июня 2018 г.

GDPR - доверяй и проверяй

Возврат к бюрократии или Сотрудник на доверии
(рубрика - Нюх на баги)

Европейское сообщество решилось на усовершенствование охраны данных. Теперь тестировщикам и сотрудникам отделов тех-поддержки необходимо в срочном порядке совершенствовать свои знания в области юриспруденции.
Начать обучение следует с самого документа - "General Data Protection Regulation (GDPR)".
В большей мере вопрос касается персональных, конфиденциальных данных. А есть ли в них различие? Что об этом думают эксперты? Читайте "Experts on the GDPR #3: What is personal data under the GDPR?".
С технической точки зрения эксперты определили облачные сервисы для защиты данных - "Experts on the GDPR #4. Storing encrypted personal data in the cloud: What is the most secure option?", "EU GDPR: соблюдение требований регуляторов в сфере облачных вычислений".
Какая же ответственность теперь будет у сотрудников техподдержки первого уровня и тестировщиков? Для техподдержки объектом пристального внимания становится информация о кастомерах, которую необходимо дифференцировать по территориальному признаку - индивидуальные данные от покупателей и поставщиков следует хранить и обновлять в рамках GDPR, компаньонов из других стран позволено обслуживать в прежнем режиме, только если они не связаны с европейцами. Было бы проще ко всем применить политику GDPR, но Вы уверены, что иные страны не имеют более жёстких условий? Поэтому техподдержка первого уровня - одно из самых важных звеньев в процессе фильтрации данных. Например, баг от пользователя должен храниться во внутренней системе компании разработки, а все контакты пользователя в независимой базе, вплоть до отдельного сервера. Получается, связующее звено "техподдержка" при этом несёт полную ответственность за линковку данных об исправляемом баге и пересылаемом отчёте пользователю. Тестировщику, оформляющему баг в базу при этом придётся унифицировать проблему, применяя переименование и аггрегацию для сокрытия данных от сторонних глаз. А Ваши базы контрагентов и задач готовы к такой конфиденциальности?
Создавая и тестируя базы данных в программном продукте, выпускаемом Вашей компанией, следует более тщательно контролировать простоту наименований таблиц и полей, связей реляционных баз и доступность их описания. В этом плане хороший пример в OEBS, где таблицы и поля имеют нелогичные наименования, в основном состоящие из цифр, что хорошо запутывает взломщиков. Также должны быть усилены тесты по способам и местам хранения данных - физические носители, облачные сервисы, удалённое управление с ограничением прав доступа и функций. При пересылке данных должны использоваться высоко-защищённые от несанкционированного доступа способы, а пересылаемые данные защифрованы в обязательном порядке. Также не менее важно проверять объём информации, присылаемой с отчётом о баге, чтобы в ней не хранилось что-либо, идентифицирующее пользователя продукта. Объём и содержимое пересылаемых данных необходимо проверять на актуальность, необходимость и достаточность, предотвращать скрытые пересылки (без ведома пользователя) паролей, IP-адресов, списков баз и прав доступа, прочих идентификаторов.
Список ответственных за сохранность данных не ограничивается техподдержкой. Компания, выпускающая десктопный продукт и продающая его через свой сайт, вполне может быть распределённой: например, зарегистрирована компания в США, разработчики и тестировщики фактически раскиданы по России и Украине, маркетологи разъезжают по всему миру, сервера с исходниками и данными пользователей могут быть распределены  по всему миру. Удобнее иметь сервера с исходным кодом и задачами поближе к группе разработки, а сервис продаж в Европе. Но при этом копия базы данных покупателей обязана быть у разработчика в оригинале, а не переименованная, поскольку могут быть проблемы, напрямую зависящие от комбинации исходных данных. Такие моменты прописаны в GDPR как доступ к данным по запросу "Art. 15 GDPR  Right of access by the data subject". О предварительных действиях компании разработки рассказано в "How to prepare for Data Access Requests under GDPR", "GDPR data access portal: Logging into the GDPR data access portal, Making a data access request, The data access request excel template, Making a data deletion request, Making a data change request, Making a consent change request".
Поскольку дело теперь уходит в юридическую область, которая верит только документам, то процесс тестирования и техподдержки становится более бюрократичным. Для чего компания обязана принять внутреннее соглашение и неукоснительно следовать ему. В противном случае, компания подвержена опасности разорения при утере данных пользователем Вашего продукта.

среда, 20 июня 2018 г.

Качество кода одним числом

Maintainability Index – величина качества кода

Качество продукта, согласно ISO-9126, состоит из 6 частей (см. Рис.1 "ISO-9126").
Рис.1 "ISO-9126"
Из этих же шести пунктов (см. Рис.1 "ISO-9126") строится и качество кода, которое можно измерить для любого языка программирования. К сожалению, идеального кода не существует и добиться невозможно, как и КПД-100%.
Одна из простейших метрик – количество параметров, которое рекомендуют не более 7: 5 входящих, 2 на выход. Особое место занимают глобальные переменные, наличие которых усложняет код.
Более сложно качество кода вычисляется по формулам, только одна из которых "цикломатическая сложность" пока принята институтом стандартов. Когда научному миру удастся доказать полезность и значимость остальных формул, тестировщики смогут официально ориентироваться на эти лимиты.
Формула расчёта Maintainability Index была выведена достаточно давно Доном Колеманом, Паулем Оманом и Джеком Хегмейстером. Она имеет несколько вариаций для различных языков программирования. Фактически, польза индекса "ремонтопригодности" не только в оценке готового кода, но по этой величине вполне можно спрогнозировать устойчивость кода с учётом будущих исправлений.
Согласно формулам (см. Рис.2 "Две формулы подсчёта количества багов в юните", где TNOpr – общее количество операторов, TNOpd – общее количество операндов, DNOpr – количество уникальных операторов, DNOpd  – количество уникальных операндов) Мариуса Халстеда, если код состоит хотя бы из одного оператора и операнда, то величина багов в этом коде уже не нулевая.
Рис.2 "Две формулы подсчёта количества багов в юните"
Если оценить обе формулы (см. Рис.2 "Две формулы подсчёта количества багов в юните") через их графики, то очевидно, что количество багов в новом и исправленном коде будет нулевым только в "пустой" подпрограмме.
 
Рис.3 "График и формула подсчёта новых багов"
На рисунке 3 "График и формула подсчёта новых багов" верхняя формула для расчёта прогнозируемых багов минимизирована по количеству операторов (1 шт) и операндов (2 шт). Количество багов смотрим по оси Y, количество операторов и операндов (только целые числа) смотрим по оси X. Поскольку рабочей подпрограммы без операторов и операндов не существует, то по графику убеждаемся, что количество багов резко уходит в бесконечность только при нулевых значениях операторов и операндов [0..1], количество багов растёт плавно (y>0 при x>1). 
 
 Рис.4 "График и формула подсчёта недавних багов"
Минимизировав вторую формулу (см. Рис.2 "Две формулы подсчёта количества багов в юните") для расчёта недавних багов и приняв один оператор на пару операторов, получаем по-сути аналогичный график (см. Рис.4 "График и формула подсчёта недавних багов"), когда количество багов равномерно растёт по оси Y и не может быть отрицательным, так как в рабочем коде должен быть хотя бы один оператор и операнд, то есть значения по оси X рассматриваются только целочисленные, начиная с 1.
Итак, мы убедились, что в любом коде всегда есть баги. А об их серьёзности можно судить по величине Maintainability Index (MI).

Из чего же складывается величина качества кода?
Максимальная формула учитывает значения Сложности Халстеда, Цикломатической Сложности, значимые Строки кода и объём Комментариев:
MI = 171 - 5.2 * ln(HV) - 0.23 * CC - 16.2 * ln (LOC) + 50 * sin(sqrt(2.4 * COM)), где HV – сложность Халстеда, CC – цикломатическая сложность, LOC – количество строк кода, COM – объём комментариев в коде.
Укороченная формула не учитывает объём комментариев:
MI = 171 - 5.2 * ln(HV) - 0.23 * CC - 16.2 * ln (LOC)
Компилируемые языки программирования "не отвлекаются" на комментарии, поэтому для них (например, Си) вполне очевидно использование укороченной формулы. А языки-интерпретаторы (например, SQL) корректнее оценивать по полной формуле, так как комментарии внутри цикла в некоторых языках могут замедлять исполнение программы, поскольку на вычленение незначимых строк тоже нужно время.
Пределы индекса принято рассматривать по следующей таблице (см. Рис.5 "Лимиты Maintainability Index"):
- подпрограмма требует немедленного исправления, если MI упал меньше 65;
- подпрограмму желательно исправить, если MI больше или равен 65, но меньше 85;
- подпрограмма не нуждается в исправлении, если MI равен или больше 85.
Исходя из формулы абсолютное максимальное значение Maintainability Index равно 221 (171-0-0-0+50), но оно не достижимо ни при каком содержимом сорсника.
Рис.5 "Лимиты Maintainability Index"
Об истории лимитов MI можно почитать в статье.

Итак, чем больше индекс, тем лучше код. Рассмотрим способы повышения индекса важности кода.
Более скорый способ увеличения индекса исходя из формулы первой модели "MI = 171 - 5.2 * ln(HV) - 0.23 * CC - 16.2 * ln (LOC) + 50 * sin(sqrt(2.4 * COM))" возможен за счёт увеличения объёма комментариев, так как индекс в формуле – наибольшее положительное число "50". Объём комментариев зависит от функции синуса, которая колеблется в пределах [-1..1]. Но поскольку объём комментариев можно исчислять двумя способами – как процент или долю, а значение синуса может быть и отрицательным, то необходимо выяснить оптимальные пределы комментариев. Для этого рассмотрим график функции "y(x)= 50 * sin(sqrt(2.4 * x))" на отрезках [0..100] (при исчислении комментариев в процентах) и [0..1] (при исчислении комментариев в долях от общего кода).
Рис.6 "График комментариев в процентах"
На графике (см. Рис.6 "График комментариев в процентах"), построенном по формуле "y(x)= 50 * sin(sqrt(2.4 * x))", по оси X имеем процентное соотношение комментариев к строкам кода, а по оси Y – величину для расчёта Maintainability Index. 1-2% или 25-26% или 83-84% комментариев дадут желаемый максимум (y=50), 0% или 4% или 17% или 37% или 66% комментариев абсолютно не влияют на Maintainability Index (y=0), 9% или 50-51% комментариев самым сильным образом (y=-50) отрицательно влияют на индекс ремонтопригодности. При этом MI может стать и отрицательной величиной. 
Рис.7 "График комментариев в долях"
На графике (см. Рис.7 "График комментариев в долях"), построенном по формуле "y(x)= 50 * sin(sqrt(2.4 * x))", по оси X имеем долевое соотношение комментариев к строкам кода, а по оси Y – величину для расчёта Maintainability Index. График показывает, что 3-4 комментированные строки кода из 10 рассматриваемых (или каждая третья) максимально помогают увеличить MI, то есть являются самым полезным соотношением.
Итак, если MI упал ниже 65, то по-быстрому его поднять можно вставкой комментариев в каждую третью строку.
Примечания:
- полезность/качество комментариев не рассчитывается формулой, поэтому не стоит забывать, что просто закомментированный код – это не полезные примечания;
- при добавлении комментариев соответственно увеличится и общее количество строк кода.

Шаг второй по повышению индекса устойчивости подпрограммы – снизить количество строк кода, потому что в формуле "MI = 171 - 5.2 * ln(HV) - 0.23 * CC - 16.2 * ln (LOC)" наибольший отрицательный индекс "16.2" у величины строк. На графике (см. Рис.8 "График и формула строк кода") видно, например, что 4500 строк уменьшат индекс на 136 пунктов из 171 возможного по формуле. Количество строк в подпрограмме определяется по спецсимволам текста, поэтому парсер обмануть не получится обычным размещением команд в одну строку файла. Единственный вариант – оптимизация кода за счёт объединения и выноса идентичных блоков кода в самостоятельные функции, которые будут рассматриваться как отдельные подпрограммы.
Примечания:
- не забывайте, что при этом увеличится количество параметров и скорее всего даже глобальных;
- блок-схемы, flowchart или UML диаграммы помогают вычленить повторяющиеся блоки хода подпрограммы.
 
 Рис.8 "График и формула строк кода"
Если пойти от обратного и принять в формуле MI(<=65) максимальные значения HV(=1000), CC(=10) и комментариев (sin[X]=1), то в одном юните желательно иметь не более 1500 строк (см. Рис.9 "График максимального количества строк кода и формула с учётом комментариев").
 Рис.9 "График максимального количества строк кода и формула с учётом комментариев"
То есть по формуле Maintainability Index с учётом комментариев мы вывели лимит для оптимального количества строк в подпрограмме: LOC<1500 mi="">=65.
Для формулы второй модели (без учёта комментариев) смотрите рисунок 10 "График максимального количества строк кода и формула без учёта комментариев".
 Рис.10 "График максимального количества строк кода и формула без учёта комментариев"
График по оси Y показывает MI, а LOC по оси X. Из чего следует, что в юните без комментариев для стабильно-устойчивого кода нужно иметь менее 50 строк (см. Рис.11 "Увеличенный график максимального количества строк кода для формулы без учёта комментариев").
 
 Рис.11 "Увеличенный график максимального количества строк кода для формулы без учёта комментариев"
Об иных подробностях строк кода читайте в статье "Source lines of code".

Третий шаг по повышению MI – это снижение сложности Халстеда из части "5.2 * ln(HV)". Максимальная величина Халстеда – 1000. Исходя из этого на графике (см. Рис.12 "График и формула Halstead Volume в рамках MI") видно, что сложность Халстеда максимально может уменьшить индекс ремонтопригодности на 36 пунктов.
 
 Рис.12 "График и формула Halstead Volume в рамках MI"
Все величины Халстеда рассчитываются по операторам и операндам. Напомню, что в выражении "a+b" оператором является плюс, а операндами – переменные "a" и "b". Длина программы по Халстеду – это сумма всех операторов и всех операндов. Словарь юнита он определил как сумму уникальных операторов и операндов. А помножив длину программы на логарифм словаря, Халстед получил объём подпрограммы (или ещё эту величину называют сложностью Халстеда):
HV = ( TNOpr + TNOpd ) * log2 ( DNOpr + DNOpd ),
где TNOpr – общее количество операторов, TNOpd – общее количество операндов, DNOpr – количество уникальных операторов, DNOpd  – количество уникальных операндов. Более подробно о величинах Халстеда читайте в статье "Halstead complexity measures".
Если принять, что на один оператор приходится два операнда, то график функции HV будет приблизительно, как на рисунке 13 "График и функция сложности Халстеда".
 Рис.13 "График и функция сложности Халстеда"
По оси Y смотрим значение HV, а по оси X выбираем количество операторов. Максимальному значению HV=1000 соответствует 45 операторов, и соответственно около 90 операндов (~ два операнда на один оператор).
Для увеличения MI до 65 и выше надо уменьшать HV, то есть количество операторов и операндов. В коде (см. пример на рисунке 14 "Пример сложных и простых вычислений") можно множество простых операций объединить в одну сложную. Это как в начальной школе по арифметике при имеющемся решении задачи в три-четыре действия выполнить расчёт одним действием.
 Рис.14 "Пример сложных и простых вычислений"
На скриншоте из ClearSQL (см. Рис.15 "Пример упрощения кода по HV, MI") показана разница в значениях HV для сложной "hv_1" и простой "hv_2" подпрограмм.
 Рис.15 "Пример упрощения кода по HV, MI"
Уменьшая количество операторов и операндов в коде снижается сложность Халстеда (HV), и как следствие увеличивается (улучшается) индекс ремонтопригодности (MI).

Четвёртый шаг по улучшению MI – снижение цикломатической сложности.
Томас Дж.Маккейб вывел формулу цикломатической сложности юнита как разность рёбер (edges) и узлов (junctions) с добавлением удвоенного количества компонент связности (coherences):
CC = Edges – Junctions + 2*Coherences
Максимальное значение величины Маккейба утверждено Американским Национальным Институтом Стандартов и Технологий (NIST), равно 10, но последнее время расширяют до 15. Нам тестировщикам это значение говорит о необходимом количестве юнит-тестов. Более подробно о цикломатической сложности читайте в статье "Cyclomatic complexity". Цикломатическая сложность снижает индекс ремонтопригодности максимально на 2-3 пункта, поэтому её рассматриваем в последнюю очередь. График (см. Рис.16 "График и формула цикломатической сложности в рамках MI") показывает часть "0.23 * CC" из формулы MI.
 
 Рис.16 "График и формула цикломатической сложности в рамках MI"
По оси X берём целочисленное значение Cyclomatic Complexity (max=10 or 15), по оси Y видим объём снижения (коэффициент – отрицательная величина "-0.23") MI.
Для улучшения MI нужно уменьшать CC, то есть "выпрямлять" ход программы. Но учтите, что иногда сложные условия (композиция нескольких AND и OR) рассчитывается как одно, то есть уменьшается количество узлов и рёбер, следовательно и само значение CC будет меньше.
Рис.17 "Пример кода цикломатической сложности"
В примере (см. Рис.17 "Пример кода цикломатической сложности") процедура threeinone имеет одно сложное условие (CC=4 или CC=2), а процедура oneinthree – три простых условия (СС=4 всегда).

Итак, для оценки качества кода достаточно вычислить только одну величину – Maintainability Index. В слабом юните исправления следует применять по очереди к комментариям кода, количеству строк, операторов и операндов, узлов и связей хода программы. Элементарных знаний математического анализа и школьного курса информатики достаточно специалисту, решившему тестировать код на любом языке программирования, при этом не углубляясь в синтаксис языка.

Полезные ссылки:
* Качественный анализ программного модуля на основе метрик кода
* Don M. Coleman, Dan Ash, Bruce Lowther, Paul W. Oman. Using Metrics to Evaluate Software System Maintainability. IEEE Computer 27(8), 1994, pp. 44-49.
* Paul Omand and Jack Hagemeister. “Metrics for assessing a software system’s maintainability”. Proceedings International Conference on Software Mainatenance (ICSM), 1992, pp 337-344.
* Paul W. Oman, Jack R. Hagemeister: Construction and testing of polynomials predicting software maintainability. Journal of Systems and Software 24(3), 1994, pp. 251-266.
* The Maintainability Index was introduced at the International Conference on Software Maintenance in 1992
* To date, MI is included in Visual Studio (since 2007), in the recent (2012) JSComplexity and Radon metrics reporters for Javascript and Python, and in older metric tool suites such as verifysoft.
* Think Twice Before Using the Maintainability Index
* P. Oman
* J. Hagemeister


среда, 13 июня 2018 г.

Документор кода или псевдокод

Осенью 2016 года сотрудникам, рекламирующим и распространяющим продукт ClearSQL, мной было предложено позиционировать его не только для разработчиков, но и для тестировщиков. Но пользу утилит аудиторов кода они оценили только недавно, начав серию статей с Псевдокода (https://www.youtube.com/watch?v=pFCAALkJ9RU).
Именно Псевдокод является самым простым и доступным способом оценки полноты и качества кода. Фактически, это комментарии к коду, понятные любому человеку.
Комментарии псевдокода добавляются в основной код со специальными тегами. За счёт этих тегов можно вычленять только комментарии (обычный текст, который можно брать из текста технического задания от аналитика продукта) или композицию комментариев со строками кода. В ClearSQL есть возможность генерить Flowchart (блок-схему, UML диаграмму) по комментариям псевдокода. Нижеследующие скриншоты сняты из редакторов кода, псевдокода и диаграмм приложения ClearSQL 6.9.
Текст кода с комментариями псевдокода:

Диаграмма flowchart кода:

Текст псевдокода:

Диаграмма flowchart по комментариям псевдокода (UML формат, слева-направо, со строками кода):

Если аналитики балуют программистов составлением тех.задания в виде блок-схем, то сравнение UML диаграммы от аналитика с Flowchart по комментариям псевдокода даст моментально объём тех.задания, не покрытого кодом или не продуманного аналитиком. В нижеследующем примере видно, что программист обработал не только граничные значения (есть/нет звонок), но и промежуточный результат (абонент занят).
Блок-схема аналитика (нарисовано вручную в Paint):

Диаграмма flowchart по комментариям псевдокода со строками кода:


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

закомментировать эти строки (можно с тэгами псевдокода)

разбить их на логические куски

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

Наличие комментариев в коде имеет ряд преимуществ:
* из-за текучки кадров следующему программисту будет быстрее и проще разобраться с чужим кодом (легаси);
* maintainability index (уровень качества кода) любого кода достигается больше минимума в 85 за счёт 3/10 комментированных строк (но только если это не временно неиспользуемый код, а именно пояснения к коду = полезные комментарии);
* по комментариям к коду не только легче разобраться с его предназначением, но и можно улучшить свои знания языка программирования;
* наличие комментариев в коде ускоряют восстановление истории задачи и добавляют уверенности при смене или потере VCS и BTS, так как нет смысла искать изменения по системе контроля версий или по баг-трекинговой системе;
* сертификация программного обеспечения подразумевает наличие документации, которую легко и быстро можно вычленить из комментариев псевдокода, а не писать с нуля, как это было в моей практике.

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



понедельник, 11 июня 2018 г.

Call Tree диаграммы в ClearSQL

Подсказки по работе с Call Tree диаграммами в приложении ClearSQL (https://www.sqldev.tech/clearsql)

1. Для любых скриптов проекта, имеющих в коде вызовы объектов базы данных Oracle, ClearSQL генерит диаграммы Call Tree. Главный объект диаграммы выделен цветом по значению опции "main menu / Options / Code Analyzer Options / Diagram Options / Call Tree / Call Tree Colors / Selected subroutine". Объекты в диаграмме сгруппированы по владельцу и опционально по "родительскому" (подпрограммы пакета или объектного типа). Группировка утяжеляет генерацию диаграмм. Объекты по имени и владельцу попадают в диаграммы уникально для всего проекта. На перегенерацию при анализе скрипта не влияют некоторые локальные опции диаграммы, если включена "main menu Options / Preferences / Project Analysis / Carts, Diagrams and Matrices / Keep diagram local settings"? но их смена применяется при перерисовке диаграммы в самом окне диаграммы по кнопке Redraw.

2. Существует два окна с диаграммами Call Tree в интерфейсе – уровень проекта (закладка All Call Trees) и уровня скрипта (закладка Script: Editor and Analyzer Info / Call Trees). В отчёт эти диаграммы попадают "as is" в зависимости от опций интерфейса и отчёта "main menu / Tools / Project Report Assistant". Обе закладки состоят из двух частей – дерево диаграмм и окно просмотра выбранных в дереве диаграмм. Выбор объектов в дереве диаграмм автоматически подсвечивает скрипты в дереве проекта с основным объектом диаграммы.

3. Примечания к титрам видеоролика (https://www.youtube.com/watch?v=7qsJYZQKVbo):

* 3 сек "Call Trees in ClearSQL" - название продукта неполноценно отформатировано (часть Clear должна быть italic-format = ClearSQL);

* 12 сек "Purpose ClearSQL draws subroutine calls and called-by path of PL/SQL code in call tree diagrams." – уровень вложенности вызовов настраивается в "main menu / Options / Code Analyzer Options / Diagram Options / Call Tree / Call Tree Appearance / Call level", по-умолчанию равен 3 в обе стороны. Подписи обращений к объектам данных показаны по-умолчанию опцией "main menu / Options / Code Analyzer Options / Diagram Options / Call Tree / Call Tree Appearance / Show data flow labels";

* 26 сек "Statements  Data flows show how subroutines get data from data objects (table, view) with SELECT statement, and how they put data back with INSERT or UPDATE statements, delete data with DELETE statements." – суб-команды из выражения MERGE тоже попадают в схему как самостоятельные связки, но никакие команды не попадают в диаграмму из строкового значения какой-либо переменной кода и из EXECUTE IMMEDIATE;

* 40 сек "Clicking call tree blocks locates subroutine in the Code Editor, so you have the source code at hand." – навигация из диаграммы в текст кода работает в одностороннем порядке, т.е. из кода в диаграммы навигации не существует, но из дерева диаграмм автоматически подсвечиваются срипты в дереве проекта;

* 45 сек "For example, clicking the CREATETRN function opens the DNTS1 package, where you can see from where the INSERT INTO transactions table flows." – на закладке All Call Trees для демо проекта откройте дерево диаграмм до ноды "Dataset Objects / TRANSACTIONS", при этом в дереве проекта позиционируется скрипт "Package Body.sql", по клику в диаграмме на блоке "CREATETRN" активный курсор из закладки All Call Trees перейдёт в окно "Script: Editor and Analyzer Info / Code Editor" и подсветит первую строку подпрограммы "CreateTRN", в которой имеется первый из вызовов объекта "TRANSACTIONS". Поскольку один и тот же объект в скрипте может вызываться в нескольких местах, то локатор из Call Tree диаграммы в код находится в стадии доработки и частично реализован в ClearDB Documenter (http://www.conquestsoftwaresolutions.com/page/cleardb_screen_shots  - Docu | PL/SQL code in diagrams — Slide 2/4: Call Trees), или например в доке (http://www.conquestsoftwaresolutions.com:8082/docus/), из пакета "HR.DBG_DEMO.PROC1" вызывается процедура "HR.DBG_DEMO.PROC2" и её упоминание в пакете есть на 47 и 55 строках тела пакета;

* 1 мин 3 сек "Clicking the MAKETRANS procedure will help you identify the SELECT statement FROM this table." – следует читать как " Clicking the MAKETRANS block in diagram navigates you to the SELECT statement for this table in code text.";

* 1 мин 15 сек "Legend The diagram legend won't let you forget what all these colorful arrows & boxes mean." – цвета блоков по типам объектов совпадают с настройками, если диаграмма генерилась с включенной группировкой, иначе – блоки вызываемых и вызывающих объектов покрашены в красный и терракотовый цвета, для которых не существует юзерских настроек;

* 1 мин 24 сек "Flexible GUI  Zoom out a complex diagram net to see the overall picture or magnify its separate parts to see the details closer." – зуммер и лупа доступны не только в Call Tree, но и в Flowchart диаграммах. Осторожно: кнопки "Zoom diagram" и "Magnifier" никак не синхронизированы с встроенным списком в нижнем правом углу процентного просмотра html-вьювера. При регенерации диаграмм зуммер сбрасывается в дефолт – 100%;

* 1 мин 37 сек "Flexible GUI  For better usability, turn on the Highlight Elements feature to see the separate data flows and not to get lost in the maize of lines & blocks. Note: Highlight is available in SVG format only!" – формат диаграмм SVG является дефолтным, но сменить можно в "main menu / Options / Code Analyzer Options / Diagram Options / Output Diagram Format" перед генерацией.