1

Suppose I have two "modules", A, and B (I'm choosing not to use classes, because you generally can't create an instance of a module, which makes this question simpler). These modules contain methods suited for dealing with the same particular type of (arbitrary) data. Crucially, the representation/format of this data is different between A and B.

At some point we have a piece of data which is in a format which one of the two modules "understands", but the other does not, and the programmer has a desire to "convert" the piece of data from one representation to another.

For the sake of example, lets say we have data which is in a format that module A understands, but module B does not. On which of the two modules should I place the method that converts the data from "A representation" to "B representation"?


To explore the question a bit, it seems that we have to choose one of the following to be true:

  • A given module knows how to convert data from another format, to the format it understands
  • A given module knows how to convert data from the format it understands, to another format

In either scenario, in order for a conversion to take place, a given module must contain information about the data representation/format of a module other than itself in order to perform a conversion. From an OOP design or separation-of-concerns perspective, this seems like a bad idea.

Is introducing a third module, C, which understands how to convert the data between different representations, a more sane way to approach this?

2
  • If you find it necessary to spend a rep point on downvoting this question I'd appreciate it if you take the time to explain why. – taylorthurlow Dec 17 '20 at 19:01
  • 4
    Topics like this are best answered for real cases with context. In the current form, the question is IMHO too general and unfocussed - any kind of place, either "A, B, or C", or a combination of two, or all 3 can be "the right" place, depending on the circumstances. – Doc Brown Dec 17 '20 at 21:01
4

It is usually better to have a module or class convert from another format to the format it understands.

While one can argue that all getters and setters are evil, it is clear that setters are more evil and problematic. Setters might

  1. cause concurrency issues
  2. throw IllegalArgumentExceptions (or similar)
  3. have complex data validation issues (nulls, valid birthday, etc...)
  4. leave the result in an indeterminate state.

Calling lots of setters on an different class or module that you don't fully understand is rife with dangers, since you don't know all the complexities. Getters rarely have any of these issues. When you convert from a B, you are only calling its getters. So, the best approach is something like (Java syntax, yours may vary)

public static A fromB(B b);   or

public A(B b)

True, there may be data validation issues with A, but A already knows about them. The programmer only needs have deep knowledge about A, not A and B.

Next, consider what happens when B changes.
They add a new required field, APIVersion. If A is converting to a B, A must change. And you are likely to forget about it.

But, if A is converting from a B, it might be able to stay the same. Depends if A cares about APIVersion. If it doesn't care, you leave it alone. If it does care, you should have already opened up an issue to add APIVersion, and it falls into that work naturally.

That said, if you have a lot of things to interconvert, A-Z, this becomes very messy.

An alternative approach is to have everybody understand some common intermediate data representation, say XML, JSON, CSV, a database, whatever makes sense for your stuff. Then, for your conversion, do something like:

  A.readXML(b.toXML());
   ...
  A.readXML(z.toXML());
4
  • 2
    The setter/getter distinction is something that I hadn't thought about, probably because the non-generalized example of this I'm dealing with right now isn't particularly complex. I appreciate the insight quite a bit, thank you. Your last point is also a good one - anything sufficiently complex translation should probably be represented/encapsulated in either a data type created for the purpose, or serialized into something like JSON or XML. Cheers! – taylorthurlow Dec 17 '20 at 20:12
  • 1
    @taylorthurlow Thanks. Note that, should you use that intermediate format, the decision as to whether the class itself reads it, or there is some helper class, will spark a religious war. IMO, if that representation is very standard and abstract, and unlikely to change, it's fine for the class to do the work. YMMV. – user949300 Dec 17 '20 at 20:16
  • 5
    Trying to understand why a setter is needed in "convert to B" case? Can't we just call B's constructor or a static create function in B if it has? – lennon310 Dec 18 '20 at 17:42
  • 1
    @lennon310 Valid point. Depends if B has a full constructor / factory. Even so, you are more likely to run into validation issues, and required changes when another field must be added. – user949300 Dec 18 '20 at 18:48
0

Your question is a bit vague, so there can be several answers.

First, if this is about code and all this happens inside an application then there should not be any data and conversion at all. Object-orientation does not deal with data, only objects with behavior, therefore there should not be any logic to convert anything.

Second, if this is not all code, and some external media is read, like a database, file or network, then the "module" would read that data into whatever objects it prefers. I would call that "parsing" not "converting".

Please update your question with more details if you means something else.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.