You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Добавляйте переносы строк до и после многострочных элементов кода (кроме случаев когда элемент находится в конце блока).
Однострочные элементы кода можно группировать без пропуска строк.
Лоически групиируйте члены типа, отделяя группы переносами строк. (При больших размерах групп, можно выделять подгруппы, по смысловому признаку, отделяя подгруппы пропусками строк)
// не очень ХОРОШОif(_students.Count >= MaxStudentsAmount){thrownew Exception("Students limit exceeded");}else{
_students.Add(stident);returnstudent;}// ХОРОШОif(_students.Count >= MaxStudentsAmount)thrownew Exception("Students limit exceeded");
_students.Add(stident);returnstudent;
Не используйте boolean флаги для того, чтобы управлять условиями выхода из цикла.
// ПЛОХО (не нада так пажалуста)while(true){// что угодно тут будет плохо :)// особенно, если не будет brake;}// ЛУЧШЕfor(inti=0;i<studentsConut;++i){// почти всё что угодно тут будет лучше чем предыдущий вариант// особенно, если тут не будет while (true)}
Method declaration
Метод, возвращающий коллекцию, в случае отсутствия элементов для возврата, должен возвращать пустую коллекцию, а не null.
// ПЛОХОpublicList<Student>FindStudents(intcourse){// объявляем лист (но не инициализируем)List<Student>students;/* ищем студентов любым возможным методом */// если студенты не нашлись, возвращаем nullif(students.Count isnull)returnnull;// возвращаем студентов, если хоть кто-то нашёлсяreturnstudents;}// ХОРОШОpublicList<Student>FindStudents(intcourse){// создаём пустой листvarstudents=newList<Student>();/* ищем студентов любым возможным методом */// возвращаем студентов даже, если это пустой лист (не null)returnstudents;}
Метод, который работает с пользовательскими аргументами, должен валидировать их.
// ПЛОХОpublicvoidFindStudentByFullName(stringname,stringsurname){/* поиск студента без проверки входных данных */}// ХОРОШОpublicvoidFindStudentByFullName(stringname,stringsurname){if(string.IsNullOrWhiteSpace(name))thrownew ArgumentException("Name to find student is empty");if(string.IsNullOrWhiteSpace(name))thrownew ArgumentException("Surname to find student is empty");/* поиск студента после проверки входных данных */}
В конструкторе должен соблюдаться порядок инициализации:
Валидация аргументов
Инициализация, которая не зависит от аргументов
Инициализация полей аргументами
Инициализация, которая требует какой-то логики, вызовов методов
// ХОРОШОpublicMegaFaculty(string facultyName){// валидацияif(string.IsNullOrWhiteSpace(facultyName))thrownew ArgumentException("Mega faculty name is empty");// инициализация, не зависящая от аргументов_courses=newList<OgnpCourse>();// инициализация полей аргументамиName=facultyName;/* сложная инициализация с вызовом различных методов */
NotifyISU(this);}
Property declaration
При объявлении автосвойств, помещайте аксессоры на одной строке с названием и типом
При объявлении get-only свойств, используйте bodied expressions вместо явного get аксессора
// ХОРОШОpublicIReadOnlyCollection<string>Values=> _values;// ПЛОХОpublicIReadOnlyCollection<string>Values{
get
{return_values;}}publicIReadOnlyCollection<string>Values{get => _values;}
Type declaration
Конструктор по умолчанию объявляйте явно.
Конструкторы должны полностью инициализировать объект. Валидация аргументов должна происходить в конструкторах.
Минимизируйте область доступа к данным. Предпочтительней хранить информацию в приватных полях нежели в публичных свойствах. Методы, которые не нужны внешнему коду, нужно делать приватными.
Не оставляйте мутабельные поля для отложенной инициализации. Инициализируйте поля в конструкторах и делайте иммутабельные поля и свойства, где это уместно.
Не использовать поля для передачи данных внутри метода или между методами класса.
Поддерживайте инвариант типа. Если у типа есть несколько полей, которые между собой связаны, то не должно быть способа изменить одно из полей и нарушить связь между ними.
Члены класса должны располагаться в следующем порядке:
Константы
Поля
Свойства
Конструкторы и Create-методы
Публичные методы
Приватные методы
Нумерация значений енама должна начинаться с 1. 0 может быть использован для Undefined значений.
Не используйте приватные свойства.
Не используйте оператор == для сравнения не числовых типов. Не переопределяйте оператор == для не числовых типов.
Не используйте наследование для переиспользования логики. Если объект наследуется, то справедливым должно быть высказывание, что производный объект является базовым (см. LSP).
Exceptions
Для ошибок бизнес логики стоит бросать кастомный эксепшен. Для стандартных ошибок, например, невалидных аргументов, стоит использовать стандартные типы.
Нужно обрабатывать, где это оправдано, ошибки NRE, OutOfRange etc и вместо них бросать более понятные ошибки, которые описывают проблемную ситуацию.
Если ошибка не может быть обработана, то её необходимо прокидывать дальше, а не игнорировать.
Common
Методы расширения должны выделяться в специальные классы. Они должны иметь соответствующий постфикс Extensions.
Весь исходный код должен быть написан на английском. Это касается нейминга, комментариев и ошибок. Если есть необходимость использовать другой язык, то нужно применить инструменты локализации.
Для обозначения отсутствия значения стоит использовать null, а не default. Для значимых типов стоит возвращать Nullable.
Избегайте кастов там, где можно их не использовать. Программа должна стремиться к повышению типизации и увеличению количества мест, где происходят проверки во время компиляции.
Минимизируйте количество ап кастов. Старайтесь не использовать более общие типы в сигнатурах, если они не поддерживаются.
При написании цепочки вызовов методов, переносите каждый вызов на отдельную строку.
Используйте Type.Parse вместо Convert.ToType (например, int.Parse вместо Convert.ToInt32).
Restrict
Не используйте dynamic.
Не используйте goto.
Не пишите касты для своих типов - implicit или explicit.
Не используйте публичные вложенные типы.
Не используйте модификатор доступа internal. Исключение - если нет возможности использовать другой.
Не используйте reflection для доступа к полям.
Не используйте query-like LINQ.
Не используйте Tuple, ValueTuple и KeyValueTuple в сигнатурах своих методов. Вводите специальные типы, которые лучше описывают данную структуру.
Не пишите в лямбдах больше одной операции, выносите сложную логику в методы.
Не используйте char, short для экономии памяти. Большинство интерфейсов работают с int, а значит в коде появится много кастов, которые усложняют код.
Не используйте unsigned для гарантии, что значение будет больше нуля. Большинство интерфейсов работают с int, а значит в коде появится много кастов, которые усложняют код.
Suggestions
При реализации методов создания или поиска, стоит возвращать сущности, а не какие-то их части - названия или идентификаторы. Если написано, что нужно найти магазин, то ожидается, что вернется не строка, а магазин.
Используйте специализированные проверки вида CollectionAssert.Contains(...) вместо Assert.IsTrue(collection.Contains(...)).
Не пишите сложную логику поверх примитивных типов, вводите информативные обёртки, в которых можно инкапсулировать валидацию и логику.
Стоит отделять логику ввода, вывода и бизнес-логику.
Dto
Для простых DTO, где это возможно, стоит использовать record.
Если для DTO используется класс, то сеттеры должны быть приватными.
Если для DTO используется класс, то должен быть публичный пустой конструктор.