Why all our objects be a little more private
Tags: codequality, design, csharp
Published: 2019-12-23 18:26:28

When I first started developing software, and for a good period of my development life, I didn't care or really know about object property accessors.

Every class I created would look like this

```csharp
public class FileMapper
{
	public string FileName { get; set; }
	public string FileType { get; set; }
	public string FullFilePath { get; set; }
	public string UniqueIdentifier { get; set; }
}
```

I would use accessors for methods and the classes themselves, but I never really cared about the properties. 

This created some rather interesting debugging sessions. 

One of the blessings and curses of the above class, is that ANY one of the properties can be set from ANY place in your codebase.

I'll just let that sink in. 

The properties of an object can be changed from absolutely anywhere.

If you are the one and only person working on the code base, this may not cause too many headaches. You yourself know that the UniqueIdentifier should only ever be set once and never changed. And that the FullFilePath is made up of a base directory + the unique identifier + the file name. 

For every file that has been mapped previously, this structure stands. For other services that may rely on this same structure, a change would cause missing files here, there and everywhere.

However, once you stop working on the code base and a new developer starts they do not have the same knowledge. 

They may start manipulating the file path after the file has already been saved. 

They may even change the unique identifier, causing the once built file path to now be completely incorrect. 

# Private setters to the rescue

So let's add some private setters to the class.

```csharp
public class FileMapper
{
	public FileMapper()
	{
		this.UniqueIdentifier = Guid.NewGuid().ToString();
		this.FullFilePath = Path.Combine(Constants.SomeDirectoryPath, this.UniqueIdentifier, this.FileName);
	}

	public string FileName { get; private set; }
	public string FileType { get; private set; }
	public string FullFilePath { get; private set; }
	public string UniqueIdentifier { get; private set; }
}
```

I want to state now, one of the most important concepts I stick by when writing code.

**The only thing that should be able to update the state of an object, is the object itself**

Whilst some people might think that's overkill and a little impractical, it certainly saves a lot of headaches. 

I know, for an absolute fact, that once the FullFilePath has been set, it will never be changed.

Properties do change, and that's where methods come in. To update the file path of a FileMapper, use a method not the property directly. That allows code like this

```csharp
public class FileMapper
{
	public FileMapper()
	{
		this.UniqueIdentifier = Guid.NewGuid().ToString();
		this.FullFilePath = Path.Combine(Constants.SomeDirectoryPath, this.UniqueIdentifier, this.FileName);
	}

	public string FileName { get; private set; }
	public string FileType { get; private set; }
	public string FullFilePath { get; private set; }
	public string UniqueIdentifier { get; private set; }

	public void UpdateFilePath(string newBasePath)
	{
		foreach (var file in Directory.GetFiles(Path.Combine(Constants.SomeDirectoryPath, this.UniqueIdentifier))
		{
			File.Move(file, Path.Combine(newBasePath, this.UniqueIdentifier, Path.GetFileName(file));
		}

		this.FullFilePath = Path.Combine(newBasePath, this.UniqueIdentifier, this.FileName);
	}
}
```

I know that whenever the file path is updated, all the previous files will come along with it. No file loss, no missing data.

That method can be called whenever, by whoever, and the same things will happen. 

If a new developer comes along and wants to work out what is going on, it's explicit and easy to follow.

I'd love to hear your thoughts on the usage of private setters, but it is certainly one of my core concepts in development. 

Remember

**The only thing that should be able to update the state of an object, is the object itself**