Один простой подход (особенно если вы подписываете код или запутываете свои сборки) - разбить приложение на несколько отдельных сборок (dll). Затем, если вы обновите код, вам нужно будет только развернуть сборки, которые действительно изменились.
Самым важным является контроль зависимостей: хорошо определить интерфейсы между сборками в начале и добавить новые интерфейсы для расширения существующей функциональности (вместо того, чтобы вносить «существенные изменения» в существующие интерфейсы), чтобы вы могли сделать полезные изменения в приложении без необходимости развертывания множества сборок в вашем патче. (Если существует много зависимостей, вы обнаружите, что для внесения изменений в любом месте вам все равно потребуется развернуть почти все сборки для клиента, что несколько противоречит цели).
Этот подход не даст наиболее компактных возможных исправлений, но он чрезвычайно прост и легко реализуем - и во многих случаях он может предоставлять «приемлемо небольшие» исправления. Это также побуждает разработчиков задуматься об использовании хороших модульных конструкций с минимальными зависимостями - так что это стоит делать (в разумных пределах), даже если вы добавите более сложный механизм исправлений сверху.
Если вы используете патч-подход, я бы посоветовал периодически предоставлять клиенту полную версию, так как чем больше патчей вы применяете, тем выше риск того, что что-то не синхронизируется. (Рассмотрим, как работает Центр обновления Windows - ОС постепенно обновляется с помощью исправлений, но время от времени Microsoft выпускает пакет обновления, который объединяет все небольшие исправления в одно большое исправление и реже выпускает целую новую версию операционной системы. что пользователи должны переустановить с нуля)