Как уменьшить вероятность ошибки

Andrey Karpov

  • Введение
  • Примеры ошибок
  • О других ошибках в Firefox
  • Вернемся к ошибкам в обработчиках ошибок
  • Первая рекомендация
  • Вторая рекомендация
  • Третья рекомендация
  • Четвертая рекомендация
  • Заключение

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

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

Введение

Вначале информация для читателей, которые не знакомы с моими предыдущими заметками. Их можно найти здесь:

  • Заметка N1 [Miranda IM];
  • Заметка N2 [Chromium, Return to Castle Wolfenstein и т.д.];
  • Заметка N3 [Qt SDK].

Как всегда, я буду не абстрактен, а начну с примеров. В этот раз примеры будут взяты из исходного кода Firefox. Я постараюсь продемонстрировать, что даже в качественном и известном приложении с кодом для обработки ошибок, всё обстоит не самым лучшим образом. Дефекты были найдены мной с помощью анализатора PVS-Studio 4.50.

a0078_Firefox_ru/image1.png

Примеры ошибок

Пример N1. Неполноценная проверка целостности таблицы

int  AffixMgr::parse_convtable(..., const char * keyword)
{
  ...
  if (strncmp(piece, keyword, sizeof(keyword)) != 0) {
      HUNSPELL_WARNING(stderr,
                       "error: line %d: table is corruptn",
                       af->getlinenum());
      delete *rl;
      *rl = NULL;
      return 1;
  }
  ...
}

Диагностика PVS-Studio: V579 The strncmp function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument. affixmgr.cpp 3708

Здесь сделана попытка проверить целостность таблицы. К сожалению, эта проверка может сработать, а может и не сработать. Для вычисления длины ключевого слова используют оператор sizeof(), что естественно некорректно. В результате, работоспособность кода зависит от счастливого стечения обстоятельств (длины ключевого слова, размера указателя ‘keyword’ в текущей модели данных).

Пример 2. Неработающая проверка при чтении файла

int PatchFile::LoadSourceFile(FILE* ofile)
{
  ...
  size_t c = fread(rb, 1, r, ofile);
  if (c < 0) {
    LOG(("LoadSourceFile: "
         "error reading destination file: " LOG_S "n",
         mFile));
    return READ_ERROR;
  }
  ...
}

Диагностика PVS-Studio: V547 Expression ‘c < 0’ is always false. Unsigned type value is never < 0. updater.cpp 1179

Это пример, когда код обработки ошибки пишется по принципу «чтобы было». Программист даже не задумался, что собственно он написал, и как это будет работать. Проверка некорректна. Функция fread() возвращает количество прочитанных байт с помощью беззнакового типа. Прототип функции:

size_t fread( 
   void *buffer,
   size_t size,
   size_t count,
   FILE *stream 
);

Естественно, для хранения результата используется переменная ‘c’, имеющая тип size_t. Как следствие, результат проверки (c < 0) всегда ложен.

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

Аналогичную ошибку можно увидеть и в других местах:

V547 Expression ‘c < 0’ is always false. Unsigned type value is never < 0. updater.cpp 2373

V547 Expression ‘c < 0’ is always false. Unsigned type value is never < 0. bspatch.cpp 107

Пример 3. Проверка указателя на NULL уже после его использования

nsresult
nsFrameSelection::MoveCaret(...)
{
  ...
  mShell->FlushPendingNotifications(Flush_Layout);
  if (!mShell) {
    return NS_OK;
  }
  ...
}

Диагностика PVS-Studio: V595 The ‘mShell’ pointer was utilized before it was verified against nullptr. Check lines: 1107, 1109. nsselection.cpp 1107

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

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

Пример 4. Проверка указателя на NULL уже после его использования

CompileStatus
mjit::Compiler::performCompilation(JITScript **jitp)
{
  ...
  JaegerSpew(JSpew_Scripts,
    "successfully compiled (code "%p") (size "%u")n",
    (*jitp)->code.m_code.executableAddress(),
    unsigned((*jitp)->code.m_size));

  if (!*jitp)
      return Compile_Abort;
  ...
}

Диагностика PVS-Studio:V595 The ‘* jitp’ pointer was utilized before it was verified against nullptr. Check lines: 547, 549. compiler.cpp 547

Кстати, использование указателя до проверки — распространенная ошибка. Это ещё один пример на эту тему.

Пример 5. Неполная проверка входных значений

PRBool
nsStyleAnimation::AddWeighted(...)
{
  ...
  if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null ||
      unit[0] == eCSSUnit_Null || unit[0] == eCSSUnit_URL) {
    return PR_FALSE;
  }
  ...
}

Диагностика PVS-Studio: V501 There are identical sub-expressions ‘unit [0] == eCSSUnit_Null’ to the left and to the right of the ‘||’ operator. nsstyleanimation.cpp 1767

Кажется, здесь сразу 2 опечатки. Затрудняюсь сказать, как именно должен выглядеть здесь код, но, наверное, хотели написать так:

