Skip to main content
Added a more contextual part about the WebService angle (was that added after my original answer?)
Source Link

For your example, yes, it's an anti-pattern.

The WebService handler already allows for multiple functions. You can have a URI that maps to each function:

class WebService { Service service; @Mapping("/confabulation/") void confabulation(@RequestBody Data data) { // ... } @Mapping("/reticulation/") void reticulation(@RequestBody Data data) { // ... } @Mapping("/splicing/") void splicing(@RequestBody Data data) { // ... } } 

Update: @edalorzo also mentions this in a comment on the OP: "You could just define a rest endpoint for each"

The same applies within software (without Web Service exposure):

Writing a software language within a software language is an anti-pattern. I personally call it the "code in code" anti-pattern which feels similar to the "database in database" anti-pattern.

Assuming that process merely does a switch, an extra layer of indirection is added without increasing value.

The caller should just call directly: eg service.CONFABULATION(data);. If an end-user is given a choice for the 3, have the switch on the UI side.


There are plenty of cases where such a "routing" design MAY BE warranted. Nothing clear-cut comes to my mind right now.

I would suggest that you look for: Value-add - some sort of business-logic being applied, and you need that to be done once in a single place.

In fact, there are plenty of cases where a "routing" design should NOT necessarily apply:

  • Authorisation - This need not be centralised. You just need CONFABULATION to call IsAuthorised("CONFABULATION") near the start of the function/service.
  • Invalid Hint - Where the ProcessingType is just a hint, and the data is the source of truth/validity. This need not be centralised. CONFABULATION checks for IsValidForConfabulation(data), if not, it might then use a shared-function to find the correct new function: ProcessDataWithCorrectFunction(data).

I would be interested in exploring a range of possible "routing" scenarios, to determine whether a central "routing" service function is the ONLY solution or clearly superior among alternatives.

For your example, yes, it's an anti-pattern. Writing a software language within a software language is an anti-pattern. I personally call it the "code in code" anti-pattern which feels similar to the "database in database" anti-pattern.

Assuming that process merely does a switch, an extra layer of indirection is added without increasing value.

The caller should just call directly: eg service.CONFABULATION(data);. If an end-user is given a choice for the 3, have the switch on the UI side.


There are plenty of cases where such a "routing" design MAY BE warranted. Nothing clear-cut comes to my mind right now.

I would suggest that you look for: Value-add - some sort of business-logic being applied, and you need that to be done once in a single place.

In fact, there are plenty of cases where a "routing" design should NOT necessarily apply:

  • Authorisation - This need not be centralised. You just need CONFABULATION to call IsAuthorised("CONFABULATION") near the start of the function/service.
  • Invalid Hint - Where the ProcessingType is just a hint, and the data is the source of truth/validity. This need not be centralised. CONFABULATION checks for IsValidForConfabulation(data), if not, it might then use a shared-function to find the correct new function: ProcessDataWithCorrectFunction(data).

I would be interested in exploring a range of possible "routing" scenarios, to determine whether a central "routing" service function is the ONLY solution or clearly superior among alternatives.

For your example, yes, it's an anti-pattern.

The WebService handler already allows for multiple functions. You can have a URI that maps to each function:

class WebService { Service service; @Mapping("/confabulation/") void confabulation(@RequestBody Data data) { // ... } @Mapping("/reticulation/") void reticulation(@RequestBody Data data) { // ... } @Mapping("/splicing/") void splicing(@RequestBody Data data) { // ... } } 

Update: @edalorzo also mentions this in a comment on the OP: "You could just define a rest endpoint for each"

The same applies within software (without Web Service exposure):

Writing a software language within a software language is an anti-pattern. I personally call it the "code in code" anti-pattern which feels similar to the "database in database" anti-pattern.

Assuming that process merely does a switch, an extra layer of indirection is added without increasing value.

The caller should just call directly: eg service.CONFABULATION(data);. If an end-user is given a choice for the 3, have the switch on the UI side.


There are plenty of cases where such a "routing" design MAY BE warranted. Nothing clear-cut comes to my mind right now.

I would suggest that you look for: Value-add - some sort of business-logic being applied, and you need that to be done once in a single place.

In fact, there are plenty of cases where a "routing" design should NOT necessarily apply:

  • Authorisation - This need not be centralised. You just need CONFABULATION to call IsAuthorised("CONFABULATION") near the start of the function/service.
  • Invalid Hint - Where the ProcessingType is just a hint, and the data is the source of truth/validity. This need not be centralised. CONFABULATION checks for IsValidForConfabulation(data), if not, it might then use a shared-function to find the correct new function: ProcessDataWithCorrectFunction(data).

I would be interested in exploring a range of possible "routing" scenarios, to determine whether a central "routing" service function is the ONLY solution or clearly superior among alternatives.

Source Link

For your example, yes, it's an anti-pattern. Writing a software language within a software language is an anti-pattern. I personally call it the "code in code" anti-pattern which feels similar to the "database in database" anti-pattern.

Assuming that process merely does a switch, an extra layer of indirection is added without increasing value.

The caller should just call directly: eg service.CONFABULATION(data);. If an end-user is given a choice for the 3, have the switch on the UI side.


There are plenty of cases where such a "routing" design MAY BE warranted. Nothing clear-cut comes to my mind right now.

I would suggest that you look for: Value-add - some sort of business-logic being applied, and you need that to be done once in a single place.

In fact, there are plenty of cases where a "routing" design should NOT necessarily apply:

  • Authorisation - This need not be centralised. You just need CONFABULATION to call IsAuthorised("CONFABULATION") near the start of the function/service.
  • Invalid Hint - Where the ProcessingType is just a hint, and the data is the source of truth/validity. This need not be centralised. CONFABULATION checks for IsValidForConfabulation(data), if not, it might then use a shared-function to find the correct new function: ProcessDataWithCorrectFunction(data).

I would be interested in exploring a range of possible "routing" scenarios, to determine whether a central "routing" service function is the ONLY solution or clearly superior among alternatives.