How Should I Structure My Revit Add-in Code? 14 tips from Team Reope
I asked some of my colleagues at Reope for their best tips for architects and engineers getting into Revit C# development. These are the 14 points that kept coming up.

Some of these tips are universal software development principles. They apply whether you're building a Revit add-in, a web app, or anything else. Others come from eight years of building software on top of Revit for world-class architecture and engineering firms like BIG, Heatherwick, and KPF. We'll flag which is which as we go.
Write Code Your Colleagues Can Read, Not Code That Impresses Others
This was the first thing everyone said. When you come from architecture, there's a temptation to make your code "perfect." Lots of comments, complex structures, the works.
But here's what we've seen: readable code wins. Think about it like a Revit model. Would you rather inherit one with clean, logical naming conventions, or one plastered with text notes explaining the chaos underneath? Same principle applies.
Four Clean Code Principles Every AEC Developer Should Follow
A few non-negotiables that our team kept circling back to, all rooted in Clean Code principles:
Single Source of Truth. Don't repeat variable values across your code. If you're copy-pasting the same values, something's wrong.
DRY (Don't Repeat Yourself). Seeing the same code in multiple places? Time to create a reusable method.
KISS (Keep It Simple, Stupid). Complexity doesn't make you look smart. It makes your code unmaintainable.
And one more that everyone agreed on: leave code cleaner than you found it.
Five Classes That Cover Most Revit Add-ins
For a straightforward Revit add-in with a user interface, you don't need a complex architecture. Here's what our team actually uses:
- MyApplication inherits
ExternalApplication - MyCommand inherits
IExternalCommand - MyView is your WPF window
- MyViewModel handles what displays in the view
- MyModel manages all interaction with the Revit model
Often, your ViewModel and Model classes can handle all the logic you need.
Use MVVM So Any Developer Can Jump Into Any Project
MVVM stands for Model-View-ViewModel. Yes, it's one more acronym. But stick with us.
The magic is separation of concerns. Your View knows about the ViewModel, but nothing about the Model. Your ViewModel knows about the Model, but nothing about the View. Your Model is completely unaware of both.
Why bother? Because when everyone on your team uses MVVM, any developer can jump into any project and immediately understand what's happening where. It's like having a consistent modeling standard across all your Revit projects.
Avoid abbrevations
This one came up fast. Stop using abbreviations. This isn't 1995. Your screen is big enough, and you have autocomplete.
Bad: var fec = new FilteredElementCollector(doc);Good: var collector = new FilteredElementCollector(document);
One thing to be mindful of: avoid "magic strings" too. Those hardcoded strings scattered through your code. Use nameof() for class and method names. Use enums for options and variants. And please, check for null where relevant. It'll save you hours of debugging.
Comments Are Useful Until They Lie to You
Your code should be readable on its own. That's the goal. But sometimes you genuinely need a comment. Maybe you're explaining why you chose a specific approach, or flagging a Revit API quirk that isn't obvious.
The problem is that comments don't update themselves. Code changes, but the comment next to it stays the same. And a wrong comment is sometimes worse than no comment at all. It actively misleads the next person reading your code. They trust it, follow the wrong assumption, and waste hours.
So if you write a comment, make it count. Explain the "why," not the "what." And if you're updating the code next to a comment, update the comment too. Or delete it.
Static Variables Will Burn You in Revit Add-ins
Here's something that trips up a lot of architects-turned-coders: the allure of static variables.
Static variables live in memory for your entire program's lifetime. That sounds convenient. Until you realize you now have to manually keep those values updated throughout your add-in's lifecycle. It's like having a shared parameter that persists across all projects. Sounds useful until the data gets stale.
Better approach: build up and tear down data with your add-in's functions. If data belongs to a window, create it when the window opens and destroy it when it closes. Need to persist something? Use Revit's Schema storage.
Each Method Should Do Exactly One Thing
Your methods should do one thing. Not two things. Not "one main thing plus a little side task." One thing.
And that thing should be obvious from the method name. GetAllSpaces(Document doc) tells you exactly what it does. ProcessData() tells you nothing.
Worth noting that void methods should only be used when you're changing something outside your program. Writing to a file, uploading to the web, modifying the Revit model. If a void method is changing things inside your program through nested calls, you're making life hard for the next developer. Probably you in three months.
Three Key Ways to Access the Revit Document From Anywhere in Your Code
Every Revit coder hits this: you need access to Document, but it's not available where you need it.
Three approaches that actually work:
Get it from an Element. If you have any Element in your code: element.Document
Pass it through method calls. Send Document as a parameter, or include it as a property in an object. Works best with shallow code structures (which you should aim for anyway).
Static variable at the top. Only if you're disciplined about keeping it updated.
Use Iterators Instead of Lists When Processing Large Revit Models
When you're processing elements from a FilteredElementCollector, use iterators instead of converting to a list. An ElementIterator keeps only one element in memory at a time. Crucial for large projects.
var iterator = filteredElementCollector.GetElementIterator();
iterator.Reset();
while (iterator.MoveNext())
{
var candidate = iterator.Current;
// Process element...
}
This is especially useful when you're searching for a single element and can exit early.
Catch Errors at the Top, Not Scattered Through Your Code
Better for a program to fail and stop than to run with corrupt data.
Handle errors with try/catch at the highest logical point. Where it makes sense to inform the user or offer a choice. Don't scatter try/catch blocks deep in your code. That makes debugging a nightmare.
And don't be afraid to throw exceptions when something actually goes wrong: throw new Exception("Clear description of what failed"). These should be caught higher up in your code structure.
Dig Deeper With Robert C. Martin's Clean Code
If you want to go deeper, the Clean Code series on YouTube is worth your time. About ten hours total, but watch at 1.5x speed.
The principles here are based on Robert C. Martin's "Clean Code." It's become the foundation for how we structure all our tools at Reope, from Night Runner to Radar.
Summary: The Full List
Here's everything in one place:
- Write readable code over "perfect" code. If your colleague can't understand it, it doesn't matter how clever it is.
- Single source of truth. Don't repeat variable values across your code.
- DRY (Don't Repeat Yourself). If you see the same code in multiple places, create a reusable method.
- KISS (Keep It Simple, Stupid). Complexity doesn't make you look smart. It makes your code unmaintainable.
- Leave code cleaner than you found it. Just like you'd clean up a messy Revit family before using it.
- Structure your add-ins with five classes: Application, Command, View, ViewModel, and Model.
- Use MVVM to separate concerns so any developer can jump into any project.
- Name variables clearly. No abbreviations, no magic strings, use enums.
- Write comments that explain "why," not "what." Update them when you change the code, or delete them.
- Avoid static variables in Revit add-ins. Build up and tear down data with your functions instead.
- Each method does one thing. Name it so that thing is obvious.
- Access the Revit Document through elements, method parameters, or (carefully) a static variable.
- Use iterators instead of lists when processing large element collections.
- Handle errors with try/catch at the highest logical point. Don't scatter them deep in your code.
Start with these principles. Your future self (and your colleagues) will thank you.
Ready to talk about scaling your firm's Revit development capabilities?
Reach out to us at Reope and let's figure out what makes sense for your team.








