Каталог решений - Способы написать действительно надежный код в 1Сv7.7

Способы написать действительно надежный код в 1Сv7.7

Способы написать действительно надежный код в 1Сv7.7

В наличии

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

Категория:

Описание

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

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

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

Джоэл Спольски ( http://www.joelonsoftware.com/articles/Wrong.html )

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

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

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

Например:

// Локальная строковая переменная процедуры или функции
стрМояПеременная = "Моя строка"; 
// Локальная переменная процедуры или функции для хранения дат
датЕщеПеременная = '08.08.08'; 
// Локальная переменная процедуры или функции для чисел
чслПростоПеременная = 5; 
// Глобальная переменная глобального модуля для справочника сотрудников
гл_спрСотрудники = СоздатьОбъект("Справочник.Сотрудники");
// Переменная не глобального модуля для справочника сотрудников
г_спрСотрудники = СоздатьОбъект("Справочник.Сотрудники");

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

Перем МояПеременная; 

На самом деле не так хороша, как кажется на самом деле. Так как она несет в себе некоторые минусы в применении к 1С.

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

Процедура Выполнить()
      Перем чслПер, чслРез;
      чслРез = чслПер + 3;
      Сообщить("" + чслРез);
КонецПроцедуры

Это относится и к передаче переменных в параметры функций:

Функция ПриемПараметров1(чслПар1, чслПар2, чслПар3)
      Возврат чслПар1 + чслПар2 + чслПар3;
КонецФункции

Процедура Выполнить()
      Перем чслПер1;
	  
      //
      // Текст процедуры
      //
	  
      Сообщить(""+ПриемПараметров1(чслПер1, 2, 3));
КонецПроцедуры

А вот если не иметь привычки явно объявлять, а только определять присвоением, то в таком случае, при интерпретации Вам интерпретатор выдаст ошибку: «Переменная не определена (ИмяПеременной)», что позволит отловить такие вещи еще на этапе компиляции. Например:

 
 Процедура Выполнить()
      чслРез=0; чслПер1=0;
      чслРез = чслПер1 + чслПер2 + 3;
      Сообщить("" + чслРез);
КонецПроцедуры

Или:

Функция ПриемПараметров1(чслПар1, чслПар2, чслПар3)
      Возврат чслПар1 + чслПар2 + чслПар3;
КонецФункции

Процедура Выполнить()
	  чслПер1=0;
	  
	  //
	  // Текст процедуры
	  //
	  
	  Сообщить(""+ПриемПараметров1(чслПер1, чслПер2, 3));
КонецПроцедуры

Поэтому, я бы рекомендовал явно объявлять только глобальные переменные модулей, а локальные переменные процедур и функций, определять не явно в начале процедуры или функции начальными значениями:

Процедура Выполнить()
      // Объявления локальных переменных процедуры или функции
      стрМояПеременная = ""; // Строковая переменная
      датЕщеПеременная = '00.00.00'; // Переменная для хранения дат
      чслПростоПеременная = 0; // Переменная для чисел
      // Переменная для справочника сотрудников
      спрСотрудники = СоздатьОбъект("Справочник.Сотрудники"); 
      
      //
      // Операторы процедуры или функции
      //
КонецПроцедуры

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

чслПер= чслПер+1; // Переменная не увеличится на 1, она останется пустой

Но, если в начале функции Вы будете иметь привычку присваивать начальные значения переменным, то Вы напишете:

чслПер=0;
//
// Операторы процедуры или функции
//
чслПер= чслПер+1; 

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

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

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

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

Функция ПриемПараметров1(чслПар1, чслПар2, чслПар3)
      Возврат чслПар1 + чслПар2 + чслПар3;
КонецФункции

Процедура Выполнить()
      Сообщить(""+ПриемПараметров1( , 3, ));
КонецПроцедуры

Также существует нюанс при передаче параметров описанный в статье:

Занимательная передача параметров
//sale.itcity.ru/profile/20743/blogs/628/

Поэтому, принимая параметры процедур и функций, стоит проверять их типы и приводить к нужным типам принудительно. Например:

Функция ПриемПараметров1(чслПар1, чслПар2, чслПар3)
      чслПар1=Число(чслПар1);
      чслПар2=Число(чслПар2);
      чслПар3=Число(чслПар3);
      Возврат чслПар1+чслПар2+чслПар3;
КонецФункции

А для агрегатных типов:

Функция ПриемПараметров1(чслПар1, спрПар2)
      чслРез=1; // Результат: =1 – удачно, =0 – не удачно
      чслПар1=Число(чслПар1);
      Если ТипЗначения(спрПар2)<>11 Тогда // 11 – тип Справочник
             // Возможно еще вывод сообщения или другие действия
             чслРез=0;
             Возврат чслРез;
      Иначе
             Если спрПар2.Вид()<>"Сотрудники" Тогда
                    // Возможно еще вывод сообщения или другие действия
                    чслРез=0;
                    Возврат чслРез;
             КонецЕсли;  
      КонецЕсли;
	
      //
      // Операторы процедуры или функции
      //
	
      Возврат чслРез;
КонецФункции

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

has been added to your cart:
Оформление заказа