if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null ||
    unit[0] == eCSSUnit_URL  || unit[1] == eCSSUnit_URL) {

Из-за опечаток функция может начать обрабатывать некорректные входные значения.

Пример 6. Неполная проверка входных значений

nsresult PresShell::SetResolution(float aXResolution, float
  aYResolution)
{
  if (!(aXResolution > 0.0 && aXResolution > 0.0)) {
    return NS_ERROR_ILLEGAL_VALUE;
  }
  ...
}

Диагностика PVS-Studio: V501 There are identical sub-expressions to the left and to the right of the ‘&&’ operator: aXResolution > 0.0 && aXResolution > 0.0 nspresshell.cpp 5114

А вот ещё один пример неудачной проверки входных параметров. В этот раз из-за опечатки не проверяется значение аргумента aYResolution.

Пример 7. Неразыменованный указатель

nsresult
SVGNumberList::SetValueFromString(const nsAString& aValue)
{
  ...
  const char *token = str.get();
  if (token == '') {
    return NS_ERROR_DOM_SYNTAX_ERR; // nothing between commas
  }
  ...
}

Диагностика PVS-Studio: V528 It is odd that pointer to ‘char’ type is compared with the » value. Probably meant: *token == ». svgnumberlist.cpp 96

Проверка, что между запятыми ничего нет, не работает. Чтобы узнать, пустая строка или нет, можно сравнить первый символ с ». Но здесь с нулем сравнивается не первый символ, а указатель. Этот указатель всегда неравен нулю. Корректная проверка должна была выглядеть так: (*token == »).

Пример 8. Неподходящий тип для хранения индекса

PRBool 
nsIEProfileMigrator::TestForIE7()
{
  ...
  PRUint32 index = ieVersion.FindChar('.', 0);
  if (index < 0)
    return PR_FALSE;
  ...
}

Диагностика PVS-Studio: V547 Expression ‘index < 0’ is always false. Unsigned type value is never < 0. nsieprofilemigrator.cpp 622

Функция не вернёт PR_FALSE, если в строке нет точки и продолжит работать с некорректными данными. Ошибка в том, что для переменной ‘index’ выбран беззнаковый тип данных. Проверка (index < 0) не имеет смысла.

Пример 9. Формирование неправильного сообщения об ошибке

cairo_status_t
_cairo_win32_print_gdi_error (const char *context)
{
  ...
  fwprintf(stderr, L"%s: %S", context, (wchar_t *)lpMsgBuf);
  ...
}

Диагностика PVS-Studio: V576 Incorrect format. Consider checking the third actual argument of the ‘fwprintf’ function. The pointer to string of wchar_t type symbols is expected. cairo-win32-surface.c 129

Даже если ошибка успешно обнаружена, её еще надо суметь правильно обработать. А поскольку обработчики ошибок тоже никто не тестирует, то там можно увидеть много интересного.

Функция _cairo_win32_print_gdi_error() распечатает абракадабру. В качестве третьего аргумента функция fwprintf() ожидает указатель на unicode-строку, а вместо этого получает строку в формате ‘const char *’.

Пример 10. Ошибка записи дампа

bool ExceptionHandler::WriteMinidumpForChild(...)
{
  ...
  DWORD last_suspend_cnt = -1;
  ...
  // this thread may have died already, so not opening
  // the handle is a non-fatal error
  if (NULL != child_thread_handle) {
    if (0 <= (last_suspend_cnt =
                SuspendThread(child_thread_handle))) {
  ...
}

Диагностика PVS-Studio: V547 Expression is always true. Unsigned type value is always >= 0. exception_handler.cc 846

Это другой пример в обработчике ошибок. Здесь некорректно обрабатывается результат, возвращаемый функцией SuspendThread. Переменная last_suspend_cnt имеет тип DWORD, а значит она всегда будет больше или равна 0.

О других ошибках в Firefox

Сделаю небольшое отступление и расскажу о результатах проверки Firefox в целом. Проект качественен, и PVS-Studio выявил мало ошибок. Однако, так как он большой, то в количественном отношении ошибок достаточно много. К сожалению, мне не удалось полноценно изучить отчет, выданный инструментом PVS-Studio. Дело в том, что для Firefox отсутствует файл проекта для Visual Studio. Проект проверялся консольной версией PVS-Studio, вызываемой из make-файла. Открыв отчет в Visual Studio, можно просмотреть все диагностические сообщения. Но раз нет проекта, то Visual Studio не подсказывает, где какие переменные объявлены, не позволяет перейти в место определения макросов и так далее. В результате, анализ неизвестного проекта крайне трудоемок, и я смог изучить только часть сообщений.

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

class nsBaseStatis : public nsStatis {
public:
  ...
  PRUint32 mLWordLen[10]; 
  ...
  nsBaseStatis::nsBaseStatis(...)
  {
    ...
    for(PRUint32 i = 0; i < 20; i++)
       mLWordLen[i] = 0;
    ...
  }
  ...
};

Диагностика PVS-Studio: V557 Array overrun is possible. The value of ‘i’ index could reach 19. detectcharset.cpp 89

Хотя эта и подобные ошибки интересны, они не связаны с темой данной статьи. Поэтому, если интересно, можно посмотреть на некоторые другие ошибки в этом файле: mozilla-test.txt.

Вернемся к ошибкам в обработчиках ошибок

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

Что же с этим делать и какие можно дать рекомендации?

Первая рекомендация

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

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

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

Итак, теперь вы предупреждены. И я уверен, это уже очень хорошо и полезно.

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

Вторая рекомендация

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

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

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

Третья рекомендация

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

Другими словами, при статическом анализе покрытие кода составляет 100%. Достичь такого покрытия кода с помощью других видов тестирования практически нереально. Покрытие кода при юнит-тестах и регрессионном тестировании обычно составляет менее 80%. Оставшиеся 20% протестировать очень сложно. В эти 20% входят большинство обработчиков ошибок и редких ситуаций.

Четвертая рекомендация

Можно попробовать использовать методологию внесения неисправностей. Смысл в том, что ряд функций время от времени начинают возвращать различные коды ошибок, и программа должна корректно их обрабатывать. Например, можно написать свою функцию malloc(), которая время от времени будет возвращать NULL, даже если память ещё есть. Это позволит узнать, как будет вести себя программа, когда память действительно кончится. Аналогично можно поступать с такими функциями, как fopen(), CoCreateInstance(), CreateDC() и так далее.

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

Заключение

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

Присылаем лучшие статьи раз в месяц

Check Miranda IM
Я добрался до кода широко известного клиента мгновенных сообщений Miranda IM. Вместе с различными плагинами это достаточно большой проект, размер которого составляет около 950 тысяч строк кода на C и C++. И, как в любом солидном проекте с историей развития, в нем имеется немалое количество ошибок и опечаток.

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

Для анализа Miranda IM я использовал (да, вы уже угадали) анализатор PVS-Studio 4.14. Код проекта Miranda IM весьма качественен, что подтверждается популярностью этой программы. Я и сам являюсь пользователем этого клиента и не имею к нему претензий в плане качества. Проект собирается в Visual Studio с Warning Level 3 (/W3), а количество комментариев составляет 20% от всего текста программы.

1. Избегайте функции memset, memcpy, ZeroMemory и им аналогичные

Мы начнем с ошибок, возникающих при использовании низкоуровневых функций работы с памятью такими, как memset, memcpy, ZeroMemory и им подобных.

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

1) Обработка больших массивов. То есть там, где оптимизированный алгоритм функции даст выигрыш по сравнению с обработкой элементов в простом цикле.

2) Обработка большого количества маленьких массивов. Также имеет смысл с точки зрения улучшения производительности.

Во всех остальных случаях лучше попробовать обойтись без них. Например, я считаю эти функции излишними в такой программе, как Miranda. Никаких ресурсоёмких алгоритмов или огромных массивов в ней нет. Следовательно, использование функций memset/memcpy проистекает только из удобства написания короткого кода. Однако, эта простота очень обманчива и, сэкономив несколько секунд на написании кода, можно неделями вылавливать нечётко проявляющуюся ошибку порчи памяти. Рассмотрим несколько примеров кода, взятых из проекта Miranda IM.

V512 A call of the ‘memcpy’ function will lead to a buffer overflow or underflow. tabsrmm utils.cpp 1080

typedef struct _textrangew
{
  CHARRANGE chrg;
  LPWSTR lpstrText;
} TEXTRANGEW;

const wchar_t* Utils::extractURLFromRichEdit(...)
{
  ...
  ::CopyMemory(tr.lpstrText, L"mailto:", 7);
  ...
}

Копируем только кусок строки. Ошибка банальна до безобразия, но от этого не перестаёт быть ошибкой. Скорее всего, раньше здесь использовалась строка, состоящая из ‘char’. Затем перешли на Unicode строки, а поменять константу забыли.

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

strncpy(tr.lpstrText, "mailto:", 7);

Тогда при переходе к Unicode строкам, число 7 изменять не надо:

wcsncpy(tr.lpstrText, L"mailto:", 7);

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

V568 It’s odd that the argument of sizeof() operator is the ‘& ImgIndex’ expression. clist_modern modern_extraimage.cpp 302

void ExtraImage_SetAllExtraIcons(HWND hwndList,HANDLE hContact)
{
  ...
  char *(ImgIndex[64]);
  ...
  memset(&ImgIndex,0,sizeof(&ImgIndex));
  ...
}

Здесь хотелось обнулить массив, состоящий из 64-указателей. Но вместо этого мы обнулим только первый элемент. Эта же ошибка, кстати, присутствует ещё раз в другом файле. Скажем спасибо Copy-Paste:

V568 It’s odd that the argument of sizeof() operator is the ‘& ImgIndex’ expression. clist_mw extraimage.c 295

Корректный вариант кода должен выглядеть следующим образом:

memset(&ImgIndex,0,sizeof(ImgIndex));

Кстати, взятие адреса у массива может только дополнительно запутать того, кто читает код. Здесь взятие адреса не имеет никакого эффекта. И код может быть написан так:

memset(ImgIndex,0,sizeof(ImgIndex));

Следующий пример.

V568 It’s odd that the argument of sizeof() operator is the ‘& rowOptTA’ expression. clist_modern modern_rowtemplateopt.cpp 258

static ROWCELL* rowOptTA[100];

void rowOptAddContainer(HWND htree, HTREEITEM hti)
{
  ...
  ZeroMemory(rowOptTA,sizeof(&rowOptTA));
  ...
}

Снова, вместо вычисления размера массива, мы вычисляем размер указателя. Правильным выражением будет «sizeof(rowOptTA)». Для очистки массива я предлагаю следующий вариант такого кода:

const size_t ArraySize = 100;
static ROWCELL* rowOptTA[ArraySize];
...
std::fill(rowOptTA, rowOptTA + ArraySize, nullptr);

Я уже привык, что подобные строки любят размножаться по программе копированием:

V568 It’s odd that the argument of sizeof() operator is the ‘& rowOptTA’ expression. clist_modern modern_rowtemplateopt.cpp 308

V568 It’s odd that the argument of sizeof() operator is the ‘& rowOptTA’ expression. clist_modern modern_rowtemplateopt.cpp 438

Вы думаете, что это всё касательно низкоуровневой работы с масивами? Нет, не всё. Смотрите дальше, бойтесь и бейте по рукам любителей написать memset.

V512 A call of the ‘memset’ function will lead to a buffer overflow or underflow. clist_modern modern_image_array.cpp 59

static BOOL ImageArray_Alloc(LP_IMAGE_ARRAY_DATA iad, int size)
{
  ...
  memset(&iad->nodes[iad->nodes_allocated_size], 
    (size_grow - iad->nodes_allocated_size) *
       sizeof(IMAGE_ARRAY_DATA_NODE),
    0);
  ...
}

В этот раз размер копируемых данных вычислен корректно. Вот только перепутан местами второй и третий аргумент. Как следствие, мы заполняем 0 элементов. Корректный вариант:

memset(&iad->nodes[iad->nodes_allocated_size], 0,
  (size_grow - iad->nodes_allocated_size) *
     sizeof(IMAGE_ARRAY_DATA_NODE));

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

Возникает вопрос, а как же обойтись без memset при работе с такими структурами, как OPENFILENAME:

OPENFILENAME x;
memset(&x, 0, sizeof(x));

Очень просто. Создать обнуленную структуру можно так:

OPENFILENAME x = { 0 };

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

Проблема путаницы между signed и unsigned типами может на первый взгляд показаться надуманной. Но этот вопрос зря недооценивается программистами.

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

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

V547 Expression ‘wParam >= 0’ is always true. Unsigned type value is always >= 0. clist_mw cluiframes.c 3140

В коде программы имеется функция id2pos, которая возвращает значение ‘-1’ в случае ошибки. С этой функцией всё в порядке. В другом месте результат работы функции id2pos используется следующим образом:

typedef UINT_PTR WPARAM; 
static int id2pos(int id);
static int nFramescount=0;

INT_PTR CLUIFrameSetFloat(WPARAM wParam,LPARAM lParam)
{
  ...
  wParam=id2pos(wParam);
  if(wParam>=0&&(int)wParam<nFramescount)
    if (Frames[wParam].floating)
  ...
}

Проблема в том, что переменная wParam имеет беззнаковый тип. Следовательно, условие ‘wParam>=0’ всегда истинно. Если функция id2pos вернет ‘-1’, то условие проверки недопустимых значений не сработает, и мы начнем использовать отрицательный индекс.

Я почти уверен, что вначале был написан следующий код:

if (wParam>=0 && wParam<nFramescount)

Компилятор Visual C++ выдал предупреждение «warning C4018: ‘<‘: signed/unsigned mismatch». Это предупреждение как раз включено на Warning Level 3, с которым и собирается Miranda IM. И в этот момент этому месту было уделено недостаточное внимание. Предупреждение было подавлено явным приведением типа. Но ошибка не исчезла, а только спряталась. Корректным вариантом должен был стать следующий код:

if ((int)wParam>=0 && (int)wParam<nFramescount)

Так что внимание и ещё раз внимание к подобным местам. В Miranda IM я насчитал 33 условия, которые из-за путаницы с signed/unsigned всегда истинны или всегда ложны.

Продолжим. Следующий пример мне особенно нравится. А комментарий, просто прекрасен.

V547 Expression ‘nOldLength < 0’ is always false. Unsigned type value is never < 0. IRC mstring.h 229

void Append( PCXSTR pszSrc, int nLength )
{
  ...
  UINT nOldLength = GetLength();
  if (nOldLength < 0)
  {
    // protects from underflow
    nOldLength = 0;
  }
  ...
}

Думаю, пояснений к этому коду не требуется.

Конечно, в ошибках не всегда виноваты только программисты. Иногда свинью подкладывают и разработчики библиотек (в данном случае WinAPI).

#define SRMSGSET_LIMITNAMESLEN_MIN 0
static INT_PTR CALLBACK DlgProcTabsOptions(...)
{
  ...
  limitLength =
    GetDlgItemInt(hwndDlg, IDC_LIMITNAMESLEN, NULL, TRUE) >=
    SRMSGSET_LIMITNAMESLEN_MIN ?
    GetDlgItemInt(hwndDlg, IDC_LIMITNAMESLEN, NULL, TRUE) :
    SRMSGSET_LIMITNAMESLEN_MIN;
  ...
}

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

Проблема в том, что функция GetDlgItemInt() возвращает вовсе не ‘int’, как ожидал программист. Эта функция возвращает UINT. Вот её прототип из файла «WinUser.h»:

WINUSERAPI
UINT
WINAPI
GetDlgItemInt(
    __in HWND hDlg,
    __in int nIDDlgItem,
    __out_opt BOOL *lpTranslated,
    __in BOOL bSigned);

В результате PVS-Studio выдает сообщение:

V547 Expression is always true. Unsigned type value is always >= 0. scriver msgoptions.c 458

И это действительно так. Выражение «GetDlgItemInt(hwndDlg, IDC_LIMITNAMESLEN, NULL, TRUE) >= SRMSGSET_LIMITNAMESLEN_MIN» всегда истинно.

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

3. Избегайте большого количества вычислений в одной строке

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

Чаще всего ошибки возникают там, где программист, с целью создать компактный код, собирает в одну строку сразу несколько действий. При незначительном выигрыше в изящности он существенно увеличивает риск опечатки или того, что не учтёт побочные действия. Рассмотрим пример:

V567 Undefined behavior. The ‘s’ variable is modified while being used twice between sequence points. msn ezxml.c 371

short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len)
{
  ...
  while (*(n = ++s + strspn(s, EZXML_WS)) && *n != '>') {
  ...
}

Здесь возникает неопределенное поведение (undefined behavior). Этот код может корректно функционировать в течение долгого периода жизни программы. Но нет никакой гарантии, что он также будет вести себя после смены версии компилятора или ключей оптимизации. Компилятор в праве вначале вычислить ‘++s’, а затем взывать функцию ‘strspn(s, EZXML_WS)’. Или, наоборот, вначале он может вызвать функцию, а уже затем увеличить значение переменной ‘s’.

Приведу другой пример, почему не стоит пытаться собрать всё в одну строку. В Miranda IM некоторые ветви исполнения программы отключены/включены с помощью вставок вида ‘&& 0’. Примеры:

if ((1 || altDraw) && ...
if (g_CluiData.bCurrentAlpha==GoalAlpha &&0)
if(checkboxWidth && (subindex==-1 ||1)) {

С приведенными сравнениями всё ясно и они хорошо заметны. А теперь представьте, что вы встречаете фрагмент показанный ниже. Код я отформатировал. В программе это ОДНА строка.

V560 A part of conditional expression is always false: 0. clist_modern modern_clui.cpp 2979

LRESULT CLUI::OnDrawItem( UINT msg, WPARAM wParam, LPARAM lParam )
{
  ...
  DrawState(dis->hDC,NULL,NULL,(LPARAM)hIcon,0,
    dis->rcItem.right+dis->rcItem.left-
    GetSystemMetrics(SM_CXSMICON))/2+dx,
    (dis->rcItem.bottom+dis->rcItem.top-
    GetSystemMetrics(SM_CYSMICON))/2+dx,
    0,0,
    DST_ICON|
    (dis->itemState&ODS_INACTIVE&&FALSE?DSS_DISABLED:DSS_NORMAL));
   ...
}

Если здесь нет ошибки, то всё равно непросто вспомнить и найти в этой строке слово FALSE. Вы его нашли? Согласитесь — непростая задача. А если это ошибка? Тогда вообще нет шансов найти её, просто просматривая код. Подобные выражения очень полезно выносить отдельно. Пример:

UINT uFlags = DST_ICON;
uFlags |= dis->itemState & ODS_INACTIVE && FALSE ?
            DSS_DISABLED : DSS_NORMAL;

А я сам, пожалуй, написал бы это длинным, но более понятным способом:

UINT uFlags;
if (dis->itemState & ODS_INACTIVE && (((FALSE))))
  uFlags = DST_ICON | DSS_DISABLED;
else 
  uFlags = DST_ICON | DSS_NORMAL;

Да, это длиннее, но зато легко читается, а слово FALSE лучше заметно.

4. Выравнивайте в коде всё, что возможно

Выравнивание кода уменьшает вероятность допустить опечатку или ошибки при Copy-Paste. Если ошибка все же будет сделана, то найти её в процессе обзора кода будет в несколько раз проще. Рассмотрим пример кода.

V537 Consider reviewing the correctness of ‘maxX’ item’s usage. clist_modern modern_skinengine.cpp 2898

static BOOL ske_DrawTextEffect(...)
{
  ...
  minX=max(0,minX+mcLeftStart-2);
  minY=max(0,minY+mcTopStart-2);
  maxX=min((int)width,maxX+mcRightEnd-1);
  maxY=min((int)height,maxX+mcBottomEnd-1);
  ...
}

Монолитный фрагмент кода, читать который совершенно не интересно. Отформатируем его:

minX = max(0,           minX + mcLeftStart - 2);
minY = max(0,           minY + mcTopStart  - 2);
maxX = min((int)width,  maxX + mcRightEnd  - 1);
maxY = min((int)height, maxX + mcBottomEnd - 1);

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

Мою рекомендацию по выравниванию не стоит понимать буквально и везде строить столбцы кода. Во-первых, это требует дополнительного времени при написании и правке кода. Во-вторых, это может привести к другим ошибкам. В следующем примере, как раз желание сделать красивый столбик привело к возникновению ошибки в коде Miranda IM.

V536 Be advised that the utilized constant value is represented by an octal form. Oct: 037, Dec: 31. msn msn_mime.cpp 192

static const struct _tag_cpltbl
{
  unsigned cp;
  const char* mimecp;
} cptbl[] =
{
  {   037, "IBM037" },    // IBM EBCDIC US-Canada 
  {   437, "IBM437" },    // OEM United States 
  {   500, "IBM500" },    // IBM EBCDIC International 
  {   708, "ASMO-708" },  // Arabic (ASMO 708) 
  ...
}

Желая сделать красивую колонку чисел, легко увлечься и вписать в начале ‘0’, сделав константу восьмеричной.

Уточняю рекомендацию. Выравнивайте в коде всё, что возможно. Но не выравнивайте числа, дописывая нули.

5. Не размножайте строку более, чем один раз

Копирование строк при программировании неизбежно. Но можно подстраховать себя, не вставляя строку из буфера обмена сразу несколько раз. В большинстве случаев лучше скопировать строку, затем отредактировать. Вновь скопировать и отредактировать. И так далее. Так трудней забыть что-то изменить в строке или изменить её неправильно. Рассмотрим пример кода:

V525 The code containing the collection of similar blocks. Check items ‘1316’, ‘1319’, ‘1318’, ‘1323’, ‘1323’, ‘1317’, ‘1321’ in lines 954, 955, 956, 957, 958, 959, 960. clist_modern modern_clcopts.cpp 954

static INT_PTR CALLBACK DlgProcTrayOpts(...)
{
  ...
  EnableWindow(GetDlgItem(hwndDlg,IDC_PRIMARYSTATUS),TRUE);
  EnableWindow(GetDlgItem(hwndDlg,IDC_CYCLETIMESPIN),FALSE);
  EnableWindow(GetDlgItem(hwndDlg,IDC_CYCLETIME),FALSE);    
  EnableWindow(GetDlgItem(hwndDlg,IDC_ALWAYSPRIMARY),FALSE);
  EnableWindow(GetDlgItem(hwndDlg,IDC_ALWAYSPRIMARY),FALSE);
  EnableWindow(GetDlgItem(hwndDlg,IDC_CYCLE),FALSE);
  EnableWindow(GetDlgItem(hwndDlg,IDC_MULTITRAY),FALSE);
  ...
}

Скорее всего, никакой настоящей ошибки здесь нет. Просто два раза работаем с элементом IDC_ALWAYSPRIMARY. Тем не менее, ошибиться в подобных блоках из скопированных строк весьма легко.

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

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

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

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

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

V560 A part of conditional expression is always true: 0x01000. tabsrmm tools.cpp 1023

#define GC_UNICODE 0x01000

DWORD dwFlags;

UINT CreateGCMenu(...)
{
  ...
  if (iIndex == 1 && si->iType != GCW_SERVER &&
      !(si->dwFlags && GC_UNICODE)) {
  ...
}

Допущена опечатка. Вместо оператора ‘&’ используется оператор ‘&&’. Как здесь подстраховаться при написании кода, я не знаю. Корректный вариант условия:

 (si->dwFlags & GC_UNICODE)

Следующий пример.

V528 It is odd that pointer to ‘char’ type is compared with the » value. Probably meant: *str != ». clist_modern modern_skinbutton.cpp 282

V528 It is odd that pointer to ‘char’ type is compared with the » value. Probably meant: *endstr != ». clist_modern modern_skinbutton.cpp 283

static char *_skipblank(char * str)
{
  char * endstr=str+strlen(str);
  while ((*str==' ' || *str=='t') && str!='') str++;
  while ((*endstr==' ' || *endstr=='t') &&
         endstr!='' && endstr<str)
    endstr--;
  ...
}

В этом коде всего лишь забыты две звездочки ‘*’ для разыменования указателей. Результат может быть фатальным. Этот код предрасположен к access violation. Корректный вариант кода:

while ((*str==' ' || *str=='t') && *str!='') str++;
while ((*endstr==' ' || *endstr=='t') &&
       *endstr!='' && endstr<str)
  endstr--;

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

Следующий пример.

V514 Dividing sizeof a pointer ‘sizeof (text)’ by another value. There is a probability of logical error presence. clist_modern modern_cachefuncs.cpp 567

#define SIZEOF(X) (sizeof(X)/sizeof(X[0]))

int Cache_GetLineText(..., LPTSTR text, int text_size, ...)
{
  ...
  tmi.printDateTime(pdnce->hTimeZone, _T("t"), text, SIZEOF(text), 0);
  ...
}

На первый взгляд все хорошо. В функцию передается текст и его длина, посчитанная с помощью макроса SIZEOF. На самом деле макрос следует назвать COUNT_OF, но не в этом дело. Беда в том, что мы пытаемся посчитать количество символов в указателе. Здесь вычисляется «sizeof(LPTSTR) / sizeof(TCHAR)». Человек такие подозрительные места замечает плохо, а вот компилятор и статический анализатор хорошо. Исправленный вариант кода:

tmi.printDateTime(pdnce->hTimeZone, _T("t"), text, text_size, 0);

Следующий пример

V560 A part of conditional expression is always true: 0x29. icqoscar8 fam_03buddy.cpp 632

void CIcqProto::handleUserOffline(BYTE *buf, WORD wLen)
{
  ...
  else if (wTLVType = 0x29 && wTLVLen == sizeof(DWORD))
  ...
}

Здесь уместна рекомендация писать константу в условии на первом месте. Вот такой код просто не скомпилируется:

if (0x29 = wTLVType && sizeof(DWORD) == wTLVLen)

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

Если программист отказывается от такого стиля сравнений, то ему остается или полагаться на компилятор/анализатор, или рисковать.

Кстати, несмотря на то, что про эту ошибку все знают, она не самая редкая. Ещё три примера из Miranda IM, где анализатор PVS-Studio выдал предупреждение V559:

else if (ft->ft_magic = FT_MAGIC_OSCAR)
if (ret=0) {return (0);}
if (Drawing->type=CLCIT_CONTACT)

Анализ кода позволяет также выявить если и не ошибки, то очень подозрительные места в коде. Например, в Miranda IM указатели используют далеко не только как указатели. Если в одних местах кода такие игры выглядят нормально, то в других пугают. Пример кода, который меня крайне настораживает:

V542 Consider inspecting an odd type cast: ‘char *’ to ‘char’. clist_modern modern_toolbar.cpp 586

static void
sttRegisterToolBarButton(..., char * pszButtonName, ...)
{
  ...
  if ((BYTE)pszButtonName)
    tbb.tbbFlags=TBBF_FLEXSIZESEPARATOR;
  else
    tbb.tbbFlags=TBBF_ISSEPARATOR;
  ...
}

Фактически мы проверяем, что адрес строки не кратен 256. Мне не понятно, что на самом деле хотели написать в условии. Возможно, это даже правильно, но сильно сомнительно.

Анализом кода можно найти немало некорректных условий. Пример:

V501 There are identical sub-expressions ‘user->statusMessage’ to the left and to the right of the ‘&&’ operator. jabber jabber_chat.cpp 214

void CJabberProto::GcLogShowInformation(...)
{
  ...
  if (user->statusMessage && user->statusMessage)
  ...
}

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

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

Статический анализ представляет больший интерес в процессе разработки программы, а не в качестве разовых проверок. Множество ошибок и опечаток находится в процессе тестирования и создания юнит-тестов. Но если часть из этих ошибок можно найти ещё на этапе написания кода, то это будет колоссальный выигрыш времени и сил. Обидно два часа отлаживать программу, чтобы потом заметить лишнюю точку с запятой ‘;’ после оператора ‘for’. Такую ошибку можно часто обезвредить, потратив 10 минут на статический анализ измененных в процессе работы файлов.

Заключение

В этой статье я поделился только некоторыми мыслями по поводу того, как допускать меньше ошибок при программировании на Си++. Зреют и другие мысли, о которых я постараюсь написать в следующих статьях и заметках.

P.S.

Уже стало традицией, что после подобной статьи, кто-то спрашивает, а сообщили ли вы разработчикам программы/библиотеки о найденных ошибках. Заранее отвечу на вопрос, отправили ли мы баг репорт по проекту Miranda IM.

Нет, не отправили. Это слишком ресурсоёмкая задача. В статье показана только малая часть от того, что было найдено. В проекте около ста фрагментов, где стоит поправить код, и более ста, где я просто не знаю, ошибка это или нет. Однако, перевод этой статьи будет отправлен авторам Miranda IM и им будет предложена бесплатная версия анализатора PVS-Studio. Если они проявят интерес, то смогут сами проверить исходный код и исправить то, что сочтут нужным.

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

V523 The ‘then’ statement is equivalent to the ‘else’ statement. scriver msglog.c 695

if ( streamData->isFirst ) {
  if (event->dwFlags & IEEDF_RTL) {
    AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "rtlpar");
  } else {
    AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "ltrpar");
  }
} else {
  if (event->dwFlags & IEEDF_RTL) {
    AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "rtlpar");
  } else {
    AppendToBuffer(&buffer, &bufferEnd, &bufferAlloced, "ltrpar");
  }
}

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

