C++ Builder
| Главная | Уроки | Статьи | FAQ | Форум | Downloads | Литература | Ссылки | RXLib | Диски |

стр.: (3) < [1] 2 3 >
Оценивание качества кода
vvoid
Отправлено: 11.04.2005, 15:15


Машинист паровоза

Группа: Участник
Сообщений: 171



Не раз встрчал на форуме: выражение "парень, а у тебя качественный код". Смотрел я этот код, ну и вообщем-то ничего особенного я там не видел, разве что всегда была туева хуча коментариев. Такое впечатление, что качество кода оценивают наличием коментариев. Я сейчас не говорю про какие-то программерские сверх навороты и придерживаюсь мнения, что и Hello word можно написать красиво! Вот у меня и возник вопрос, а как Вы оцениваете качество (красоту, понятность, реюзабельность smile.gif ) кода?

Спасибо за ответы, уверен, что будет интересно почитать разные мнения разных прораммистов.
Konstantine
Отправлено: 11.04.2005, 16:05


Мастер участка

Группа: Модератор
Сообщений: 545



для меня — в первую очередь — это отступы, т.к. без них — это похоже на молитву — Бог (проц) поймёт, а окружающие — пофиг.
затем — понятливость алгоритмов — если используются заумные нестандартные алгоритмы, то нужно их краткое описание (в т.ч. комментариях)
немаловажны названия переменных — типа для счётчиков обычно используются i, j,k; для указателей — p... и т.д.
Функции также требуют внимания — если из названия функции и входных переменных непонятно что нужно в качестве входных переменных и что она с ними делает (извините не смог описать проще smile.gif ) то это должно быть описано (кратко и понятно)
кстати — если используются неклассические формы (ну типа ++q=p++ или сложнее) — это тоже требует быть описаным

кстати эти все требования я стараюсь сам для себя соблюдать — зато когда открыл проект через год — всё сразу не вспомнил а изучил smile.gif
vvoid
Отправлено: 11.04.2005, 16:43


Машинист паровоза

Группа: Участник
Сообщений: 171



Отступы — без сомнения. Нужна строгая система, которая прослеживается на протяжении всего проэкта. (классное сравнение с молитвой smile.gif )
Описание нестандартных алгоритмов — согласен.
Названия функций и переменных — должны по-возмжности исключать необходимость коментариев. Считаю, что даже временные переменные надо называть полными именми.
Ещё желательно, что бы был указан тип переменных, ведь int это не unsigned int wink.gif, где что используется, там то и должно быть.
Пусть функция имеет название хоть в 60 символов, но описывает свои действия (у меня такие функции встречались).
А вот использование нестандартних конструкций... Я не приветствую, пусть лучше всё будет записано в несколько строк, и разделено скобками, но будет понятно, какое действие за каким делать. (не то что бы я не мог разобрать, что делается при ++q=p++, но ведь могут быть и покруче накрутки). Оптимизатор себе отоптимизирует как надо, и количество строк сейчас принципиальное значение не имеет, зато понятно и приятно wink.gif
Sl@Sh
Отправлено: 11.04.2005, 17:33


Мастер участка

Группа: Участник
Сообщений: 383



Если все, кто читают код всё (или почти всё) понимают, то этот код можно назвать просто читаемым (читебельным).

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

Алгоритмы вообще важная штука. Вот например простой алгоритм, который меняет местами переменные :
1)
CODE

int a = 15, b = 20, c;
c = a;
a = b;
b = c;

2)
CODE

int a = 15, b = 20;
a = a + b;
b = a — b;
a = a — b;


Разница в том, что первый случай обходит создание новой переменной.
Георгий
Отправлено: 11.04.2005, 23:21


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



ещё один критерий — отсутствие дублирования, высокое повторное использование кода.

например алгоримт обмена значений 2х переменных должен быть реализован так swap( a, b ); т.е. изобретать велосипед не стоит.

чёткость и непротиворечивость комментариев.

цикломатическая сложность — структурная сложность программного блока по вычислительным циклам. рекомендуется считать, что "цена" оператора вне цикла = 1, внутри цикла = 10, а внутри вложенного цикла = 100. и так далее.

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

а вообще SQAP, стандарт IEEE оценивает качество, как результат "опроса" по списку контральных вопросов с вынесением относительных оценок и сравнении со средними по фирме.
Guest
Отправлено: 12.04.2005, 10:00


Не зарегистрирован







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

