Reader small image

You're reading from  Refactoring with C#

Product typeBook
Published inNov 2023
Reading LevelIntermediate
PublisherPackt
ISBN-139781835089989
Edition1st Edition
Languages
Right arrow
Author (1)
Matt Eland
Matt Eland
author image
Matt Eland

Matt Eland is a Microsoft MVP in Artificial Intelligence (AI) who has been working with .NET since 2001. Matt has served as a senior engineer, software engineering manager, and .NET programming instructor. He is currently an AI specialist and senior consultant at Leading EDJE near Columbus, Ohio, where he helps companies with their software engineering and data science needs using C# and related technologies. Matt speaks and writes in his community and co-organizes the Central Ohio .NET Developers Group while pursuing a master's degree in data analytics.
Read more about Matt Eland

Right arrow

Refactoring at the Method Level

In the last chapter, we covered improving individual lines of code. We’ll expand on those lessons to cover refactoring entire methods and solving issues with how code comes together to form larger methods that then interact with each other.

We saw a little of this in Chapter 2 when we covered the extract method refactoring. However, in this chapter, we’ll expand our set of tools covering the basics of refactoring methods and then move into more advanced areas as we cover the following main topics:

  • Refactoring the flight tracker
  • Refactoring methods
  • Refactoring constructors
  • Refactoring parameters
  • Refactoring to functions
  • Introducing static methods and extension methods

Technical requirements

The starting code for this chapter is available from GitHub at https://github.com/PacktPublishing/Refactoring-with-CSharp in the Chapter04/Ch4BeginningCode folder.

Refactoring the flight tracker

This chapter’s code focuses largely on a single FlightTracker class intended to track and display the outgoing flights from a commercial airport for passengers in the terminal, as pictured in Figure 4.1:

Figure 4.1 – FlightTracker displaying outbound flight statuses

Figure 4.1 – FlightTracker displaying outbound flight statuses

The FlightTracker class has a number of methods related to managing and displaying flights. It is supported by the Flight class which represents an individual flight in the system and the FlightStatus enum which represents all relevant statuses of a flight, as shown in the class diagram in Figure 4.2:

Figure 4.2 – A class diagram showing FlightTracker and supporting classes

Figure 4.2 – A class diagram showing FlightTracker and supporting classes

