4

Every so often a programmer notices that he has some very similar code in a few places. Lets say here are there instances of similar code. (This is a toy example for clarity. in the wild, this anti-pattern generally doesn't occur on code quite this simple)

function showLoginError(){
    let msg = "Login Error";
    logAtLevel(WARNING, msg);
    displayInPopup(msg);
}

function showDbError(){
    let msg = "Could not access DB";
    logAtLevel(ERROR, msg);
    displayInPopup(msg);
    notify("db-admin@foo.com");
}

function showUnknownError(){
    let msg = "Something has gone wrong";
    logAtLevel(ERROR, msg);
    displayInPopup(msg);
    notify("general-admin@foo.com");
}

An experienced programmer may refactor into something like this and now this can be reused generally and understood pretty trivially.

function showError(logLevel, msg, notifyEmail){
    logAtLevel(logLevel, msg);
    displayInPopup(msg);
    if(notifyEmail){
        notify(notifyEmail);
    }
}

function showLoginError(){
    showError(WARNING, "Login Error");
}

function showDbError(){
    showError(ERROR, "Could not access DB", "db-admin@foo.com");
}

function showUnknownError(){
    showError(ERROR, "Something has gone wrong", "general-admin@foo.com");
}

but with less experienced programmers, I often see something like

function showError(errorType){
    let msg;
    let logLevel = ERROR;
    if(errorType == "LOGIN"){
        msg = "Could not access DB";
        level = WARNING;
    }else if(errorType == "DB"){
        msg = "Could not access DB";
    }else if(errorType == "UNKNOWN"){
        msg = "Something has gone wrong";
    }
    logAtLevel(logLevel, msg);
    displayInPopup(msg);
    if(errorType != "LOGIN"){
        notify(errorType == "DB" ? "db-admin@foo.com" : "general-admin@foo.com")
    }
}

function showLoginError(){
    showError("LOGIN");
}

function showDbError(){
    showError("DB");
}

function showUnknownError(){
    showError("UNKNOWN");
}

They should have isolated parts function that change and extracting them out of the function, but instead, they made a function with "modes" (or sometimes boolean flags).

The function's mode is generally checked in several places throughout the function to implicitly set variables and/or to determine which parts of the function execute. While they they've gotten rid of copy-pasted code, they've added a special kind of spaghetti code in its place.

I've seen this enough times now that I'm thinking there has to be a name for it.

P.S. If one doesn't already exist, I'm thinking "Rotini Code" since it's like spaghetti but it comes in with 3 different colors mixed together.

zevdg
  • 1,091
  • 2
  • 9
  • 20

1 Answers1

0

Yes, this is RTTI = Run-time type information. Often a code smell, sometimes not.

Often it's a code smell and should be replaced with polymorphism, see e.g. Do polymorphism or conditionals promote better design?

As an aside, Java enums function more like sub-classes of the enum class so that you can avoid having to write a lot of functions that switch on the enum. But it's not always avoidable (e.g. when a class that can't add methods to the enum must add its own method to the enum).

Community
  • 1
  • 1
djechlin
  • 59,258
  • 35
  • 162
  • 290
  • This isn't really what I'm looking for. RTTI is a C++ specific language feature that allows sniffing type info at run-time. In general computer science terms, this is called reflection. My example does not involve types at all, just stand alone functions. Type info really doesn't come into it. – zevdg Mar 06 '16 at 17:32
  • @PsyWolf you could call it DIY-RTTI then, since you're just writing your own language-agnostic boilerplate to implement what C++ offers as a feature. Term taken from here http://stackoverflow.com/questions/234458/do-polymorphism-or-conditionals-promote-better-design which is a question specifically about this (oft) anti-pattern. – djechlin Mar 06 '16 at 20:35