Это собственно про то что этим кодом реализуется, а вот про сам код слово красиво наверно больше про вкусы...как с женщинами.
Asher
Отправлено: 12.04.2005, 13:48


Мастер участка

Группа: Модератор
Сообщений: 550



Если для исправления какого-то таракана надо переписать всю систему... biggrin.gif
Лучше с таким кодом не встречаться.
vvoid
Отправлено: 12.04.2005, 15:36


Машинист паровоза

Группа: Участник
Сообщений: 171



Георгий затронул интересный ряд: "отсутствие дублирования, высокое повторное использование кода", позволю себе добавить следующее звено: Модульность
Сам себя часто ловлю на том, что это я где-то уже писал... wink.gif. Терпеть не могу такме моменты. БРРР. Считаю, что про повтоное использование действительно хорошей функции(й) надо задумаваться сразу, объединять сходные по смыслу, выполняющимся заданиям функции в отдельные модули и когда есть уверенность в действительно качественной и безошибочной реализации "куска кода" можно собирать библиотеки (или библиотечки ;-) ).
Я не с проста упомянул про качественную и безошибочную реализацию, поскольку во многих случаях, открывая свою когдашнюю (прошлую) реализацию чего либо, у меня появляется желание написать это заново — знаний и навыков то ведь добавилось! Наверняка каждый сталкивался с ситуацией, когда до конца понимаешь, что ты делаешь уже после того, как довёл это до какого-либо стабильного состояния. Не зря японцы в несколько раз больше времени тратят на общумаывание решения задачи, чем на рализацию этого решения (может не самым лучшим образом сформулировал предложение — извиняйте smile.gif )
62316e
Отправлено: 12.04.2005, 15:45


Дежурный стрелочник

Группа: Участник
Сообщений: 38



От скажыте как будет лутше?
1)
CODE
int a=50;
int b=10;
int c=a+b;

2)
CODE
int a(50);
int b(10);
int c(a+b);

Или в даном случае "лутше" не причем? cool.gif
Asher
Отправлено: 12.04.2005, 17:29


Мастер участка

Группа: Модератор
Сообщений: 550



Лучше по коду или оформлению?
По генерируемому коду они абсолютно идентичны.
Или это простой пример общего случая?
Тогда будет ли между этими варантами разница зависит от специфических свойств конкретного типа
62316e
Отправлено: 12.04.2005, 18:23


Дежурный стрелочник

Группа: Участник
Сообщений: 38



QUOTE
Лучше по коду или оформлению?
По коду.
QUOTE
По генерируемому коду они абсолютно идентичны.
Нет.
QUOTE
Или это простой пример общего случая?
В даном случее тут есть конструктор и если его зделали то не просто так!???
vvoid
Отправлено: 12.04.2005, 19:12


Машинист паровоза

Группа: Участник
Сообщений: 171



QUOTE
В даном случее тут есть конструктор и если его зделали то не просто так!???


А зачем он здесь сделан? (если это задумка программиста).

Если суть вопроса в том, зачем это вообще было добавлено в С++, то, возможно, это можно объяснить тем, что С++ — типа объектно-ориентированный язык, значит все переменные в нём должны рассматриваться как объекты неких классов. Класс, как известно, должен всегда находиться в некотором стабильном, чётко определённом, состоянии (инвариантность классов), для этого и был придуман конструктор, который должен вызываться только в момент создания объекта любого класса. Получается, что инициализация переменных, которая в С делалась таким образом:
CODE

int a=50;
int b=10;
int c=a+b;

, в С++, для придерживания принципов объектно-ориентированного программирования, должна проводится так:
CODE

int a(50);
int b(10);
int c(a+b);


PS*
Хотя мне лично больше нарвится так:
CODE

int a;
int b;
int c;

a = 50;
b = 10;
с = a + b;

Я считаю, что по возможности объявление переменных должно быть отдельно от логики программы, разумеется с классами дела обстоят по-другому, но я создание объктов классов всегда визуально отделяю от объявления простых переменных пустой строкой — получается чисто и опрятно smile.gif .

Отредактировано vvoid — 12/04/2005, 19:14
62316e
Отправлено: 12.04.2005, 20:30


Дежурный стрелочник

Группа: Участник
Сообщений: 38



QUOTE
...пустой строкой — получается чисто и опрятно
Выше пишеш одно делаеш другое! Если тебе нравитса Паскаль пишы как в Паскале...
Георгий
Отправлено: 12.04.2005, 21:47


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



