Код-ревью проекта. С#.Unit testing
начала изучать юнит тесты.
Чтобы попрактиковаться, сделала небольшой проект, суть которого реализация двухсвязного списка и покрытие кода юнит тестами. Использовала MSTests. Хотелось бы получить код-ревью.
Буду рада любому отзыву!
Ссылка на репозиторий: https://github.com/juliion/MyList
Ответы (2 шт):
Чтож, хотели ревью, его есть у меня немного.
Проект на гитхабе.
- Раз хотите, чтобы вас судили по проекту, озаботьтесь хотя бы описанием нормальным или названием. "MyList" ничего не говорит о проекте.
- "Установи dot net" не указывает не конкретную версию. Что конкретно установить?
- У вас список фич, было бы неплохо расширить примерами кода
- Ссылки на какие то коммиты, где фейлятся какие то тесты - они точно в Readme нужны?
- Если есть желание показать, что вы умеете в git, то не стоит пушить в мастер все. У вас только 1 ветка на проект. Но это абсолютно не обязвтельное требование, просто пожелание - держите мастер чистеньким
- Не увидел лицензии в репозитории
Код
- Названия. Например "List" вообще ничего не говорит о классе. Как насчет "DoubleLinkedList"? "DoubleLinkedListNode"?
- Node видится как просто деталь имплементации вашего списка, зачем этот класс вынесен и сделан публичным? По мне так это внутренний приватный класс для класса списка.
- Как следствие предыдущего
public Node Head { get; private set; }Node не должно покидать List, поле должно хотя бы выглядеть какpublic char Head => this.HeadNode.Data;Иначе клиенты с вашими нодами сделают все, что захотят и сломают вашу реализацию на раз. - Хотите делать список свой действиельно расширяемым, почему бы тогда не использовать обобщения?
DoubleLinkedList<T>? - Если делаете класс для того, чтобы кто то его мог использовтаь - хотя бы xml комментарии вставляйте
- Когда делаете класс для переиспользования, делайте для него отдельный проект типа библиотеки. На надо его рядом с Program ложить
var tmp = new Node()избегайте таких названий переменныхpublic void InsertAt(char val, int ind)не экономьте на буквах, индекс значитindexthrow new Exception("Wrong index");пишите более информативные сообщения об ошибках, типа "параметр под именем индекс имеет неверное значение. Значение параметра -10, допустимые значения от 0 до count"- Качество кода не на высоте, тот же метод
public void InsertAt(char val, int ind)запутанный. Я уверен, можно код переписать и сделать его в 3 раза короче и 10 раз понятней. И так для всего кода. PrintForward()почему список вдруг будет что то печатать на консоль? Позабыли про S из SOLID?- Скорость работы тут явно не в приоритете. Метод
Reverse()просто режет глаза.
Тесты
- Чтобы проверять, вылезло ли исключение не надо try/catch, надо Assert.ThrowsException
- У вас в каждом тесте есть
firstElement, secondElement, thirdElement- может сделать из них readonly поля? Да и вообще, вам обязательно их так называть? Да и вообще, вам обязательно их иметь как переменные? - Что понравилось - более менее логичное и консистентное наиманование тестов (что тестируем _ сценарй _ результат)
Резюмируя, не все так плохо. Для новичка в программировании, того, кто только учится на джуна - неплохо. Видно, что где то старались (тестов накидать), где то забили совсем (название проекта, например), что в среднем получаем оценку удовлетворительно. Что не плохо, но может быть и лучше.
Публичный доступ к Node нарушает инкапсуляцию, в идеале пользователям Вашей коллекции нужно знать как можно меньше деталей и скорее всего им будет достаточно использовать лишь API класса List;
PrintForward нарушает Single Responsibility Principle (см. SOLID), лист не должен знать как себя выводит и тащить за собой зависимость консоли, это не его ответственность поэтому её следует реализовать в другом месте (в подовляющем большинстве случаев);
Название List слегка вводит в заблуждение пользователей вашего кода, возможно стоит назвать его DoubleLinkedList;
Почитайте о подхода к стайлингу в коде, попробуйте использовать статические анализаторы кода, например Stylecop;
Попробуйте реализовать паттерн итератор поверх вашей коллекции (см. IEnumerable, IEnumerator интерфейсы);
Попробуйте абстрагировать от типа хранимых данных используя Generics вместо хранения элементов типа char;
Почитайте о best practise о том как вести собественный репозиторий;
Напишите тесты на Ваш клас для публичного АПИ, чтобы показать другим о том что Вашим классом можно пользоваться и как это делать;
Добавьте Summary на публичный АПИ класса;
Попробуйте интегривать ваш репозиторий с CI системой, например GitHub actions;
Посмотрите чужие репозитории чтобы понять как вашу задачу решили другие;
Попробуйте минимизировать АПИ вашего класса до наиболее низкоуровневого решающего поставленную задачу, а все ништяки увести в extensions methods, таким образом вы покажите пример как с Вашим классам работать и расширять его варианты использования.
Много всего другого, но можете начать с этого. А вообще, совет по практике, порешайте простые алгоритмические задачи на общедоступных ресурсах, например на Leetcode/Codewars. А дальше попытайтесь писать простые проекты на основе туториалов. Все понемногу придет с опытом, главное упорство и внутренний интерес, удачи!