We’ll explore these pieces of code throughout this chapter, but for now, we need to understand that the key responsibilities of FlightTracker include the following:

  • Tracking a list of flights
  • Scheduling new flights (adding...

Refactoring methods

In this section, we’ll explore a number of refactorings related to methods and their interactions. We’ll start by discussing the access modifier of a method.

Changing method access modifiers

During my time as a professional C# instructor, I noticed my students often tended to not think about the access modifiers they used in their code. Specifically, my students would usually do one of two things:

  • They marked all methods as public by default unless someone (usually me) suggested they use a different access modifier
  • They marked all methods as private by default (or omitted the access modifier entirely, defaulting to private anyway) until the compiler gave them an issue requiring them to make a method more accessible

Both approaches are insufficient for a simple reason: we want to explicitly declare the visibility level of our methods. This way, whenever you read code, you are reminded explicitly by the access modifier what other...

Refactoring constructors

When you think about the job of a constructor, its whole reason for being is to get the object into its correct initial position. Once the constructor completes, the object is generally considered ready for use by other code.

This means that constructors can be very handy for ensuring that certain pieces of information are in place.

Right now, our Flight class is defined fairly minimally and only has the default constructor that .NET provides in the absence of any explicit constructor:

Flight.cs

public class Flight {
    public string Id { get; set; }
    public string Destination { get; set; }
    public DateTime DepartureTime { get; set; }
    public DateTime ArrivalTime { get; set; }
    public string Gate { get; set; }
    public FlightStatus Status { get; set; }
    public override string ToString() {
...

Refactoring parameters

Now that we’ve explored the basics of methods and constructors, let’s talk about managing parameters. This is important because it is possible that poorly thought-out parameters can quickly reduce the maintainability of your code.

Let’s look at a few common refactorings you’ll want to perform over the life of your methods.

Reordering parameters

Sometimes, you’ll realize that the order of parameters in a method doesn’t make as much sense as another arrangement might. At other times, you might notice that a few of your methods take in the same kinds of parameters, but with inconsistent ordering. In either case, you’ll find yourself wanting to reorder your method parameters.

Let’s look at a practical example from the various MarkX methods we saw earlier:

FlightTracker.cs

public Flight? MarkFlightDelayed(string id,
  DateTime newDepartureTime) {
  // Details omitted...
...

Refactoring to functions

In this section, we’ll explore some aspects of refactoring related to functional programming. Functional programming is an approach to programming that focuses on functions and their interactions instead of purely on objects and classes.

Functional programming has become more popular over the last decade and that popularity has influenced the C# language with the addition of new forms of syntax.

We’ll explore a few of the syntactical improvements related to functional programming and see how they can help make concise and flexible programs. While this is not a book about functional programming, we’ll still find ourselves exploring a few of these concepts in this section and Chapter 10, Defensive Coding Techniques.

Using expression-bodied members

To start dipping our toes into the waters of the more functional syntax, let’s take a look at the FindFlightById method in FlightTracker:

private Flight? FindFlightById(string...

Introducing static methods and extension methods

Now that we’ve explored some of the more functional aspects of method refactoring, let’s take a look at some of the features that helped revolutionize .NET: static methods and extension methods.

Making methods static

Sometimes, your classes will have methods that don’t work directly with instance members (fields, properties, or non-static methods) of that class. For example, FlightTracker has a Format method that converts a DateTime to a string resembling “Wed Jul 12 23:14 PM”:

private string Format(DateTime time) {
    return time.ToString("ddd MMM dd HH:mm tt");
}

Here, Format doesn’t rely on anything other than the parameters it is provided to calculate a result. Because of this, we can make Format a static method.

Static methods are methods associated with the class itself and not with an instance of the class. As a result, you don’t need...

Reviewing and testing our refactored code

Over the course of this chapter, we took a repetitive FlightTracker class and restructured it to ensure that its method signatures were more consistent and that common logic was reused wherever possible.

Refactored code

The final refactored code from this chapter is available in the https://github.com/PacktPublishing/Refactoring-with-CSharp repository inside of the Chapter04/Ch4RefactoredCode folder.

Before we move on, we should ensure that all tests still pass by running the unit tests from the Test menu and then selecting the Run All Tests menu item.

Summary

In this chapter, we saw how various methods, constructors, and parameter refactorings can be applied to keep your code orderly. We saw how overloading and chaining together methods and constructors gives you more options, while renaming, adding, removing, and reordering parameters helps ensure consistency.

Near the end of this chapter, we covered Actions, Funcs, static methods, and extension methods, and showed how thinking about your code in terms of small, reusable functions can help solve certain types of problems more effectively.

In the next chapter, we’ll cover object-oriented refactoring techniques and revisit our parameter refactorings in this chapter by exploring how large sets of parameters can be brought under control by extracting classes.

Questions

  1. Are there any areas of your code where you seem to be confused more frequently by the parameter ordering or naming?
  2. Can you think of any places in your code where slightly different actions are performed based on the same or similar conditions? If so, does moving to use an Action or a Func make sense?
  3. Does your code have a set of “helper methods” that might make sense to make static and put into a static class? If so, would switching to extension methods improve your code elsewhere?

Further reading

You can find more information about the materials discussed in this chapter at the following URLs:

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Refactoring with C#
Published in: Nov 2023Publisher: PacktISBN-13: 9781835089989
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $15.99/month. Cancel anytime

Author (1)

author image
Matt Eland

Matt Eland is a Microsoft MVP in Artificial Intelligence (AI) who has been working with .NET since 2001. Matt has served as a senior engineer, software engineering manager, and .NET programming instructor. He is currently an AI specialist and senior consultant at Leading EDJE near Columbus, Ohio, where he helps companies with their software engineering and data science needs using C# and related technologies. Matt speaks and writes in his community and co-organizes the Central Ohio .NET Developers Group while pursuing a master's degree in data analytics.
Read more about Matt Eland