возможно я чтото не понимаю, но причём тут ООП?

C++ в отличии от C имеет:
механизм полиморфного поведения (классы)
механизм упрощенной обработки ошибок (исключительных ситуаций)
механизм метапрограммирования — шаблоны (похоже в последние 2-3 года наиболее активно развивается именно это направление)
+ такая мелочь как улучшенный контроль преобразования типов

и всё это только для снижения интеллектуальной сложности кода, вернее не только кода, а структуры ПО и соответствующему ей кода.

таким образом, с точки зрения качества структуры и кода, использование ООП или процедурного программирования, или непроцедурного (например язык программирования потока управления) не имеет никакого значения.

качество от инструмента не зависит. от инструмента зависит трудоёмкость.

Отредактировано Георгий — 12/04/2005, 21:51
** Harold
Отправлено: 13.04.2005, 00:49


Не зарегистрирован







Типы, ООП, и т.д.
НО, знакомые очень"волосатые"(без преувеличения) программеры на MS VISUAL'e пишущие с "закрытыми" глазами (надеюсь, будет мало возражений по поводу кашерности, тем паче, что и мне, как дятлу, Builder ближе, но и мой Борландовый интерфейс (все остальное — фигня — "встречают по одежке" ) скрипя зубами принимают и даже пишут под него СОМ-объекты, ну чтоб с MS'ом потом личных проблем поменьше иметь...
Ну, так я о качестве кода — все типы описываются ВСЕГДА максимально понятно — iInteger, fFloat, bBoolean, dwDoubleWord и т.д...
Даже мне, дятлу, мало понимающему в современном программировании понятно (типа, Enlish ещё в школе вдолбили)... Пример (не мой)
CODE

OxidePlant1->InsertHardwareBlock(0x7042,0x0C,(IUnknown**)&m_pBlock7042_C);
  notifyBlock7042_C.OnIsWorkedEvents = TForm1::OnIsWorkedEvents;
 notifyBlock7042_C.Connect( m_pBlock7042_C );
  // создаем DigitalOut выходы 0-13
m_pBlock7042_C->InsertOxideTemperatureController(
   402,    // идентификатор устройства
   0,      // задействованы выходы начиная с DigitalOut_0
     14,     // Всего выходов
     (IUnknown**)&m_pTempCtrl_C );
  m_pTempCtrl_C->AddRef();
  notifyAnalogIn.OnAlarmEvents = TForm1::OnLogDevAlarmEvents;
  notifyAnalogIn.OnInfoAnalogEvents = TForm1::OnLogDevInfoAnalogEvents;
  notifyAnalogIn.OnInfoDigitalEvents = TForm1::OnLogDevInfoDigitalEvents;
  notifyAnalogIn.Connect( m_pTempCtrl_C );
  m_pTempCtrl_C->SetFeedBack( m_pTermocouple2 );

Все, конечно, красиво и ООП-кашерно, но мне, лично, через if-else проще, и работает не хуже... Ну, или учиться под MS писать или все тоже самое по простому — топориком — компы-то нынче ого-го. Ну и пусть себе Борландовые обертки мой бред "разворачивают"... зато мне понятнее. НЕ ХОЧУ Я API в полном объеме и сразу! Поспорьте, может, я и не прав (но цель-то достигнута — все работает — не хочу я пока MS — слишком много заморочек и СРАЗУ. Не желаю продираться через ЧАЩУ всякой синтаксической ПУРГИ)...
К чему всё это?
Да так... наверное, от моего НЕУМЕНИЯ...
** Harold
Отправлено: 13.04.2005, 01:11


Не зарегистрирован







Н-да, у Борланда, с редактором(!) — БЕДА... было все КРАСИВО... Но, сама их идея мне нравится — дятлам ЛЕГКО...
PS. Ну, про хелп, вообще, молчу.С MSDN'a, чтоль, пример взяли бы...
Зачем неплохую идею так изгадили...?! (в сердцах...)
Asher
Отправлено: 13.04.2005, 08:25


Мастер участка

Группа: Модератор
Сообщений: 550



QUOTE

По генерируемому коду они абсолютно идентичны.
Нет.

А в отладчике посмотреть?
Я же уточнил именно этот случай кодя — или это просто пример более общего случая использования?
Но даже в общем случае если это класс-тип с явно объявленным конструктором, то в обоих случаях просто вызовется этот конструктор. Разницы не будет.
Проверено отладчиком.
Sl@Sh
Отправлено: 13.04.2005, 09:44


