#ifdef vs OO patterns

K

kk_oop

Hi. In our domain, we have to vary a lot of code based on a radar type
(of which there are 3--for now). The legacy code acheives this by
heavy use of #ifdef macros sprinkled throughout the code. We now have
an opportunity to redesign a lot of this code. I am recommending that
instead of the macro approach, we use polymorphism-based design
options, such as the strategy, template method and abstract factory
patterns. To me, this just seems intuitively like a better approach.
However, I want to be able to articulate why this a better approach, so
I am prepared to respond to those who will recommend continuing with
the macro approach.

Could someone articulate some reasons or cite articles/URLs that
support the polymorphism/pattern approach over the macro approach?

Thanks in advance!

Ken
 
N

Nick Keighley

Hi. In our domain, we have to vary a lot of code based on a radar type
(of which there are 3--for now). The legacy code acheives this by
heavy use of #ifdef macros sprinkled throughout the code. We now have
an opportunity to redesign a lot of this code. I am recommending that
instead of the macro approach, we use polymorphism-based design
options, such as the strategy, template method and abstract factory
patterns. To me, this just seems intuitively like a better approach.
However, I want to be able to articulate why this a better approach, so
I am prepared to respond to those who will recommend continuing with
the macro approach.

Could someone articulate some reasons or cite articles/URLs that
support the polymorphism/pattern approach over the macro approach?

in my experience maintaining code that is crawling with #ifdefs is
painful
in the extreme. How many places would you have to change the code in
if you added a 4th radar type? It could run into hundreds or thousands.

The preprocessor is generally bad news.

This might be interesting:-
http://www.objectmentor.com/resources/articles/ocp.pdf

You could also try asking your question comp.object

Be careful your current code may be quite efficeint in memory usage
(only
code needed is included in a particuar build). Naive application of
polymorphism may cause your executable to get much larger.
 
A

Axter

Hi. In our domain, we have to vary a lot of code based on a radar type
(of which there are 3--for now). The legacy code acheives this by
heavy use of #ifdef macros sprinkled throughout the code. We now have
an opportunity to redesign a lot of this code. I am recommending that
instead of the macro approach, we use polymorphism-based design
options, such as the strategy, template method and abstract factory
patterns. To me, this just seems intuitively like a better approach.
However, I want to be able to articulate why this a better approach, so
I am prepared to respond to those who will recommend continuing with
the macro approach.

Could someone articulate some reasons or cite articles/URLs that
support the polymorphism/pattern approach over the macro approach?

Thanks in advance!

Ken

Your approach may be a great idea when starting with a new project, or
a project that is in it's early stages.
However, it's very problematic to try to convert an existing well
season project to a different format.
You usaully end up with many bugs, and problems that are hard to
forcast.
 
P

Phlip

kk_oop said:
Hi. In our domain, we have to vary a lot of code based on a radar type
(of which there are 3--for now). The legacy code acheives this by
heavy use of #ifdef macros sprinkled throughout the code. We now have
an opportunity to redesign a lot of this code. I am recommending that
instead of the macro approach, we use polymorphism-based design
options, such as the strategy, template method and abstract factory
patterns. To me, this just seems intuitively like a better approach.
However, I want to be able to articulate why this a better approach, so
I am prepared to respond to those who will recommend continuing with
the macro approach.

Could someone articulate some reasons or cite articles/URLs that
support the polymorphism/pattern approach over the macro approach?

We don't need to cite anything - preprocessor abuse is always wrong. All the
C++ tutorials will tell you that.

If you had lots of unit tests, you could change from one design to the other
incrementally, one ifdef at a time, while improving other design aspects and
improving the tests.

Read /Working Effectively with Legacy Code/ by Mike Feathers.
 
M

mlimber

Axter said:
Your approach may be a great idea when starting with a new project, or
a project that is in it's early stages.
However, it's very problematic to try to convert an existing well
season project to a different format.
You usaully end up with many bugs, and problems that are hard to
forcast.

But, if the existing product "works" but is difficult to maintain and
extend, then refactoring to patterns may actually reduce the overall
bug rate. The OP might be interested in _Refactoring to Patterns_ by
Joshua Kerievsky.

Cheers! --M
 
M

mlimber

Hi. In our domain, we have to vary a lot of code based on a radar type
(of which there are 3--for now). The legacy code acheives this by
heavy use of #ifdef macros sprinkled throughout the code. We now have
an opportunity to redesign a lot of this code. I am recommending that
instead of the macro approach, we use polymorphism-based design
options, such as the strategy, template method and abstract factory
patterns. To me, this just seems intuitively like a better approach.
However, I want to be able to articulate why this a better approach, so
I am prepared to respond to those who will recommend continuing with
the macro approach.

Could someone articulate some reasons or cite articles/URLs that
support the polymorphism/pattern approach over the macro approach?

Thanks in advance!

Ken

Patterns can be very handy, but if the programming team is not
proficient with C++ and an OO-based design, they can actually impede
productivity. (Of course training can help with those things.) As the
FAQ argues, the choice of language (and we could add design
methodology) depends more on business concerns than it does on what is
"best":

http://www.parashift.com/c++-faq-lite/big-picture.html#faq-6.5

That being said, you might want to ask this question on comp.object,
comp.software.patterns, and comp.software-eng for some additional
insight since this forum is more for discussions of the C++ language
proper rather than general design.

As for the preprocessor, our official position is that it is evil and
should be avoided:

http://www.parashift.com/c++-faq-lite/newbie.html#faq-29.8

It sounds like your existing software follows bad programming practice
and is thus likely fragile and hard to maintain and extend, but whether
you move to design patterns or not, I would strongly recommend ridding
your code of #ifdefs (except in the few instances where they are
necessary, such as header file include guards).

Cheers! --M
 
M

mlimber

Nick Keighley wrote:
[snip]
Be careful your current code may be quite efficeint in memory usage
(only
code needed is included in a particuar build). Naive application of
polymorphism may cause your executable to get much larger.

Agreed, but since the currently #ifdef'ed parts aren't needed anyway,
if properly factored into patterns, they could be excluded at the
project/makefile level to keep about the same size. As you note,
however, such an implementation is not usually the simplest to achieve.

Cheers! --M
 
K

kk_oop

Phlip said:
kk_oop wrote:

Read /Working Effectively with Legacy Code/ by Mike Feathers.

Great book. Have it, love it, use it frequently. I didn't see where
that addresses the #ifdef issue, though.

- Ken
 
P

Phlip

kk_oop said:
Great book. Have it, love it, use it frequently. I didn't see where
that addresses the #ifdef issue, though.

You guys have a latent OO pattern of a common Radar abstraction and
three concrete Radar implementations.

However, you don't use OO to run the pattern. You use conditional
compilation to produce three separate programs.

This is so wrong you won't find a citation for how wrong it is.
Someone, early in this code's history, decided that preprocessor abuse
would somehow be cleaner, or more elegant, or more efficient, than
writing one program that handles three kinds of radar.

The concept you generally need is called "Software Product Lines".
Google for that, and you will find some advice about conditional
compilation, and much advice about OO abstractions.

To get where you need to go, you must either refactor (via unit tests),
or rewrite (also via unit tests). So you need Feather's book.

If you hope to allay your team's fears about refactoring, you can't do
it by citing anything saying OO is superior to preprocessor abuse. You
should do it by coaching code cleanup and refactoring. Then you should
introduce just a few abstractions that allow just a few #ifdefs to go
away. That will turn the tide against the rest.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,902
Latest member
Elena68X5

Latest Threads

Top