3 основных заблуждения при управлении качеством на предприятии

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

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

3. Потребуется для устранения причин брака не один год. Довольно
распространенное заблуждение – обычно используется для объяснения, почему
проводится системная работа слишком медленно либо не осуществляется вовсе.
Однако практика подтверждает принцип Парето – на 20% проблем приходятся 80%
случаев брака. Устранив самые значимые проблемы, удастся значительно сократить
вероятность производственного брака.

Как избавиться от брака по вине работника на 100%

5 причин брака на предприятии и как с ними бороться

1. Сырье.

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

2. Оборудование

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

3. Технология производства

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

4. Условия работы персонала

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

5. Непрофессионализм и безответственность рабочих

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

Пошаговый алгоритм ликвидации брака на предприятии

Первый шаг. Составить таблицу с указанием всех случаев брака на предприятии.
Для показательной статистики рекомендуем анализ данных минимум за год.

Второй шаг. Объединяем аналогичные причины производственного брака в общую
группу. Благодаря выделению группы схожих причин брака удастся рассчитать число
случаев за период, также потери от них. (см. табл. 2).

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

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

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

В бережливом производстве существует термин пока-ёкэ (poka-yoke, япон. –
защита от ошибок). Данный термин предполагает: чтобы предотвратить
производственный брак в будущем, требуется обеспечение таких условий, когда
физически невозможно повторение брака, чтобы не было у сотрудника возможности
повторной ошибки и пр. До решения проблемы наше руководство нередко обвиняло
подчиненных, ссылаясь на проблему человеческого фактора. Однако
совершенствование производственного процесса позволило кардинально уменьшить
вероятность ошибки на предприятии – меньше начали выполняться операции в уме,
ответственность была делегирована между разными сотрудниками, удалось улучшить
благоприятные условия для работы.

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