Мастер участка

Группа: Участник
Сообщений: 383



Млять, забыл файл присоеденить, жаль в редактировании нельзя

User Attached Image Скачать файл
Sovets.rar


vvoid
Отправлено: 13.04.2005, 15:19


Машинист паровоза

Группа: Участник
Сообщений: 171



QUOTE (62316e @ 12/04/2005, 20:30)
QUOTE
...пустой строкой — получается чисто и опрятно
Выше пишеш одно делаеш другое! Если тебе нравитса Паскаль пишы как в Паскале...

То ли ты меня не розумієш, то ли я тебя.
Паскаль мне, кстати, не нравится.

На сколько я понял, ты имеешь ввиду, что я писал:
QUOTE
в С++, для придерживания принципов объектно-ориентированного программирования, должна проводится так:
CODE

int a(50);
int b(10);
int c(a+b);

а сам привёл в корне другой пример! Скажи, ты всегда знаешь нужное значение переменной при её объявлении?

И ещё заметь, С++ именно типа объектно-ориентированный язык! И вообще, кто тебе сказал, что объектно-ориентированное программирование всегда хорошо!!??

PS* если я начал разглагольствовать не по той теме, которую ты имел ввиду — пиши — я прокоментриую!
vvoid
Отправлено: 13.04.2005, 15:38


Машинист паровоза

Группа: Участник
Сообщений: 171



2Harold
Не влазя в логику:
CODE

#define DeviceID (402)
#define OutputPinStartIndex (0)
#define OutputPinTotalCount (14)

OxidePlant1->InsertHardwareBlock(0x7042,
0x0C,
(IUnknown**)&m_pBlock7042_C);

notifyBlock7042_C.OnIsWorkedEvents = TForm1::OnIsWorkedEvents;

notifyBlock7042_C.Connect(m_pBlock7042_C);

// создаем DigitalOut выходы 0-13
m_pBlock7042_C->InsertOxideTemperatureController
(DeviceID,
OutputPinStartIndex,
OutputPinTotalCount,
(IUnknown**)&m_pTempCtrl_C);

m_pTempCtrl_C->AddRef();

notifyAnalogIn.OnAlarmEvents = TForm1::OnLogDevAlarmEvents;
notifyAnalogIn.OnInfoAnalogEvents = TForm1::OnLogDevInfoAnalogEvents;
notifyAnalogIn.OnInfoDigitalEvents = TForm1::OnLogDevInfoDigitalEvents;

notifyAnalogIn.Connect(m_pTempCtrl_C);

m_pTempCtrl_C->SetFeedBack(m_pTermocouple2);


Если бы я ещё знал, что такое 0x7042, 0x0C — объявил бы эти числа в виде констант, чтоб всем было понятно, да чтоб сам мог разобраться, если через годик-два понадобится вспомнить, а что что я тут делал? :-)
По-моему с таким кодом легче работать, хотя это дело вкуса...
Harold, я помню, что код не твой, поэтому не принимай мои замечания на свой счёт.
Народ, давайте поэкспериментируем с этим куском кода. Что с ним ещё можно сделать и как вам мой вариант?

Отредактировано vvoid — 13/04/2005, 15:40
FataLL
Отправлено: 16.04.2005, 08:45


Дежурный стрелочник

Группа: Участник
Сообщений: 37



Все-таки сделал бы const int вместо #define и еще не нравятся мне эти подчеркивания... Хотя мне и TForm1 не нравится. Если этот m_pxxxx_C наследник от TForm1 не ясно, зачем эти присваивания. А если не наследник, то почему бы его им не сделать. Или написать методы:
CODE

TForm1::SetEvents( TNotifyBlock& notifyBlock );
TForm1::SetEvents( TNotifyAnalog& notifyAnalog );

и делать там все присвоения. Тогда бы это все стало выглядеть еще короче:
CODE

const int cnDeviceID                     = 402;
const int cnOutputPinStartIndex  = 0;
const int cnOutputPinTotalCount  = 14;

OxidePlant1->InsertHardwareBlock(0x7042,
                                                       0x0C,
                                                       (IUnknown**)&m_pBlock7042_C);

TForm1::SetEvents( notifyBlock7042_C );

notifyBlock7042_C.Connect(m_pBlock7042_C);

