-
B1. A code corresponds to the Technical Task.
All the mandatory tasks of the TT have been fulfilled.
-
B2. A project compiles.
A project can be successfully built, and a compiler doesn't show any errors.
-
B3. No unhandled errors occur when executing code.
All parts of the application work as expected while code is executing.
-
B4. All tests (if any) pass successfully.
If a project has tests, all of them pass successfully.
-
B5. Pascal casing is used for naming classes, interfaces, structs, records, and files.
public class LanguageCode { } public struct Money { }
-
B6. Pascal casing is used for naming
public
class members and constants.It's used for fields, properties, events, methods, etc.
public class Person { private const string Country = "Ukraine"; public string Name { get; } public bool IsActive; public int GetAge() { } }
-
B7. Camel casing is used for naming parameters, local variables and private fields. For
private
fields prefix_
is used.public class Person { private readonly string _name private bool _isActive; public int GetAge(int birthYear, int currentYear) { var age = currentYear - birthYear; } }
-
B8. English nouns are logically used for variable and property names.
Abbreviations are used only as service variables (for loops, predicates, etc.):
i
,x
, and so on.Bad:
var data = new List<string> { "Joe", "Ross", "Chandler" }; for (int index = 0; index < 3; index++) { Console.WriteLine(index); }
Good:
for (int i = 0; i < 3; i++) { Console.WriteLine(i); } var name = "Ross";
-
B9. Arrays use plural nouns for naming.
var integers = new List<int> { 1, 2, 3, 4, 5, 6 }; var people = new List<Person>();
-
B10. Boolean variable names start with a prefix and are affirmative.
Bad:
public class Post { private bool _deleted = false; public bool Active { get; set; } }
Good:
public class Post { private bool _isDeleted = false; public bool HasBillingAddress { get; set; } }
-
B11. Corresponding prefixes are used for names of interfaces and generic parameters.
Interface names must start with a capital
I
and then a usual pascal casing. Generic parameter names must start with capitalT
(can be just one letter).public interface ICountryService<TCountry> { public TCountry GetCountry(int id); } public class EncryptedId<T> { public T Id { get; set; } }
-
B12. Asynchronous methods are marked with an
Async
suffix.public interface IProjectRepository { public Task<Project> GetByIdAsync(int id); }
-
B13. 🅰️ All the assets have corresponding suffixes (.component, .module, .pipe, etc.)
-
B14. Curly braces are used everywhere and always start on a new line.
Curly braces are used everywhere if the statement implies and even if the code block consists of just one line. Curly braces always start with a new line.
public void Print(string mood) { if (mood == "fine") { Console.WriteLine("I'm fine"); } } public class EmptyClass { }
-
B15. Access modifiers are always specified.
Access modifiers (
public
,private
, etc.) are always specified for classes, interfaces, members, etc.private readonly string _name; public void PrintName() { Console.WriteLine(_name); } public interface IPersonInterface { }
-
B16. There is always only one line between statements.
Bad:
private readonly string _name; public void PrintName() { Console.WriteLine(_name); } public interface IPersonInterface { }
Good:
private readonly string _name; public void PrintName() { Console.WriteLine(_name); } public interface IPersonInterface { }
-
B17. Imports (
using
section) are always at the top of the file.using
statements reside at the top of the file withSystem
imports going first, and then all the others sorted alphabetically. -
B18. .NET predefined data types are not used (such as
Int32
,Boolean
orString
).Built-in primitive types are used instead:
int
,string
,bool
-
B19. No asynchronous methods return
void
.All asynchonous methods return
Task
orTask<T>
. -
B20. LINQ method syntax used.
LINQ method syntax is preferred over query syntax:
int[] numbers = { 5, 10, 8, 3, 6, 12}; //Query syntax: IEnumerable<int> evenIntsQuery = from num in numbers where num % 2 == 0 orderby num select num; //Method syntax: IEnumerable<int> evenIntsMethod = numbers.Where(num => num % 2 == 0).OrderBy(n => n);
-
B21. One class/interface/struct/enum/etc. per file.
Each class, interface, and all the other parts of the application reside in its files. Exception: nested classes are allowed if required.
-
B22. Application solution is logically structured using different projects and directories. -
B23. There are no redundant NuGet packages in the application.
All of the installed NuGet packages in different projects should be used.
-
B24.
🅰️ Folder structure maintained properly.It can be "folder-by-structure" or "flat-structure" or something else as long as it's consistent.
-
B25. 🅰️ Single responsibility rule is followed (one service or component per file).
-
B26. Sensitive data kept outside of code. -
B27. using statement
is used when working with objects that consume resources (or IDisposable interface implemented). -
B28. Asynchronous execution isn't blocked by Task.Wait or Task.Result. -
B29. LINQ calls are optimized.
Bad:
var childrenAmount = people.Where(x => x.Age < 18).Count(); var isEmpty = people.Count() == 0;
Good:
var childrenAmount = people.Count(x => x.Age < 18); var isEmpty = !people.Any();
-
B30. SQL code is always generated using parameters (no interpolation).
Bad:
int id = 1; string name = "Bill"; int age = 60; var sql = $"INSERT INTO USERS(id, name, age) VALUES({id}, {Name}, {Age})"; connection.Execute(sql);
Good:
int id = 1; string name = "Bill"; int age = 60; var sql = "INSERT INTO USERS(id, name, age) VALUES(@Id, @Name, @Age)"; connection.Execute(sql, parameters: new { Id = id, Name = name, Age = age });
-
B31. Cross-Origin Requests (CORS) are enabled. -
B32. 🅰️ Lazy loading is used for modules where possible. -
B33. 🅰️ No memory leaks while using observables.
-
B34. Interfaces are used instead of implementations. They are registered using dependency injection. -
B35. API is (mostly) RESTful.
At least:
- POST requests only create resources
- GET requests only return data, without changing anything
- PUT requests only update information, etc
-
B36. Endpoints return obvious codes.
At least:
- 200 — OK
- 201 — Created
- 404 — Not found, etc.
-
B37. No business logic inside controllers. -
B38. Controllers don't work with domain models.
An application uses DTOs for input and output and performs mapping in the application layer to avoid working with domain objects in the controllers.
-
B39. Plural nouns are used for paths (instead of verbs).
-
B40. No "magic values" in code.
Code doesn't use any "magic values". They are at the top of the class definition as constants or in separate files.
-
B41. The most abstract interfaces are used whenever possible (IEnumerable over ICollection, ICollection over IList, etc.) -
B42. Null-conditional operators are used if there are possible null values. -
🅰️ B43. No (or extra minimum) logic in templates. -
🅰️ B44. No logic inmain.ts
file.
-
A1. Properties and fields are above methods in classes. -
A2. Public methods are above the private ones. -
A3. LINQ chain is split into lines.
Bad:
var studentNames = studentList.Where(s => s.Age > 18).Select(s => s).Where(st => st.StandardID > 0).Select(s => s.StudentName);
Good:
var studentNames = studentList.Where(s => s.Age > 18) .Select(s => s) .Where(st => st.StandardID > 0) .Select(s => s.StudentName);
-
A4. No redundant
else
statements.Bad:
if (name == null) { throw new Exception("Name cannot be null"); } else { Console.WriteLine($"Hello, {name}") }
Good:
if (name == null) { throw new Exception("Name cannot be null"); } Console.WriteLine($"Hello, {name}")
-
A5. Entities for EF Core are configured using IEntityTypeConfiguration (not OnModelCreating) and split by files. -
A6. Database miggrations are short and conscise.
-
A7. The last features of the language are used.
// C# 8 // Switch statements. public static Period GetCountry(PeriodUnit unit, int amount) => unit switch { PeriodUnit.Days => Period.FromDays(amount), PeriodUnit.Months => Period.FromMonths(amount), PeriodUnit.Years => Period.FromYears(amount), _ => throw new ArgumentException("Not a valid period unit.") }; // Using declaration using var file = new System.IO.StreamWriter("CountryCodes.txt"); // Null-coalescing assignment var numbers = GetNumbers(); numbers ??= new List<int>(); // C# 9 // Target typed new private Dictionary<string, object> _properties = new(); // New pattern matching features if (name is not null) { ... }
-
A8. Global exception handling middleware exists and handles all possible application exceptions. -
A9. API is documented. -
A10. There is a logging middleware.
-
A11. The Technical Task is implemented in full.
All mandatory and optional tasks of the TT have been fulfilled.