Method names should be a summary of what the method is doing, it needs to stay percise and short and representative of the operation with respect to synchrony.
Method names must contain verbs in them to represent the action it performs.
public List<Student> GetStudents()
{
...
}
public List<Student> Students()
{
...
}
Asynchronous methods should be postfixed by the term Async
such as methods returning Task
or ValueTask
in general.
public async ValueTask<List<Student>> GetStudentsAsync()
{
...
}
public async ValueTask<List<Student>> GetStudents()
{
...
}
Input parameters should be explicit about what property of an object they will be assigned to, or will be used for any action such as search.
public async ValueTask<Student> GetStudentByNameAsync(string studentName)
{
...
}
public async ValueTask<Student> GetStudentByNameAsync(string text)
{
...
}
public async ValueTask<Student> GetStudentByNameAsync(string name)
{
...
}
If your method is performing an action with a particular parameter specify it.
public async ValueTask<Student> GetStudentByIdAsync(Guid studentId)
{
...
}
public async ValueTask<Student> GetStudentAsync(Guid studentId)
{
...
}
When utilizing a method, if the input parameters aliases match the passed in variables in part or in full, then you don't have to use the aliases, otherwise you must specify your values with aliases.
Assume you have a method:
Student GetStudentByNameAsync(string studentName);
string studentName = "Todd";
Student student = await GetStudentByNameAsync(studentName);
Student student = await GetStudentByNameAsync(studentName: "Todd");
Student student = await GetStudentByNameAsync(toddName);
Student student = await GetStudentByNameAsync("Todd");
Student student = await GetStudentByNameAsync(todd);
In general encapsulate multiple lines of the same logic into their own method, and keep your method at level 0 of details at all times.
Any method that contains only one line of code should use fat arrows
public List<Student> GetStudents() => this.storageBroker.GetStudents();
public List<Student> Students()
{
return this.storageBroker.GetStudents();
}
If a one-liner method exceeds the length of 120 characters then break after the fat arrow with an extra tab for the new line.
public async ValueTask<List<Student>> GetAllWashingtonSchoolsStudentsAsync() =>
await this.storageBroker.GetStudentsAsync();
public async ValueTask<List<Student>> GetAllWashingtonSchoolsStudentsAsync() => await this.storageBroker.GetStudentsAsync();
If a method contains multiple liners separated or connected via chaining it must have a scope. Unless the parameters are going on the next line then a one-liner method with multi-liner params is allowed.
public Student AddStudent(Student student)
{
ValidateStudent(student);
return this.storageBroker.InsertStudent(student);
}
public Student AddStudent(Student student)
{
return this.storageBroker.InsertStudent(student)
.WithLogging();
}
public Student AddStudent(
Student student)
{
return this.storageBroker.InsertStudent(student);
}
public Student AddStudent(Student student) =>
this.storageBroker.InsertStudent(student)
.WithLogging();
public Student AddStudent(
Student student) =>
this.storageBroker.InsertStudent(student);
For multi-liner methods, take a new line between the method logic and the final return line (if any).
public List<Student> GetStudents()
{
StudentsClient studentsApiClient = InitializeStudentApiClient();
return studentsApiClient.GetStudents();
}
public List<Student> GetStudents()
{
StudentsClient studentsApiClient = InitializeStudentApiClient();
return studentsApiClient.GetStudents();
}
With mutliple method calls, if both calls are less than 120 characters then they may stack unless the final call is a method return, otherwise separate with a new line.
public List<Student> GetStudents()
{
StudentsClient studentsApiClient = InitializeStudentApiClient();
List<Student> students = studentsApiClient.GetStudents();
return students;
}
public List<Student> GetStudents()
{
StudentsClient studentsApiClient = InitializeStudentApiClient();
List<Student> students = studentsApiClient.GetStudents();
return students;
}
public async ValueTask<List<Student>> GetStudentsAsync()
{
StudentsClient washingtonSchoolsStudentsApiClient =
await InitializeWashingtonSchoolsStudentsApiClientAsync();
List<Student> students = studentsApiClient.GetStudents();
return students;
}
public async ValueTask<List<Student>> GetStudentsAsync()
{
StudentsClient washingtonSchoolsStudentsApiClient =
await InitializeWashingtonSchoolsStudentsApiClientAsync();
List<Student> students = studentsApiClient.GetStudents();
return students;
}
A method declaration should not be longer than 120 characters.
public async ValueTask<List<Student>> GetAllRegisteredWashgintonSchoolsStudentsAsync(
StudentsQuery studentsQuery)
{
...
}
public async ValueTask<List<Student>> GetAllRegisteredWashgintonSchoolsStudentsAsync(StudentsQuery studentsQuery)
{
...
}
If you are passing multiple parameters, and the length of the method call is over 120 characters, you must break by the parameters, with one parameter on each line.
List<Student> redmondHighStudents = await QueryAllWashingtonStudentsByScoreAndSchoolAsync(
MinimumScore: 130,
SchoolName: "Redmond High");
List<Student> redmondHighStudents = await QueryAllWashingtonStudentsByScoreAndSchoolAsync(
MinimumScore: 130,SchoolName: "Redmond High");
Some methods offer extensions to call other methods. For instance, you can call a Select()
method after a Where()
method. And so on until a full query is completed.
We will follow a process of Uglification Beautification. We uglify our code to beautify our view of a chain methods. Here's some examples:
students.Where(student => student.Name is "Elbek")
.Select(student => student.Name)
.ToList();
students
.Where(student => student.Name is "Elbek")
.Select(student => student.Name)
.ToList();
The first approach enforces simplifying and cutting the chaining short as more calls continues to uglify the code like this:
students.SomeMethod(...)
.SomeOtherMethod(...)
.SomeOtherMethod(...)
.SomeOtherMethod(...)
.SomeOtherMethod(...);
The uglification process forces breaking down the chains to smaller lists then processing it. The second approach (no uglification approach) may require additional cognitive resources to distinguish between a new statement and an existing one as follows:
student
.Where(student => student.Name is "Elbek")
.Select(student => student.Name)
.OrderBy(student => student.Name)
.ToList();
ProcessStudents(students);