// создаем DigitalOut выходы 0-13
m_pBlock7042_C->InsertOxideTemperatureController
                             (DeviceID,                  
                              OutputPinStartIndex,
                              OutputPinTotalCount,
                             (IUnknown**)&m_pTempCtrl_C);

m_pTempCtrl_C->AddRef();

TForm1::SetEvents( notifyAnalogIn );

notifyAnalogIn.Connect(m_pTempCtrl_C);

m_pTempCtrl_C->SetFeedBack(m_pTermocouple2);

smile.gif
Георгий
Отправлено: 16.04.2005, 11:36


Почетный железнодорожник

Группа: Модератор
Сообщений: 874



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

в начале можно написать:
1. краткое описание — например: "блок чтения температуры с датчиков используется COM объект"
2. т.к. заголовка функции не увидел, то перечень использованных глобальных объектов
3. по простенькому комментарию-памятке к каждому вызову функции
Sl@Sh
Отправлено: 16.04.2005, 18:55


Мастер участка

Группа: Участник
Сообщений: 383



Интерестно, кто как считает, какой из этих вариантов лучше :
1) void Func(const int &a);
2) void Func(int a);

Оба случая поидее недопускают изменения переменной, которая передана в функцию. Однако первый случай не копирует переменную.
Какой вариант грамотней, если переменную менять не нужно ?
FataLL
Отправлено: 17.04.2005, 12:50


Дежурный стрелочник

Группа: Участник
Сообщений: 37



Если переменную менять не надо вообще (даже в функции не допускается изменений), то грамотнее:
CODE

void Func( const int& a )
{
   a++; // здесь ошибка на этапе компилирования
}

Второй вариант не меняет передаваемый параметр, но допускает его изменение в теле функции:
CODE

void Func( int a )
{
   a++; // ошибки нет, это допускается
}

cool.gif
Sl@Sh
Отправлено: 17.04.2005, 17:59


Мастер участка

Группа: Участник
Сообщений: 383



to FataLL
Вы фактически повторили мои слова. Вопрос я задал потому, что видел много функций, в которых параметр передавался по значению, но в функции не менялся.
FataLL
Отправлено: 18.04.2005, 00:03


Дежурный стрелочник

Группа: Участник
Сообщений: 37



to Sl@Sh
Я не повторял ничего. Я сказал, что это совершенно разные варианты описания функций. И применяется этот модификатор const для отлова потенциальных ошибок еще на этапе компиляции. cool.gif

Отредактировано FataLL — 18/04/2005, 00:04
Guest
Отправлено: 18.04.2005, 09:58


Не зарегистрирован







QUOTE (Sl@Sh @ 16/04/2005, 18:55)
Интерестно, кто как считает, какой из этих вариантов лучше :
1) void Func(const int &a);
2) void Func(int a);

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

Только первый вариант и есть "грамотный",
а второй — просто — распространенный wink.gif
Asher
Отправлено: 18.04.2005, 10:48


Мастер участка

Группа: Модератор
Сообщений: 550



QUOTE
Только первый вариант и есть "грамотный",
а второй — просто — распространенный

То не все так очевидно, с выбором "грамотности" вариантов.
Расширяя пример как
1) void Func(const T &a);
2) void Func(T a);
можно заметить, что T-может иметь размер и меньше размера ссылки, что может быть существенно, например при глубокой рекурсии, а во вторых в многопоточном приложении, я лично, предпочел бы поработать с один раз сделанной копией значения, чем непосредственно несколько раз обращаться к этому значению в функции.
В третих применив fastcall, для второго случая, вы вообще можете избавиться от лишних операций по доступу к памяти, особенно при inline.

Отредактировано Asher — 18/04/2005, 11:55
FataLL
Отправлено: 18.04.2005, 14:39


Дежурный стрелочник

Группа: Участник
Сообщений: 37



Правильно, универсального решения нет. Так и должно быть. Все зависит от конкретного случая. Вопрос в том, что понимать под "грамотностью". Я говорил с точки зрения безопасности. Если ошибка всплывает на этапе компиляции — это сохраняет время и нервы по отлову скрытых багов в будущем.
Asher
Отправлено: 18.04.2005, 14:45


Мастер участка

Группа: Модератор
Сообщений: 550



Согласен.
В таком варианте void Func(const T a);
компилятор выругается аналогично void Func(const T &a);
стр.: (3) < [1] 2 3 >
Вернуться в Вопросы программирования в C++Builder