Design pattern write-ups typically present tidy, pre-verified examples - here is the pattern, here is the matching code, here is why it works. Real codebases rarely hand you patterns that clean. Recognizing a pattern accurately, including recognizing when code merely resembles a pattern without actually satisfying its definition, is a more valuable skill than memorizing textbook descriptions. This article walks through two patterns examined in an actual enterprise .NET project - one genuinely present, and one initially assumed present, until closer inspection showed otherwise.

The Repository Pattern, Present Without the Name

The project follows a familiar structure: a Controller layer, and a Data Access layer reached only through an interface.

public interface IclsWorkFlow
{
    List<CtrlSlnoName> GetAddWorkFlows(int employeeSlno, int createdBy);
    bool SaveAddWorkFlows(List<UserRoleMappingModelDto> models);
}

public class clsWorkFlow : IclsWorkFlow
{
    public List<CtrlSlnoName> GetAddWorkFlows(int employeeSlno, int createdBy)
    {
        // Oracle/ADO.NET-specific logic contained here
    }

    public bool SaveAddWorkFlows(List<UserRoleMappingModelDto> models)
    {
        // Oracle/ADO.NET-specific logic contained here
    }
}

The Controller depends solely on IclsWorkFlow, with no direct reference to clsWorkFlow or any ADO.NET code:

public class WorkFlowController : ControllerBase
{
    private readonly IclsWorkFlow _workFlowDataAccess;

    public WorkFlowController(IclsWorkFlow workFlowDataAccess)
    {
        _workFlowDataAccess = workFlowDataAccess;
    }
}

Despite nothing in the codebase being labeled "Repository," this is structurally a Repository Pattern. The naming convention differs from the textbook IEmployeeRepository/EmployeeRepository pairing, but the underlying intent is identical: database-specific implementation stays hidden behind a clean interface, so the rest of the application depends on a contract rather than a concrete data-access mechanism. Recognizing this mattered less for introducing something new, and more for confirming the project already followed a sound, testable structure under a different naming convention than the pattern's usual literature.

Where an Initial Pattern Identification Was Wrong

A separate part of the project defines a shared base class for different request types, with common fields and one shared approval method:

class BaseRequest
{
    public string EmpID;
    public int Status;

    public void ApproveLevel(int currentSeqNo, int nextSeqNo)
    {
        Status = (currentSeqNo == nextSeqNo) ? 1 : 0;
    }
}

class LeaveRequest : BaseRequest
{
    public DateTime FromDate;
    public DateTime ToDate;
}

The initial instinct was to call this a Template Method Pattern - a base class defining a process, with subclasses customizing individual pieces. That label doesn't actually hold up under scrutiny. ApproveLevel() is a single method with fixed logic, not a defined multi-step sequence, and LeaveRequest doesn't override or customize any part of its behavior. This is plain Inheritance - shared fields and one shared method reused by a subclass that adds unrelated fields of its own. Labeling it Template Method would have applied pattern terminology to code that doesn't meet the pattern's actual requirements.

The Structure That Would Actually Qualify

Template Method Pattern requires a defined sequence of steps in the base class, where individual steps - not the overall sequence itself - are customized by subclasses:

abstract class BaseRequest
{
    // The fixed sequence, defined once, never overridden
    public void ProcessRequest()
    {
        ValidateRequest();
        CheckApprovalLevel();
        SendNotification();
    }

    protected virtual void ValidateRequest()
    {
        // default shared validation, optionally overridden
    }

    protected void CheckApprovalLevel()
    {
        // shared approval logic, identical for every request type
    }

    protected abstract void SendNotification();
    // each subclass must supply its own implementation
}

class LeaveRequest : BaseRequest
{
    protected override void SendNotification()
    {
        // leave-specific notification content
    }
}

class AdvanceRequest : BaseRequest
{
    protected override void SendNotification()
    {
        // advance-specific notification content
    }
}

With ProcessRequest() fixing the sequence - validate, then check approval, then notify - and only SendNotification() varying per subclass, this genuinely satisfies the pattern's definition. The algorithm's shape stays locked in the base class; only designated steps are open to customization. That's a meaningfully different structure than simply sharing a field and a method across subclasses, even though both involve inheritance.

Why the Precision Matters

It would have been straightforward to describe the original BaseRequest/LeaveRequest structure as Template Method Pattern in a design document or an interview answer, based on surface resemblance - inheritance present, a shared method present, subclasses present. But applying a pattern name to code that doesn't structurally satisfy the pattern's definition creates a misleading impression of design sophistication, and risks a teammate or reviewer taking the label at face value, expecting a defined multi-step algorithm that isn't actually implemented. Correctly identifying plain Inheritance as plain Inheritance, rather than reaching for a more sophisticated-sounding label, is a more useful and more honest habit than pattern-matching on surface features alone.

Takeaway

Design patterns are most valuable when they accurately describe a structure genuinely serving its intended purpose, not when retrofitted onto code because the shape looks superficially similar. A Repository Pattern can exist without the word "Repository" anywhere in the codebase, provided the underlying structure - interface-based abstraction over data access - is authentically present. Conversely, shared fields and a shared method through inheritance don't constitute a Template Method Pattern unless an actual sequence of steps exists, with specific points deliberately left open for customization. Being precise about which is which - including concluding "this is simply inheritance, not a named pattern" when that's accurate - is a more valuable skill than confidently mislabeling code in either direction.

Summary

Design patterns should be identified from their actual structure and intent rather than from superficial similarities. An interface-based data-access abstraction can represent the Repository Pattern even when the code uses different naming conventions, while ordinary inheritance should not be labeled as Template Method unless a fixed algorithm contains explicit customization points. Accurate pattern recognition helps developers understand existing codebases, communicate designs clearly, and avoid adding unnecessary complexity through incorrect pattern terminology.