Седьмой шаг – организация постоянного процесса повышения качества. Для каждого
сотрудника нужно определить индивидуальные показатели качества. Как правило,
достаточно 1-3 показателей. Затем каждый месяц вызывайте линейных руководителей
и запрашивайте данные по данным показателям. От каждого руководителя требуется
ежемесячный доклад о повышении либо снижении показателей работников, обращая
внимание на лучших сотрудников, освещая планируемая мероприятия на предстоящий
месяц. Руководителем выставляются оценки для своих работников. Также
оценивается и работа линейных руководителей – их вышестоящими начальниками.
Показатели лучших работников следует размещать на видных местах, предусмотреть
поощрения для отличившихся сотрудников.

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

Как снизить брак на предприятии: примеры и рекомендации

Юрий Чинчик, Руководитель службы качества и промышленной безопасности
научно-производственной фирмы «Пакер»

Наша компания специализируется на поставках мелких серий оборудования под
заказ. Среди главных направлений – термическая и механическая (фрезерная,
токарная) обработка деталей и изделий. Для уменьшения процента брака в 2006-м
году у нас начала действовать система «Бриллиант» для фрезеровщиков, токарей и
слесарей-сборщиков – всех цеховых рабочих. Фактически, дефектную деталь
предъявляет сам работник, допустивший просчет.

Ведь почему допускается выпуск брака? Работник пытается скрыть свою ошибку,
чтобы не столкнуться с штрафами. Система «Бриллиант» предполагает.

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

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

3. Межоперационный контроль. Осуществляется он контроллером, сотрудником ОТК.
У нас действует мелкосерийное производство. Чтобы в брак не ушла сразу вся
партия, рабочий должен показать контроллеру первую сделанную деталь – поскольку
именно на ней выше всего вероятность ошибки. В дальнейшем планируем исключить
такую практику проверки, но для этого еще потребуется комплекс подготовительных
работ. Примечательно, когда мы осуществляли опрос по этому вопросу, из 40
работников только двое отметили, что дополнительный контроль в их работе не
нужен.

4. Выдача личного клейма. Для работников, которые всегда сообщают про
допущенную ошибку либо вовсе не допускают брак, предоставляется личное клеймо.
Рабочие в таком случае сами выполняют роль контроллера ОТК, подтверждая
годность изделий своей печатью. Возможны ситуации, когда клеймо изымается у
работника. Основание для предоставления клейма и его лишения, порядок
сопутствующих процедур прописаны в инструкции для сотрудников.

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

Роман Лукьянчиков, Генеральный Директор компании «Московские окна»

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

1. Обновили парк станков. Вместо ручных станков установлены автоматические
производственные линии. Подобные перемены дарят уверенность в стабильном
качестве продукции, снижая нашу зависимость от человеческого фактора. В
частности, в течение последних 5 лет нам удалось сократить уровень отходов при
производстве профиля ПВХ до 4. 2% вместо прежних 7. 5%. Но для оценки
эффективности оборудования недостаточно одного параметра. При модернизации
предприятия стремились также оптимизировать свой персонал, с ростом
автоматизации и производительности труда, сокращая время на обслуживание
станков. Если говорить об окупаемости оборудования только с учетом экономии на
отходах и браке, то выходит около 6 лет.

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

3. Работа с людьми. Достичь идеального результата можно только, если каждый
сотрудник лично заинтересован в улучшении работы. Закрепляется каждый этап
нашего производства за отдельным участком. При выявлении брака еще на стадии
производства, наказаний за него не предусмотрено. Но если продукция с браком
поступает уже самому клиенту, то вычитаем 100% цены товара и расходы на
повторную доставку с участка, который брак допустил. Наказание вводится также
для начальника смены. Действует полностью прозрачная система, поэтому работники
её считают справедливой, следовательно не работают с дефектным материалом,
оперативно реагируя на сбои оборудования – брак им абсолютно не выгоден.

Действует для каждого подразделения суммарный допустимый норматив брака. На
основном производстве он составляет 4. 25%. Уровень неисправимого брака (при
котором для переделки необходимы материальные расходы) составлять должен не
более 0. 35%. На остальные 3. 9% приходится косметический брак, когда выявленные
дефекты можно устранить. Для отдела монтажа допустимый процент брака составляет
2. 04%, для доставки – 1. 58%, замеров – 1. 85%.

Павел Меньшиков, Главный бухгалтер аппарата управления Генерального Директора
компании «Мостотрест», заместитель главного бухгалтера компании «Мостотрест»

На металлургическом предприятии была введена система «Черный ящик» для учета
деятельности производственных цехов. Цель нового проекта заключалась в
сокращении сверхнормативных расходов на производстве. Каждому сотруднику по
новой системе требовалось следование норме — из каждой поступившей на обработку
1 тонны полуфабрикатов выйти должны 0. 94 тонны готовой продукции.
Следовательно, у начальника цеха было право списания отходов только 60 кг. с 1
тонны металла (окалина, угар, обрез).

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

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

Результат. Добиться улучшения ситуации удалось уже в сжатые сроки. Ранее
уровень потерь на одном из цехов составлял свыше 100 килограммов с каждой
тонны. Фактически, завалено всё помещение было бракованной продукцией и
обрезками. В отчете указывался непомерный процент угара – хотя приводилась
достаточно небольшая доля брака. Также постоянно встречались манипуляции с
цифрами – принимались полуфабрикаты по нормативному весу, а сдавались изделия
по фактическому. Новая система предполагала установку весов у обоих выездов,
изменения позволили сократить уровень отходов, который оказался даже меньше
запланированных показателей.

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

Время на прочтение
9 мин

Количество просмотров 1.6K

PVS-Studio vs Firefox
Это уже четвертая заметка, где я хочу поделиться полезными наблюдениями о паттернах ошибок и том, как можно с ними бороться. В этот раз я затрону такую тему, как обработка редких и аварийных ситуаций в программах. Рассматривая множество программ, я пришел к выводу, что код обработки ошибок в Си/Си++ программах — одно из самых ненадежных мест.
К чему приводят такие дефекты? Программа, вместо того, чтобы выдать сообщение «файл X не найден», падает и заставляет пользователя гадать, что он не так делает. Программа для работы с базой данных выводит невразумительное сообщение, вместо того, чтобы сообщить, что неверно заполнено одно из полей. Попробуем сразиться с этой разновидностью ошибок, которые досаждают нашим пользователям.

Введение

Вначале информация для читателей, которые не знакомы с моими предыдущими заметками. Их можно найти здесь:

  • Заметка N1 [Miranda IM];
  • Заметка N2 [Chromium, Return to Castle Wolfenstein и т.д.];
  • Заметка N3 [Qt SDK].

Как всегда я буду не абстрактен, а начну с примеров. В этот раз примеры будут взяты из исходного кода Firefox. Я постараюсь продемонстрировать, что даже в качественном и известном приложении с кодом для обработки ошибок, всё обстоит не самым лучшим образом. Дефекты были найдены мной с помощью анализатора PVS-Studio 4.50.

Примеры ошибок

Пример N1. Неполноценная проверка целостности таблицы

int  AffixMgr::parse_convtable(..., const char * keyword)
{
  ...
  if (strncmp(piece, keyword, sizeof(keyword)) != 0) {
      HUNSPELL_WARNING(stderr,
                       "error: line %d: table is corruptn",
                       af->getlinenum());
      delete *rl;
      *rl = NULL;
      return 1;
  }
  ...
}

Диагностика PVS-Studio: V579 The strncmp function receives the pointer and its size as arguments. It is possibly a mistake. Inspect the third argument. affixmgr.cpp 3708

Здесь сделана попытка проверить целостность таблицы. К сожалению, эта проверка может сработать, а может и не сработать. Для вычисления длины ключевого слова используют оператор sizeof(), что естественно некорректно. В результате, работоспособность кода зависит от счастливого стечения обстоятельств (длины ключевого слова, размера указателя ‘keyword’ в текущей модели данных).

Пример 2. Неработающая проверка при чтении файла

int PatchFile::LoadSourceFile(FILE* ofile)
{
  ...
  size_t c = fread(rb, 1, r, ofile);
  if (c < 0) {
    LOG(("LoadSourceFile: "
         "error reading destination file: " LOG_S "n",
         mFile));
    return READ_ERROR;
  }
  ...
}

Диагностика PVS-Studio: V547 Expression ‘c < 0’ is always false. Unsigned type value is never < 0. updater.cpp 1179

Это пример, когда код обработки ошибки пишется по принципу «чтобы было». Программист даже не задумался, что собственно он написал, и как это будет работать. Проверка некорректна. Функция fread() возвращает количество прочитанных байт с помощью беззнакового типа. Прототип функции:

size_t fread( 
   void *buffer,
   size_t size,
   size_t count,
   FILE *stream 
);

Естественно, для хранения результата используется переменная ‘c’, имеющая тип size_t. Как следствие, результат проверки (c < 0) всегда ложен.

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

Аналогичную ошибку можно увидеть и в других местах:

V547 Expression ‘c < 0’ is always false. Unsigned type value is never < 0. updater.cpp 2373

V547 Expression ‘c < 0’ is always false. Unsigned type value is never < 0. bspatch.cpp 107

Пример 3. Проверка указателя на NULL уже после его использования

nsresult
nsFrameSelection::MoveCaret(...)
{
  ...
  mShell->FlushPendingNotifications(Flush_Layout);
  if (!mShell) {
    return NS_OK;
  }
  ...
}

Диагностика PVS-Studio: V595 The ‘mShell’ pointer was utilized before it was verified against nullptr. Check lines: 1107, 1109. nsselection.cpp 1107

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

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

Пример 4. Проверка указателя на NULL уже после его использования

CompileStatus
mjit::Compiler::performCompilation(JITScript **jitp)
{
  ...
  JaegerSpew(JSpew_Scripts,
    "successfully compiled (code "%p") (size "%u")n",
    (*jitp)->code.m_code.executableAddress(),
    unsigned((*jitp)->code.m_size));

  if (!*jitp)
      return Compile_Abort;
  ...
}

Диагностика PVS-Studio:V595 The ‘* jitp’ pointer was utilized before it was verified against nullptr. Check lines: 547, 549. compiler.cpp 547

Кстати, использование указателя до проверки — распространенная ошибка. Это ещё один пример на эту тему.

Пример 5. Неполная проверка входных значений

PRBool
nsStyleAnimation::AddWeighted(...)
{
  ...
  if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null ||
      unit[0] == eCSSUnit_Null || unit[0] == eCSSUnit_URL) {
    return PR_FALSE;
  }
  ...
}

Диагностика PVS-Studio: V501 There are identical sub-expressions ‘unit [0] == eCSSUnit_Null’ to the left and to the right of the ‘||’ operator. nsstyleanimation.cpp 1767

Кажется, здесь сразу 2 опечатки. Затрудняюсь сказать, как именно должен выглядеть здесь код, но, наверное, хотели написать так:

if (unit[0] == eCSSUnit_Null || unit[1] == eCSSUnit_Null ||
    unit[0] == eCSSUnit_URL  || unit[1] == eCSSUnit_URL) {

Из-за опечаток функция может начать обрабатывать некорректные входные значения.

Пример 6. Неполная проверка входных значений

nsresult PresShell::SetResolution(float aXResolution, float aYResolution)
{
  if (!(aXResolution > 0.0 && aXResolution > 0.0)) {
    return NS_ERROR_ILLEGAL_VALUE;
  }
  ...
}

Диагностика PVS-Studio: V501 There are identical sub-expressions to the left and to the right of the ‘&&’ operator: aXResolution > 0.0 && aXResolution > 0.0 nspresshell.cpp 5114

А вот ещё один пример неудачной проверки входных параметров. В этот раз из-за опечатки не проверяется значение аргумента aYResolution.

Пример 7. Неразыменованный указатель

nsresult
SVGNumberList::SetValueFromString(const nsAString& aValue)
{
  ...
  const char *token = str.get();
  if (token == '') {
    return NS_ERROR_DOM_SYNTAX_ERR; // nothing between commas
  }
  ...
}

Диагностика PVS-Studio: V528 It is odd that pointer to ‘char’ type is compared with the » value. Probably meant: *token == ». svgnumberlist.cpp 96

Проверка, что между запятыми ничего нет, не работает. Чтобы узнать, пустая строка или нет, можно сравнить первый символ с ». Но здесь с нулем сравнивается не первый символ, а указатель. Этот указатель всегда неравен нулю. Корректная проверка должна была выглядеть так: (*token == »).

Пример 8. Неподходящий тип для хранения индекса

PRBool 
nsIEProfileMigrator::TestForIE7()
{
  ...
  PRUint32 index = ieVersion.FindChar('.', 0);
  if (index < 0)
    return PR_FALSE;
  ...
}

Диагностика PVS-Studio: V547 Expression ‘index < 0’ is always false. Unsigned type value is never < 0. nsieprofilemigrator.cpp 622

Функция не вернёт PR_FALSE, если в строке нет точки и продолжит работать с некорректными данными. Ошибка в том, что для переменной ‘index’ выбран беззнаковый тип данных. Проверка (index < 0) не имеет смысла.

Пример 9. Формирование неправильного сообщения об ошибке

cairo_status_t
_cairo_win32_print_gdi_error (const char *context)
{
  ...
  fwprintf(stderr, L"%s: %S", context, (wchar_t *)lpMsgBuf);
  ...
}

Диагностика PVS-Studio: V576 Incorrect format. Consider checking the third actual argument of the ‘fwprintf’ function. The pointer to string of wchar_t type symbols is expected. cairo-win32-surface.c 129

Даже если ошибка успешно обнаружена, её еще надо суметь правильно обработать. А поскольку обработчики ошибок тоже никто не тестирует, то там можно увидеть много интересного.

Функция _cairo_win32_print_gdi_error() распечатает абракадабру. В качестве третьего аргумента функция fwprintf() ожидает указатель на unicode-строку, а вместо этого получает строку в формате ‘const char *’.

Пример 10. Ошибка записи дампа

bool ExceptionHandler::WriteMinidumpForChild(...)
{
  ...
  DWORD last_suspend_cnt = -1;
  ...
  // this thread may have died already, so not opening
  // the handle is a non-fatal error
  if (NULL != child_thread_handle) {
    if (0 <= (last_suspend_cnt =
                SuspendThread(child_thread_handle))) {
  ...
}

Диагностика PVS-Studio: V547 Expression is always true. Unsigned type value is always >= 0. exception_handler.cc 846

Это другой пример в обработчике ошибок. Здесь некорректно обрабатывается результат, возвращаемый функцией SuspendThread. Переменная last_suspend_cnt имеет тип DWORD, а значит она всегда будет больше или равна 0.

О других ошибках в Firefox

Сделаю небольшое отступление и расскажу о результатах проверки Firefox в целом. Проект качественен, и PVS-Studio выявил мало ошибок. Однако, так как он большой, то в количественном отношении ошибок достаточно много. К сожалению, мне не удалось полноценно изучить отчет, выданный инструментом PVS-Studio. Дело в том, что для Firefox отсутствует файл проекта для Visual Studio. Проект проверялся консольной версией PVS-Studio, вызываемой из make-файла. Открыв отчет в Visual Studio, можно просмотреть все диагностические сообщения. Но раз нет проекта, то Visual Studio не подсказывает, где какие переменные объявлены, не позволяет перейти в место определения макросов и так далее. В результате, анализ неизвестного проекта крайне трудоемок, и я смог изучить только часть сообщений.

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

class nsBaseStatis : public nsStatis {
public:
  ...
  PRUint32 mLWordLen[10]; 
  ...
  nsBaseStatis::nsBaseStatis(...)
  {
    ...
    for(PRUint32 i = 0; i < 20; i++)
       mLWordLen[i] = 0;
    ...
  }
  ...
};

Диагностика PVS-Studio: V557 Array overrun is possible. The value of ‘i’ index could reach 19. detectcharset.cpp 89

Хотя эта и подобные ошибки интересны, они не связаны с темой данной статьи. Поэтому, если интересно, можно посмотреть на некоторые другие ошибки в этом файле: mozilla-test.txt.

Вернемся к ошибкам в обработчиках ошибок

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

Что же с этим делать и какие можно дать рекомендации?

Первая рекомендация

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

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

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

Итак, теперь вы предупреждены. И я уверен, это уже очень хорошо и полезно.

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

Вторая рекомендация

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

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

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

Третья рекомендация

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

Другими словами, при статическом анализе покрытие кода составляет 100%. Достичь такого покрытия кода с помощью других видов тестирования практически нереально. Покрытие кода при юнит-тестах и регрессионном тестировании обычно составляет менее 80%. Оставшиеся 20% протестировать очень сложно. В эти 20% входят большинство обработчиков ошибок и редких ситуаций.

Четвертая рекомендация

Можно попробовать использовать методологию внесения неисправностей. Смысл в том, что ряд функций время от времени начинают возвращать различные коды ошибок, и программа должна корректно их обрабатывать. Например, можно написать свою функцию malloc(), которая время от времени будет возвращать NULL, даже если память ещё есть. Это позволит узнать, как будет вести себя программа, когда память действительно кончится. Аналогично можно поступать с такими функциями, как fopen(), CoCreateInstance(), CreateDC() и так далее.

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

Заключение

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

24 августа 2021 г.

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

Какие ошибки в работе?

Ошибки в работе варьируются от технических ошибок до досадных оплошностей, которые включают в себя такие вещи, как:

  • Делать грамматические или орфографические ошибки в презентации или важном электронном письме

  • Случайная отправка личного сообщения не тому получателю в чате или электронной почте

  • Забывание перепроверить цифры, которые оказались неверными во время презентации

  • Двойное бронирование клиентов в вашем календаре

  • Оговорка во время встречи

  • Отсутствие дедлайна для проекта

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

Что делать, если вы допустили ошибку на работе

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

  1. Признайте ошибку.

  2. Принесите извинения.

  3. Найти решение.

  4. Планируйте, что делать в следующий раз.

  5. Создайте позитивную модель работы.

1. Признайте ошибку

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

2. Принесите извинения

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

3. Найдите решение

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

4. Планируйте, что делать в следующий раз

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

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

5. Создайте позитивную модель работы

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

Советы, как снизить вероятность ошибок в работе

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

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

  • Перепроверьте все сообщения и презентации. Чем больше вы привыкнете проверять наличие ошибок, прежде чем нажимать кнопку «Отправить» в чате или электронной почте, или распечатывать документы для прочтения другими на собрании, тем больше вы будете уверены в том, что ваши сообщения безошибочны.

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

  • Просмотрите свою работу. Каждый раз, когда вы завершаете задачу или процесс — особенно работу с высоким приоритетом — проверяйте ее на наличие ошибок. Если возможно, сделайте перерыв в работе над проектом, прежде чем просмотреть его в последний раз. Это поможет вам более успешно выявлять ошибки.

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

  • Устраните отвлекающие факторы. Когда вы работаете над высокоприоритетными задачами, отложите телефон, закройте электронную почту и ненужные браузеры и переведите все рабочие мессенджеры в режим «не беспокоить». Держите под рукой ручку и блокнот, чтобы записывать любые посторонние мысли, которые помогут вам сосредоточиться на задаче.

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

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

Бюллетень науки и практики /Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

ЭКОНОМИЧЕСКИЕ НАУКИ/ECONOMIC SCIENCES

УДК 330+004 https://doi.org/10.33619/2414-2948/49/31

КАК УМЕНЬШИТЬ ВЕРОЯТНОСТЬ ОШИБОК ПРИ ВЫБОРЕ ПРИОРИТЕТНЫХ

НАПРАВЛЕНИЙ СОЦИАЛЬНОГО И ЭКОНОМИЧЕСКОГО РАЗВИТИЯ СТРАНЫ

©Хубаев Г. Н., д-р экон. наук, Ростовский государственный экономический университет,

г. Ростов-на-Дону, Россия, gkhubaev@mail.ru

HOW TO REDUCE THE PROBABILITY OF ERRORS WHEN SELECTING THE PRIORITY DIRECTIONS OF THE SOCIAL AND ECONOMIC DEVELOPMENT OF THE COUNTRY

©Khubaev G., Dr. habil., Rostov State Economic University (RINH), Rostov-on-Don, Russia,

gkhubaev@mail.ru

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

Abstract. An original technique is proposed to reduce the likelihood of errors when choosing priority areas of the country’s social and economic development. Examples of the methodology implementation using the created methods and computer programs are given.

Ключевые слова: методика, вероятность ошибки, приоритетные направления, развитие страны, имитационные модели, автоматизированный синтез, программы для ЭВМ.

Keywords: methodology, probability of error, priority areas, development of the country, simulation models, automated synthesis, computer programs.

Постановка задачи. Как отмечено в Указе Президента РФ №208 от 13 мая 2017 года «О Стратегии экономической безопасности Российской Федерации на период до 2030 года», к «основным вызовам и угрозам экономической безопасности относятся: стремление развитых государств использовать свои преимущества в уровне развития экономики, высоких технологий (в том числе информационных) в качестве инструмента глобальной конкуренции; … изменение структуры мирового спроса на энергоресурсы и структуры их потребления, развитие энергосберегающих технологий и снижение материалоемкости, развитие «зеленых технологий; . уязвимость информационной инфраструктуры финансово-банковской системы; . исчерпание экспортно-сырьевой модели экономического развития, резкое снижение роли традиционных факторов обеспечения экономического роста, связанное с научно-технологическими изменениями; . отсутствие российских несырьевых компаний среди глобальных лидеров мировой экономики; . отставание в области разработки и внедрения новых и перспективных технологий (в том числе технологий цифровой экономики), недостаточный уровень квалификации и ключевых компетенций отечественных специалистов; . ограниченность масштабов российского несырьевого экспорта, связанная с

Бюллетень науки и практики /Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

его низкой конкурентоспособностью …; низкие темпы экономического роста, обусловленные внутренними причинами» (http://www.garant.ru).

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

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

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

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

Предварительные замечания. 1. Почему люди ошибаются. Люди, как известно, очень существенно различаются по своим ключевым компетенциям и творческим, «подаренным природой» способностям.

1.1. Ошибки по объективным причинам. *Люди очень разные по способностям, которыми их наделила природа. О том, насколько велика разница в творческих способностях индивидов покажем на примерах из реальной жизни. Так, из сотен миллионов игроков в шахматы лишь 3-5 человек могут сыграть 20 партий «вслепую» и только один человек в мире (А. А. Алехин) сыграл «вслепую» 32 партии. Причем в зависимости от природных способностей индивида разными будут и затраты времени на освоение нового материала, на получение знаний. Так, в экспериментах в очередной раз подтверждено очень существенное влияние индивидуальных способностей на скорость осознания возможностей практического применения полученных знаний и реальной реализации этих возможностей [1-2]. Оказалось, что при одинаковых внешних условиях и одинаковом исходном уровне знаний теоретических положений, время, достаточное для практического освоения нового учебного материала, имеет существенный разброс, значительную величину правосторонней асимметрии и, зачастую, может быть аппроксимировано альфа-распределением. Позднее подтвердилось, что при одинаковом уровне начальной подготовки и условиях эксперимента с увеличением сложности работы возрастает и величина правосторонней асимметрии распределения затрат времени на выполнение работы.

Бюллетень науки и практики / Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

*Люди очень разные по уровню профессиональной подготовки. С развитием научно-технического прогресса (НТП) все меньшую часть актуальной информации может освоить даже очень ответственный и способный член команды ЛПР. Так, в современных условиях из-за непрерывного ускорения НТП, уменьшения периода удвоения знаний, лавинообразного роста числа публикаций по большинству направлений науки и техники мало кому удается достаточно долго удерживать передовые позиции даже в одной, узкой области знания. Как отмечается в литературе, читая по 8 часов в сутки по 50 страниц в час, можно прочесть лишь ничтожно малую долю издаваемой в мире периодики по физике, математике, информатике, экономике и другим базовым наукам; и в то же время, чтобы разобраться с новой теорией и применить ее на практике даже хорошо подготовленному профессионалу зачастую нужны годы упорного труда.

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

1.2. Ошибки по субъективным причинам. *Люди очень разные по целевым приоритетам, по стойкости к соблазнам, по чертам характера: сангвиники, холерики, …, альтруисты, эгоисты, смелые и боязливые, … «Люди субъективны. Если судья голоден, приговор будет более суровым, а если он сыт и доволен, то приговор будет мягким. Антибиотики врачи прописывают чаще днем, чем утром. Потому что с утра врач еще свеж и полон сил, а днем уже устал и прописывает более жесткое лекарство.» (Даниэль Канеман. Из доклада в Москве 7 октября 2019 г.).

*Люди очень разные по личной заинтересованности, включая разную стойкость к коррупции, лоббированию, разную реакцию на внешнее давление и т. д.

2. Ущерб для населения страны от ошибок ЛПР. Ошибки команды ЛПР — одна из основных причин возникновения угроз для экономики страны.

2.1. Явный, реальный ущерб. Наглядным примером того, к каким негативным последствиям для социально-экономического развития страны могут привести такие ошибки, является отрасль вычислительной техники и информационных технологий. Так, примерно 50 лет назад кто-то по каким-то причинам решил, что страна может вполне обойтись без вложения в развитие этой отрасли достаточного количества бюджетных средств: *в обучение достаточного количества студентов, аспирантов, в переподготовку преподавателей, *в проектирование и разработку достаточного количества вычислительных машин и программного обеспечения высокого потребительского качества, *в стимулирование научной деятельности граждан путем увеличения количества грантов, премий, диссертационных советов (например, в Ленинграде-СПб действовал только один диссертационный совет по специальности «Математические методы и применение вычислительной техники в экономических исследованиях, планировании и управлении народным хозяйством и его отраслями» и лишь несколько таких советов на весь СССР).

И в результате оказалось, что сегодня на мировом рынке практически отсутствуют отечественные разработки в области алгоритмических языков, СУБД, пакетов прикладных

Бюллетень науки и практики / Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

программ для использования в различных предметных областях (причем, всего пять десятилетий назад корреляционные матрицы, корреляционные функции, регрессионные модели, затрачивая «массу» труда, времени и интеллектуальных усилий, приходилось рассчитывать, разрабатывая программы, в отличие от США, в кодах ЭВМ на машинах Минск-1 и Минск-2, соответственно, с 1 кб. и 2 кб. ОП) [3-5]. А ведь в настоящее время «конкурентным преимуществом на мировом рынке обладают государства, отрасли экономики которых основываются на технологиях анализа больших объемов данных. Такие технологии активно используются в России, но они основаны на зарубежных разработках. Отечественные аналоги в настоящее время отсутствуют. Повсеместное внедрение информационных и коммуникационных технологий, в том числе на объектах критической информационной инфраструктуры, усложняет решение задачи по обеспечению защиты интересов граждан и государства в информационной сфере» [6].

2.2. Неявный, предполагаемый ущерб. В мире 200 стран ориентируются на рыночную (или квази-рыночную) экономику, а результаты социально-экономического развития этих стран почему-то разные. Да и скорость появления позитивных изменений в экономике стран мира тоже разная (см. данные ООН и Всемирного банка по КНР, Индии и ряду других стран). Причем, как оказалось, ни климат, ни площадь территории, ни географическая широта почему-то не оказывают существенного влияния на самые главные экономические показатели и результаты.

Можно также предположить, что чем больше разброс в уровне профессионализма и способностях у команды ЛПР, тем заметнее будет разница в уровне жизни людей, которыми управляют такие ЛПР. Действительно, в двух сотнях стран с рыночной экономикой (и даже в разных административно-территориальных образованиях одной страны) доходы на душу населения и средняя величина прироста ВВП на душу населения за 5-10 лет различаются в несколько раз, продолжительность жизни населения — более чем в 1,5 раза, а доля лиц с высшим образованием, уровень образования, относительное количество тяжких преступлений и их раскрываемость, ресурсоемкость проектирования, изготовления и использования одинаковых товаров, производительность общественного труда и т. д. — в десятки раз (!).

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

3. Почему трудно выявить лиц с неординарными профессиональными компетенциями и творческими способностями.

3.1. О профессиональной компетентности. Пусть требуется выявить профессионалов в конкретной области знаний.

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

Действительно, причин для таких предположений множество. Например, на Рисунке, представлены в виде диаграммы Венна объемы знаний, которыми обладают общающиеся между собой индивиды A-E. Легко увидеть, что индивид А вряд ли сомневается в том, что

Бюллетень науки и практики / Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

индивид С, с которым у А много общего, компетентнее, умнее индивида В. В свою очередь В. по тем же причинам будет считать D более компетентным, чем А. Однако все они будут убеждены в том, что Е — весьма ограниченная личность, хотя в действительности последний обладает гораздо большим объемом знаний, чем А, В, С и D вместе взятые [6].

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

Предположим теперь, что организаторы экспертиз, формируя коллектив экспертов с использованием процедуры «взаимных рекомендаций», обратились к А с просьбой указать самого квалифицированного специалиста из тех, кого знает А. Очевидно, что А, В, С или D вряд ли будут рекомендовать в состав коллектива экспертов индивида Е.

Рисунок. Объемы знаний, которыми обладают индивиды A-E.

3.2. О творческих способностях. Не менее трудно выделить и тех, кто обладает творческими способностями: ассоциативным мышлением, умением мысленно «просчитать» последствия принятого решения на много ходов (лет) вперед. Ведь, очевидно, что тот, кто в состоянии мысленно представить 4 шага алгоритма решения задачи, не сможет убедить в правильности, обоснованности своего решения того, кто способен видеть лишь на 2 шага (или хода) вперед (если речь идет, например, о выборе путей развития экономики; при игре в шахматы все обстоит гораздо проще: правоту легко доказать реальной игрой, а ошибка в расчетах не окажет негативного влияния на жизнь других людей).

ВЫВОДЫ из содержания Предварительных замечаний:

1) В современных условиях (при непрерывном ускорении процесса удвоения знаний, почти экспоненциальном росте количества публикаций по результатам научных исследований, росте количества изобретений, патентов и открытий) НИКТО не может избежать ошибок при выборе приоритетных направлений социально-экономического развития страны и, соответственно, при формировании ее бюджета развития.

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

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

4) Как-то не очень хорошо получается: кто-то 50 лет назад всего лишь ошибся в выборе приоритетного направления вложения бюджетных средств, например, в развитие вычислительной техники и информационных технологий, а сегодня вынуждено страдать

Бюллетень науки и практики / Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

население всей страны (!). Ведь именно такой вывод следует из содержания представленного выше фрагмента из Стратегии экономической безопасности РФ (http://www.garant.ru).

Напомним, что согласно Указу Президента РФ №208 от 13 мая 2017 года «О Стратегии экономической безопасности Российской Федерации на период до 2030 года» (http://www.garant.ru), целями и задачами обеспечения экономической безопасности страны являются: «повышение устойчивости экономики к воздействию внешних и внутренних вызовов и угроз; обеспечение экономического роста, … повышение уровня и улучшение качества жизни населения». И есть четкие количественные показатели состояния экономической безопасности: «валовой внутренний продукт на душу населения (по паритету покупательной способности; . доля граждан с денежными доходами ниже величины прожиточного минимума; … децильный коэффициент;».

Но, спрашивается, как добиться осуществления этих актуальных целей и успешно решить поставленные задачи?

Нам представляется, что в современных условиях есть единственный реально осуществимый способ уменьшить вероятность ошибок при выборе приоритетных направлений социального и экономического развития страны и, соответственно, увеличить вероятность ускорения роста экономики, уровня жизни населения [7], развития человеческого потенциала [8] — для этого необходимо сформировать коллектив высокообразованных экспертов-профессионалов (из разных предметных областей) для регулярной подготовки рекомендаций (в помощь ЛПР на верхних уровнях управления) по выбору приоритетных направлений роста экономики.

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

1. Формирование коллектива экспертов для подготовки рекомендаций по составу приоритетных направлений вложения средств бюджета развития (в целях ускорения роста экономики страны)

Коллектив экспертов формируется в 3 этапа. На первом этапе на основании обычно используемых количественных показателей научной компетентности работника вуза и НИИ (количество цитирований, индекс Хирша, количество выполняемых и выполненных в качестве исполнителя и руководителя проектов-грантов РФФИ, Минвуза и других ведущих организаций России и мира, и ряд других показателей) формируется первоначальная исходная совокупность кандидатов в эксперты. Всего более 4-х десятков показателей.

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

На втором этапе для оценки реальной компетентности кандидатов в экспертную группу по конкретной предметной области (генной инженерии, информатике, медицине, биологии, математике, химии, образовании, растениеводстве, в области проектирования или закупки технологий .) и выявления творческих способностей у членов сформированной на первом этапе совокупности кандидатов используется алгоритм классификации ЛПР по уровню профессиональных знаний и творческим способностям [9-10]. С этой целью сначала необходимо выделить среди кандидатов в эксперты профессионалов в рассматриваемых

Бюллетень науки и практики /Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

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

Пояснение 1. В разделе «Предварительные замечания п. 3» мы обратили внимание на то, что в обычном общении трудно, вернее, невозможно выявить самого компетентного профессионала даже в одной предметной области и, тем более, обнаружить профессионала с творческими способностями. Правда, многие годы назад нам случайно удалось обнаружить в процессе поиска подмножества определяющих факторов при построении регрессионных моделей [11], что все члены одной из многочисленных группировок участников опросов (по методу пошагового уточнения ранжирования объектов) не только практически точно предсказали состав определяющих факторов, но даже правильно предвидели ранги Ь-коэффициентов, характеризуемые отношением Ь/оь,- Причем члены этой группировки *не общались друг с другом, *проживали в разных городах и *не знали о том, что они совместно участвуют в опросах. Таким образом, получалось, что какая-то самопроизвольно сформировавшаяся группа специалистов обладает большей компетентностью, чем остальные группы. Но обнаружить, выявить такую группу удалось, к сожалению, только после ретроспективного анализа уже решенной задачи. В дальнейшем в многочисленных экспериментах с участием студентов и слушателей ИПК руководящих работников и специалистов [12-13] мы убедились в том, что при большом количестве участников можно получить подобный неожиданный результат с достаточно высокой вероятностью. При этом тестирование заключалось в решении одинакового набора задач разного уровня сложности из одной предметной области и из разных предметных областей, то есть только тестирование путем решения испытуемым задач разного уровня сложности из разных предметных областей позволяет обнаружить и наиболее знающих специалистов в определенной предметной области, и лиц, обладающих творческими способностями.

Таблица 1.

РЕЗУЛЬТАТЫ ТЕСТИРОВАНИЯ КАНДИДАТОВ В СОСТАВ КОЛЛЕКТИВА ЭКСПЕРТОВ

Кандидат в состав коллектива экспертов Задачи, решенные кандидатами в состав коллектива экспертов (предметная область в)

X1 X2 X X;+1 X;+k Xm

Zi 1 1 1 1 0 1

Z2 0 0 0 1 1 0

Z3 1 1 1 1 0 1

. . . . . . . . . . . . . . . . . . . . .

Zi 0 1 0 0 0 0

. . . . . . . . . . . . . . . . . . . . .

Пусть Z=|Z^|, (1=1, 2, …) — множество кандидатов в состав экспертов, которым с использованием таблицы (или датчика) случайных чисел присвоены идентификаторы Z1. Всем кандидатам в эксперты предложены для решения задачи {х^-}. При этом _ (1, если / — й кандидат в эксперты решил _/ — ю задачу ^ = { 0, если ] — я задача им не решена.

Для каждой из таблиц построены матрицы Р = {р((01)},, С = {д^} (/, к £ 1, п), где

9 Не = + Р^ + ^¿А-1″) — мера подобия Жаккарда. Выделим экспертов и (/, k

(11)

=1, 2,.) и введем следующие обозначения: Р-^ — количество одинаковых задач, решенных

Бюллетень науки и практики /Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

кандидатами и в состав коллектива экспертов, т.е. Рк ) = ^ П 2^| — мощность

пересечения множеств 2^ = {х^} и 2^ = {х^} (/’ £ 1,т;х х^, Хц = 1); Р^0″* — количество

задач, решенных кандидатом в состав экспертов 2и которые не смог решить 2к, т.е. Р(^10) =

|— мощность разности множеств 2^ = {х^} и 2^ = {х^}; Р(°1) — количество задач,

решенных 2^, которые не смог решить 2и т.е. Р(|01) = 12к/ 2^

По матрице G строят графы взаимосвязи между кандидатами в эксперты по составу и сложности решенных задач, а анализ матрицы (Р+Р2) позволяет получить упорядочение кандидатов в эксперты по уровню профессиональной компетентности в выбранной конкретной предметной области.

Замечание 1. На обработку таблицы, содержащей 100 тысяч экспертов и 1000 задач, с использованием программы для ЭВМ, созданной студентами И. А. Ермоловым, А. Р. Загировым и Д. А. Полиевым, и ноутбука с 8 Гб ОП, потребовалось менее 80 мин.

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

В результате тестирования выявляют тех из кандидатов, которые решили или были близки к решению задач, подготовленных для решения специалистами из других предметных областей. Затем выполняется обработка результатов тестирования с вычислением матриц G и (Р+Р2), оценкой взаимосвязи между кандидатами в эксперты по группам решенных задач и упорядочением (ранжированием) кандидатов в состав коллектива экспертов по творческим способностям (исходя из количества и сложности решенных задач из разных предметных областей, непосредственно не связанных с повседневной деятельностью кандидата).

Таблица 2.

РЕЗУЛЬТАТЫ ТЕСТИРОВАНИЯ ВСЕХ КАНДИДАТОВ В СОСТАВ КОЛЛЕКТИВА ЭКСПЕРТОВ ДЛЯ ОЦЕНКИ НАЛИЧИЯ ТВОРЧЕСКИХ СПОСОБНОСТЕЙ

Все кандидаты в состав коллектива экспертов Задачи из разных предметных областей, решенные кандидатами в состав коллектива экспертов (предметные области)

биология информатика технологии

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

Xi X2 X Xj+1 Xj+k Xm

биология

Я 0 0 0 1 1 0

0 0 0

информатика

2т 0 0 0 0 0 1

0 0 0

технологии

£ 1 1 1 1 0 0

0 0

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

Бюллетень науки и практики / Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

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

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

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

В результате обработки Таблиц 1 и 2 сформирован коллектив экспертов для подготовки рекомендаций команде ЛПР по составу приоритетных направлений развития экономики. Однако, как отмечено в Предварительных замечаниях, в связи с ускорением процесса удвоения знаний и лавинообразным ростом количества новых изобретений, открытий, технологий, методов даже коллективу талантливых профессионалов придется затрачивать много времени на поиск перспективных направлений научно-технического прогресса, правильный выбор которых при формировании бюджета развития позволит увеличить вероятность роста экономики страны. В таких условиях для обеспечения продуктивной работы коллектива экспертов целесообразно создание базы данных, содержащей сведения о новых научных результатах исследований и о новых технологиях. Например, создание базы данных «Новости науки и технологий».

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

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

Основываясь на созданных БД, покажем обоснованность и эффективность использования алгоритмов [6, 14-16] применительно к процедуре интуитивно согласованного коллективного выбора ограниченного подмножества приоритетных направлений социально-экономического развития страны из множества возможных вариантов, т. е. на первом этапе необходимо выделить из базы «Новости науки и технологий» ограниченное подмножество перспективных разработок для последующего более глубокого анализа. Предлагаемая последовательность операций процесса такого отбора включает следующие шаги:

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

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

Бюллетень науки и практики /Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

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

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

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

Замечание 2. Если эксперт указал несколько приоритетных направлений, то в этом случае его просят выполнить их упорядочение по степени значимости, полезности, эффективности.

В результате выполнения шага 4 будет сформирована Таблица 3.

Замечание 3. Экспертов, у которых в списках приоритетных направлений оказались выбранные не более, чем 10-15 процентами участвующих в экспертизе просят объяснить, почему выбрано именно это направление, и с объяснениями знакомят всех экспертов, предлагая при желании изменить свои предыдущие ответы.

Таблица 3.

РЕЗУЛЬТАТЫ ЭКСПЕРТИЗЫ ПО ВЫБОРУ ПРИОРИТЕТНЫХ НАПРАВЛЕНИЙ РАЗВИТИЯ ЭКОНОМИКИ

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

Yi Y2 Yj Y+i Y j+k Ym

Z1 1 1 1 1 0 1

Z2 0 0 0 1 1 0

Z3 1 1 1 1 0 1

Z 0 1 0 0 1 0

IY4

Шаг 5. Обработка результатов экспертизы Таблицы 3.

Пусть Z=|Z¿|, 0=1, 2, …) — множество экспертов, которым с использованием таблицы (или датчика) случайных чисел присвоены идентификаторы Zi. Исходная информация представляется в виде таблицы {у^}. При этом

_ ( 1, если / — й эксперт выбрал _/’ — е направление;

= { 0, если ] — е направление отсутствует в списке у I — го эксперта.

Выделим экспертов и (/, к =1, 2,.) и введем следующие обозначения: Р^1″ -количество приоритетных направлений, выбранных одновременно и т.е. Р^1″ = П мощность пересечения множеств = {у„] и = {у^.} (у е 1,ш;у | у„, у„ = 1); Р^0″ — количество приоритетных направлений, выбранных экспертом но отсутствующих в списке т.е. Р^0″ = мощность разности множеств = {у^.} и = {у^}; Р(01) —

количество приоритетных направлений, отсутствующих в списке но выбранных т.е. Р^ =

Бюллетень науки и практики / Bulletin of Science and Practice https://www.bulletennauki.com

Т. 5. №12. 2019 DOI: 10.33619/2414-2948/49

В качестве меры рассогласования между строками и выберем величину =

^(01)/(^(11) + ^¿(1и)), а для оценки степени поглощения экспертом списка приоритетных направлений, выбранных экспертом (степени включения, «вхождения» списка в ) — величину к1к = Р^ДР^ + Р(;0)).

Построим матрицы Р = {р^}^ = G = Я = (i, fc е 1, п), где

^fc

Р^ДР^ + Р(10) + Р(^°1)) — мера подобия Жаккарда.

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

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

Шаг 6. По данным анализа таблицы 3 формируется список возможных приоритетных направлений для дальнейшего исследования.

Шаг 7. Выполняется ранжирование сформированного списка с использованием метода пошагового уточнения ранжирования объектов [14]. Применение этого метода позволяет *корректно осуществлять разбиение (классификацию) экспертов на группы, *повышать точность результатов экспертизы за счет наличия обратной связи при реализации каждого тура, *сохранить преимущества дельфийской процедуры, *находить согласованное с членами каждой группы участников экспертного опроса упорядочение приоритетных направлений, рассчитав точно или приближенно медиану Кемени.

ВЫВОДЫ. 1. Используя рассмотренный алгоритм и разработанные на его основе программные продукты, можно оперативно проводить сравнительный анализ практически неограниченного количества мнений экспертов, корректно и с минимальными трудозатратами осуществлять классификацию (группировку) экспертов.

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

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

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

Для оценки значений перечисленных показателей используется Метод пошагового уточнения значений затрат ресурсов с оценкой характеристик распределения (ПУЗ-ОХР) [19]. Отличие метода заключается, во-первых, в использовании многошаговой процедуры, на каждом шаге которой осуществляется имитационное моделирование, и, во-вторых, в интеграции метода Дельфи с экспертизой, направленной на получение обобщенного мнения группы экспертов о возможном диапазоне значений искомого показателя.

Бюллетень науки и практики / Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

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

Для ответа на поставленные вопросы реализуются следующие операции: Оценки каждого /-го эксперта на j-м шаге ЭЧ- аппроксимируются равномерным (если эксперт указал два значения показателя) или треугольным (если указано три значения) распределениями. Обобщенное коллективное мнение п экспертов об искомом значении показателя определяется как среднее п случайных величин, имеющих равномерное или треугольное распределения путем реализации на каждом к-ом шаге имитационного моделирования функции Э(к)об=(2Э(к)г)/п, (/€п). В качестве инструментальных средств реализации имитационного моделирования используется программный продукт [18], позволяющий с минимальными трудозатратами (в автоматизированном режиме) строить имитационную модель. В результате имитационного моделирования на каждом к-ом шаге получают статистические характеристики (математическое ожидание, дисперсию, коэффициент вариации, эксцесс, асимметрию) и распределение (таблицу и гистограмму) значений показателя — функции Э(к)об=/(Э(к)г). После каждого шага (цикла экспертизы) участников экспертной группы знакомят с объяснениями, представленными в защиту сильно отличающихся оценок значений показателя, и предлагают при желании изменить свои предыдущие ответы. На каждом очередном j-ом шаге оценивают изменение значений коэффициента вариации К(jvar функции Э(/)об. При отклонении коэффициента вариации от предыдущего значения, например, на 5% и менее можно считать, что оценки экспертов стабилизировались и целесообразно завершать экспертизу. На основании результатов имитационного моделирования на последнем шаге оценивают доверительные границы значений показателя и вероятность того, что его значения окажутся больше или меньше определенного числа.

При использовании метода ПУЗ-ОХР можно также определить, как взаимосвязаны ответы участников экспертной группы, какова степень этой взаимосвязи, и влиянием каких факторов объясняется наличие такой взаимосвязи. Задача состоит в том, чтобы выявить группы экспертов, мнения которых о значениях искомого показателя являются достаточно близкими, согласованными. Легко также увидеть группировки экспертов, по мнению которых значения искомого показателя попали в диапазон с вероятностью, не превышающей, например, 0,3; 0,5; 0,7; 0,85 или 0,95.

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

Метод ПУЗ-ОХР может применяться при оценке значений различных показателей — значений спроса на конкретный товар, ущерба от реализации угроз безопасности предприятия, времени выполнения конкретной операции делового процесса, убытков от возможных недружественных санкций конкурентов, времени, затраченного на взлом информационной системы, прогнозируемого времени решения задачи и др. [19-20].

Выводы.

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

Бюллетень науки и практики / Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

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

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

Заключение

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

2. Предложена универсальная методика, позволяющая уменьшить вероятность ошибки при выборе приоритетных направлений социального и экономического развития страны, включающая методы и инструментальные средства формирования коллектива высокообразованных экспертов-профессионалов (из разных предметных областей) для регулярной подготовки рекомендаций (в помощь ЛПР на верхних уровнях управления) по выбору приоритетных направлений роста экономики, в т. ч. методы *для отбора и тестирования кандидатов в эксперты, *для оценки значений: и затрат ресурсов на реализацию каждого направления, и возможной величины временного лага, и эффекта (социального, экономического), *для оценки доверительных границ значений искомого показателя и определения вероятности попадания значений показателей в заданный диапазон.

Статья подготовлена по результатам исследований, выполненных при поддержке Российского фонда фундаментальных исследований (РФФИ) — проект 18-010-00806/18 «Уровень жизни населения административно-территориальных образований: выявление, исследование, анализ и оценка значимости определяющих факторов (для последующей оптимизации в условиях ограниченных ресурсов)»

Источники:

(1). Указ Президента РФ №208 от 13 мая 2017 года «О Стратегии экономической безопасности Российской Федерации на период до 2030 года». URL: http://www.garant.ru

(2). Указ Президента РФ №203 от 9 мая 2017 года «О Стратегии развития информационного общества в Российской Федерации на 2017-2030 годы». URL: http://www.garant.ru

Бюллетень науки и практики / Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

Список литературы:

1. Хубаев Г. Н. О законе распределения времени освоения нового учебного материала // Системный анализ в проектировании и управлении: материалы 6-ой Международной науч.-практ. конференции (СПб., 28 июня — 5 июля 2002 г.). СПб.: СПбГПУ, 2002. С. 431-434.

2. Khubaev G. Assessment of the time required for the acquisition of knowledge // Applied Sciences and technologies in the United States and Europe: common challenges and scientific findings: 5th International Scientific Conference (New York, USA; February 12, 2014). Section 6. Pedagogy. New York. 2014. P. 86-90.

3. Шор Я. Б., Хубаев Г. Н. Корреляционный анализ надежности тиратронов с холодным катодом // Надежность и контроль качества. 1969. №8. С. 29-44.

4. Хубаев Г. Н. Расчет параметрической надежности тиратронов с холодным катодом при векторном определяющем параметре // Известия высших учебных заведений. Электромеханика. 1970. №1.

5. Хубаев Г. Н. Математическое моделирование на предприятии. Ростов-на-Дону, 1973. С. 67-77.

6. Khubaev G. Expert review: method of intuitively agreed choice // Economy modernization: new challenges and innovative practice: 5th International Conference (November 12, 2017, Sheffield, UK). P. 65-80.

7. Хубаев Г. Н., Щербакова К. Н., Сидоренко Д. С. Веб-приложение для сравнительной оценки, анализа динамики и прогнозирования уровня жизни населения субъектов РФ // Свидетельство о государственной регистрации программы для ЭВМ. № 2019619362. М.: Роспатент, 2019. http://uroven-zhizni.ru

8. Хубаев Г. Н. Уровень жизни населения субъектов Российской Федерации: статистическое исследование // II Открытый российский статистический конгресс: сборник докладов (г. Ростов-на-Дону, 4-6 декабря 2018 г.). 2018. Т. 1. Ростов-на-Дону. С. 409-414.

9. Хубаев Г. Н. Алгоритмы классификации лиц, принимающих решения, по уровню профессиональных знаний и творческим способностям // Наука и мир. 2016. №5 (33). Ч. 2. С. 168-176.

10. Khubaev G. Management personnel classification by skill level and creativity // European science review. Section 14. Economics and management. 2016. №5-6. P. 223-228.

11. Машинная обработка и экономико-статистический анализ информации для решения задач, связанных с повышением эффективности использования зерноуборочной техники. Шифр темы 308/75. Номер гос. регистрации №75024806. Ч. 1, 2. Ростов-на-Дону, 1976; 1977.

12. Хубаев Г. Н. Математические модели и методы анализа качества продукции: методические рекомендации для руководящих работников и специалистов предприятий. Ростов-на-Дону, 1974. С. 11-24.

13. Хубаев Г. Н. Количественные методы принятия решений: методические рекомендации в помощь руководящим работникам и специалистам предприятий. Ростов-на-Дону, 1975. 31 с.

14. Хубаев Г. Н. Методы формирования согласованного коллективного выбора в процессе экспертизы (на примере ранжирования сложных проблем) // Бюллетень науки и практики. 2017. №7 (20). С. 59-77.

15. Хубаев Г. Н. Метод интуитивно согласованного коллективного выбора лучшего решения // Материалы Российско-Китайского форума высоких технологий (г. Москва, 24-25 ноября 2017 г.). М.: НИТИ МИСиС, 2017.

Бюллетень науки и практики / Bulletin of Science and Practice Т. 5. №12. 2019

iНе можете найти то, что вам нужно? Попробуйте сервис подбора литературы.

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

16. Khubaev G. N. Method of isolating a desired subset of objects from a set of greater power // Scientific research of the SCO countries: synergy and integration: materials of the International Conference (July 31, 2019. Beijing, PRC). Part 1. Beijing, 2019. P. 50-57.

17. Хубаев Г. Н. Имитационное моделирование для получения групповой экспертной оценки значений различных показателей // Автоматизация и современные технологии. 2011. №11. С. 19-23.

18. Хубаев Г. Н., Щербаков С. М., Рванцов Ю. А. Система автоматизированного синтеза имитационных моделей на основе языка UML «СИМ-UML» // GeBIT 2015 (Ганновер, 2015). Каталог разработок российских компаний. МСП ИТТ, 2015.

19. Хубаев Г., Родина О. Модели, методы и программный инструментарий оценки совокупной стоимости владения объектами длительного пользования (на примере программных систем). Saarbrucken: LAP LAMBERT Academic Publishing, 2012. 370 с.

20. Khubaev G. N. Stepwise determination of damage from realization of security hazards of a company // European Sciences review (Scientific journal). Section 13. Economics and management. 2014. №11-12. P. 111-113.

References:

1. Khubaev, G. N. (2002). O zakone raspredeleniya vremeni osvoeniya novogo uchebnogo materiala. In Sistemnyi analiz vproektirovanii i upravlenii: materialy 6-oi Mezhdunarodnoi nauch.-prakt. konferentsii (SPb., 28 iyunya — 5 iyulya 2002 g.). St. Petersburg, 431-434.

2. Khubaev, G. (2014). Assessment of the time required for the acquisition of knowledge. In Applied Sciences and technologies in the United States and Europe: common challenges and scientific findings: 5th International Scientific Conference (New York, USA; February 12, 2014). Section 6. Pedagogy, New York, 86-90.

3. Shor, Ya. B., & Khubaev, G. N. (1969). Korrelyatsionnyi analiz nadezhnosti tiratronov s kholodnym katodom. Nadezhnost’i kontrol’kachestva, (8), 29-44.

4. Khubaev, G. N. (1970). Raschet parametricheskoi nadezhnosti tiratronov s kholodnym katodom pri vektornom opredelyayushchem parameter. Izvestiya vysshikh uchebnykh zavedenii. Elektromekhanika, (1).

5. Khubaev, G. N. (1973). Matematicheskoe modelirovanie na predpriyatii. Rostov-on-Don.

6. Khubaev, G. (2017). Expert review: method of intuitively agreed choice. In Economy modernization: new challenges and innovative practice: 5th International Conference (November 12, Sheffield, UK), 65-80.

7. Khubaev, G. N., Shcherbakova, K. N., & Sidorenko, D. S. (2019). Veb-prilozhenie dlya sravnitel’noi otsenki, analiza dinamiki i prognozirovaniya urovnya zhizni naseleniya sub»ektov RF. Svidetel’stvo o gosudarstvennoi registratsii programmy dlya EVM. No. 2019619362. Moscow, Rospatent, http://uroven-zhizni.ru

8. Khubaev, G. N. (2018). Uroven’ zhizni naseleniya sub»ektov Rossiiskoi Federatsii: statisticheskoe issledovanie. In: II Otkrytyi rossiiskii statisticheskii kongress: sbornik dokladov (g. Rostov-on-Don, 4-6 dekabrya 2018 g.). (1). Rostov-on-Don, 409-414.

9. Khubaev, G. N. (2016). Algoritmy klassifikatsii lits, prinimayushchikh resheniya, po urovnyu professional’nykh znanii i tvorcheskim sposobnostyam. Nauka i mir, (5), 2, 168-176.

10. Khubaev, G. (2016). Management personnel classification by skill level and creativity. European science review. Section 14. Economics and management, (5-6), 223-228.

11. Mashinnaya obrabotka i ekonomiko-statisticheskii analiz informatsii dlya resheniya zadach, svyazannykh s povysheniem effektivnosti ispol’zovaniya zernouborochnoi tekhniki. Shifr temy 308/75. Nomer gos. registratsii No. 75024806. 1, 2. Rostov-on-Don, 1976; 1977.

Бюллетень науки и практики / Bulletin of Science and Practice Т. 5. №12. 2019

https://www.bulletennauki.com DOI: 10.33619/2414-2948/49

12. Khubaev, G. N. (1974). Matematicheskie modeli i metody analiza kachestva produktsii: metodicheskie rekomendatsii dlya rukovodyashchikh rabotnikov i spetsialistov predpriyatii. Rostov-on-Don, 11-24.

13. Khubaev, G. N. (1975). Kolichestvennye metody prinyatiya reshenii: metodicheskie rekomendatsii v pomoshch’ rukovodyashchim rabotnikam i spetsialistam predpriyatii. Rostov-on-Don.

14. Khubaev, G. (2017). Methods of forming the agreed collective choice in the expertise process (on an example of ranking methods of solving complex problems). Bulletin of Science and Practice, (7), 59-77.

15. Khubaev, G. N. (2017). Metod intuitivno soglasovannogo kollektivnogo vybora luchshego resheniya. In: Materialy Rossiisko-Kitaiskogo foruma vysokikh tekhnologii (g. Moskva, 24-25 noyabrya 2017 g.). Moscow.

16. Khubaev, G. N. (2019). Method of isolating a desired subset of objects from a set of greater power. In: Scientific research of the SCO countries: synergy and integration: materials of the International Conference (July 31, 2019. Beijing, PRC). 1. Beijing, 50-57.

17. Khubaev, G. N. (2011). Imitatsionnoe modelirovanie dlya polucheniya gruppovoi ekspertnoi otsenki znachenii razlichnykh pokazatelei. Avtomatizatsiya i sovremennye tekhnologii, (11), 19-23.

18. Khubaev, G. N., Shcherbakov, S. M., & Rvantsov, Yu. A. (2015). Sistema avtomatizirovannogo sinteza imitatsionnykh modelei na osnove yazyka UML «SIM-UML». In: GeBIT2015 (Gannover, 2015). Katalog razrabotok rossiiskikh kompanii, MSP ITT.

19. Khubaev, G., & Rodina, O. (2012). Modeli, metody i programmnyi instrumentarii otsenki sovokupnoi stoimosti vladeniya ob»ektami dlitel’nogo pol’zovaniya (na primere programmnykh sistem). Saarbrucken, LAP LAMBERT Academic Publishing.

20. Khubaev, G. N. (2014). Stepwise determination of damage from realization of security hazards of a company. European Sciences review (Scientific journal). Section 13. Economics and management, (11-12), 111-113.

Работа поступила Принята к публикации

в редакцию 06.11.2019 г. 11.11.2019 г.

Ссылка для цитирования:

Хубаев Г. Н. Как уменьшить вероятность ошибок при выборе приоритетных направлений социального и экономического развития страны // Бюллетень науки и практики. 2019. Т. 5. №12. С. 265-280. https://doi.org/10.33619/2414-2948/49/31

Cite as (APA):

Khubaev, G. (2019). How to Reduce the Probability of Errors When Selecting the Priority Directions of the Social and Economic Development of the Country. Bulletin of Science and Practice, 5(12), 265-280. https://doi.org/10.33619/2414-2948/49/31 (in Russian).

Играть справедливо: как уменьшить вероятность ошибок при оценке ЕГЭ?

Введение

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

Как уменьшить погрешность

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

  2. Общение с преподавателями
    Правильное понимание задания – это основа правильной оценки. Поэтому, не стесняйтесь спрашивать учительницу, если вы не понимаете задания. Чем более вы понимаете задание, тем меньше будет вероятность ошибки при его выполнении.

  3. Проверка результатов
    После завершения экзамена обязательно проверьте результаты. Если вы обнаружили ошибку при заполнении бланка ответов, не оставляйте ее без внимания! Даже небольшая ошибка может повлиять на итоговый результат.

  4. Обращение в КЦО
    Если вы уверены в правильности ответа, но получили низкий балл, не стесняйтесь обращаться в КЦО (комиссию по контролю и оценке). Они могут перепроверить вашу работу и снизить вероятность ошибки.

Заключение

ЕГЭ — это серьезный тест на знания. Он действительно может определить будущее студента, поэтому важно понимать, как уменьшить вероятность ошибок при его оценке. Подготовка, внимательность и обращение в КЦО – все это поможет вам получить правильную и справедливую оценку.

  • Как указать на ошибки ребенку
  • Как указать на ошибки косвенно
  • Как узнать сведения об ошибке
  • Как узнать речевую ошибку
  • Как узнать причину ошибки 500