When working in a team it’s important to have a consistent code style. Consistent code is easier to read and understand and contributes to overall developer happiness and productivity. However, the thing with code styles is that it’s very subjective. Developers tend to have their own preferences and customs based on how they learned to code and what they’re used to.
What usually helps is to decide on a set of rules or coding guidelines to assist a team in writing code in a consistent way. If you have a team with different and strong opinions this can lead to debates. And after you’ve landed on a set of rules you still have to enforce them via code reviews which is tedious and time consuming and noone has time for that.
In comes CSharpier. CShapier is a code formatter for C# inspired by Prettier. It’s a dotnet tool that can be used to format individual files or all files in a directory (and subdirectories) using a simple command:
dotnet csharpier .
CSharpier becomes even more powerful when it’s integrated with your IDE or editor (Visual Studio, Rider, VsCode and more) to automatically format your code on save. This way you can focus on your code and don’t worry about the formatting at all.
What I personally love about CSharpier is that it’s very opinionated. The defaults options are good, there are only 4 configurations options and there are and no plans to add more. This takes some getting used to because chances are that CSharpier will format your code differently than you’re used to.
But, it will get you started quickly without having to spend time on configuring and debating the best settings. Simply install the tool and you’re good to go.
Example
Here’s some uglified example code from a previous post, with some parts left out for brevity:
public class ShoppingCartService {
public async Task AddProductAsync(int productId)
{
var shoppingCart = await GetUserShoppingCartAsync();
var product = await _productService.GetAllAsync().FirstOrDefault(p=>p.Id==produdctId) ?? throw new InvalidOperationException($"Product with id {productId} does not exist");
shoppingCart.AddItem();
await _shoppingCartRepository.SaveAsync(shoppingCart);
}
public async Task<ShoppingCart> GetUserShoppingCartAsync()
{
return await _shoppingCartRepository.GetShoppingCartForUserAsync(await _userService.GetLoggedInUserAsync());
}
}
After formatting it with CSharpier it looks like this:
public class ShoppingCartService
{
public async Task AddProductAsync(int productId)
{
var shoppingCart = await GetUserShoppingCartAsync();
var product =
await _productService.GetAllAsync().FirstOrDefault(p => p.Id == produdctId)
?? throw new InvalidOperationException($"Product with id {productId} does not exist");
shoppingCart.AddItem();
await _shoppingCartRepository.SaveAsync(shoppingCart);
}
public async Task<ShoppingCart> GetUserShoppingCartAsync()
{
return await _shoppingCartRepository.GetShoppingCartForUserAsync(
await _userService.GetLoggedInUserAsync()
);
}
}
There’s a playground available where you can try out CSharpier before installing it: https://playground.csharpier.com/.
Good practices
After working with the tool for a while there are some thing I would advise when getting started with CSharpier:
-
Make sure every developer is onboard and has CSharpier installed and configured to format on save.
-
If you want to enforce that all code is formatted by CSharpier you can verify this in your pipeline by executing this command in a step:
dotnet csharpier --check .
See Continuous Integration for more background info. -
Start off by making one big change to format your entire solution before you get going with CSharpier. A more organic approach by only formatting the files you touch will cause formatting differences for weeks in every file you touch, making changes very hard to review.