Location, Location, Location: Where to place code

March 26th, 2021

Where do you place a shareable, UI extension method? Today, I share my discussion I had with a fellow developer and look for feedback from others

In today's post, I wanted this to be more of a discussion for my fellow developers as to where certain code should reside.

This is a true story of a developer discussion over the past week.

In this recent discussion, I was asked to help out with an ASP.NET MVC application. They wanted a quick and easy way to create a dropdown list based on an IEnumerable<T>.

This was an easy approach since I wrote a couple posts about creating an extension method for generating SelectListItems.

Open-and-shut case, right?

Not quite.

There's always a piece of code that stands out from the rest of the application as a utility function/method/helper. Should it be shared? Should it be added to the infrastructure folder?

The discussion was similar to a familiar fairy tale of "not too hot," "not too cold," or "no, not there." It ended up being "just right" for the developer.

Scope: Local (controller)

At first, we decided to place this into the controller. Use the service to pull the list of items and then create the IEnumerable<SelectListItem> for the ViewModel.

Done!

Right?

Not entirely.

"Not a good place," said the developer, "I want to be able to create other dropdowns for other ViewModels without copying the code." (Remember the DRY principle).

Ok, next thought.

Scope: Local (Extensions Folder)

Taking it to the next level, why not create an extension folder in the root of the UI application and place extension methods dealing with UI into the folder (Everyone knows how I LOVE extension methods).

"But I would like the code usable in other ViewModels."

"With this approach, it would be usable across all ViewModels in the application," I said.

"What if other people want to use it? Is it possible to move this into a library?"

I said, "sure, you can place it into a class library."

Scope: Class Library

We started looking at the existing shared libraries in their solution and picked a nice location for the code. 

As I started adding the extension method to the library, I thought about this.

Their class library didn't have any UI code (which I thought was a good thing).

This extension method would drag the Microsoft.AspNet.Mvc assembly into the class library because of the SelectListItem generated by the extension method.

Would this make sense to reference a UI library in a shared class library?

I said, "I'm thinking we don't want to include UI code in a class library. Let's focus on creating it in the UI application."

Scope: Inheritance through ViewModel

Maneuvering back into the UI, we decided to go with the BaseViewModel approach which I described in ASP.NET MVC ViewModel: Make Your ViewModels More Functional.

I always thought this made sense.

Any time you want to create a dropdownlist using SelectListItems, you'll always have a list in your ViewModel. So why not have some code to help create your SelectListItems. This gives you a more efficient way of creating dropdownlists for every one of your views.

And it's centralized in the BaseViewModel.

Conclusion (and analysis)

After going back and forth as to where the code should reside, we agreed on building it into a BaseViewModel as a method. It can always be refactored later.

This was an interesting topic and it's funny how quickly it escalated from being local in a controller to "Can others use this in a class library?"

While this story was more of "where does the code essentially reside," it shows the code may need refactored to a new location based on whether they want it available for all ViewModels in the application or placed in a shared library for others to use. 

Here was my take on this.

I'm sure a number of developers have experienced this at one time or another. It's always good to discuss this with other developers so we can all grow.

In the long run, this leads developers down the road of best practices and possibly architectural discussions.

But tell me what you think? Did I make the right call?

What are your thoughts on this approach? Did you think this was the right place to put the code? Post your comments below and let's discuss.