Now I’m working in a mobile apps company, and Objective-c ,c++ (for iOS) and Java (for android) are my most frequently used language. Is it a good habit to just use common language features among them? (for example: never use multiple inheritance which can be used in c++ only)
I know there is already a famous thread similar to my question here:
Should we avoid language features that C++ has but Java doesn’t?
But those thread seems only asks about writing c++ as if Java just because Java is newer,and my question is about using common language features only among my environment (not restrict to c++ and java only), also my motivation to doing is different from those question mentioned.
My motivation of using common language features only is simple: to made my OOP design experience and logical design (in terms of UML diagram) more universal for my environment. for instance,when you develop a system in iOS, you gain the experience of designing those kind of system or the sub-system inside it (eg:a PDO). Once when you meet similar scenario in android,eg: a sub-system is similar to the previous one in iOS, if I always use common language features only, my design experience in iOS can be reused in android immediately (the UML diagram in iOS is similar to the android one), is it correct?
And a more concrete example, I use object adapter only instead of class adapter even in c++ because class adapter needs multiple inheritance which is not allowed in Java. If you rely on C++ features only , when you encounter similar problem in Java, you have to develop another solution for Java. But if you just use common features between them, your problem solving skills can be reused in java.
So, according to the motivation above, is using common language features only in my environment to make my experience universal a good habit?
I recently did an exercise where I did a complete UML design for a small system, and then tried to implement it. The UML was written as language-independent as possible, though possibly a bit Java-influenced. However, I used C++ to implement it. What did I learn?
There is no such thing as a language-independent design. Design decisions are shaped by their context, and frameworks and languages are part of that context. There were significant changes needed to port the essence of the design over to the implementation, but these changes impacted nearly every method declaration, added and removed some classes, and re-wired the interaction between classes. The only part that remained unchanged was the name of some classes in my domain model.
Even though individual designs are not universal, doing platform-specific design should not be problematic for you. After all, design and problem-solving are meta-skills that span the entirety of your work. In fact, these skills get stronger the more you exercise them across various domains and contexts, as you are forced to evaluate new approaches.
In this respect, solving the same problem on two different platforms is an interesting exercise: the second time, you have a far more complete understanding of the problem, and already know possible solutions. Invariably, the two designs will differ, but comparing these differences is a chance to improve both.
But you can’t simply re-use all design decisions. The only thing you can reuse is all the work leading up to the design: gathering requirements and performing an analysis of them. The result of the analysis may include UML models, but these would be truly abstract and language-independent. When you concretize this into a design, you still want to make sure both designs solve the same problem. A requirements traceability matrix is one possible approach: A table where you list all requirements and describe how each design satisfies them. Such a table is particularly useful later in the software lifecycle to prevent the two applications from diverging – other programmers that join later (or even yourself in three months) are unlikely to keep the “big picture” in mind for each small change.
Another approach to re-use as much effort as possible is to literally re-use code on all platforms. The cross-platform code would supply the required functionality as a library, and a platform-specific wrapper would integrate this library with the platform and provide the UI. However, many apps don’t really do anything spectacular, and most of the required effort lies in the UI which you can’t reuse anyway (Phonegap or similar technologies notwithstanding).
This is the kind of thing that goes wrong either way if you push to far.
Yes it’s good not to depend on quirks of the language in a design you want to reuse in another language.
However, it’s not good to obsess on whether a “language feature” exists in both, especially if it can be easily worked around.
Multiple inheritance is an unfortunate example here. Mostly because inheritance is out of favor. I prefer composition. But if we stick with it, please note that while java doesn’t do straight up multiple inheritance it can implement as many interfaces as you please. Which is a long way to say, just because it isn’t a “language feature” doesn’t mean we can’t find a way to do it. That’s what many of the GoF design patterns are really about.
Patterns, workarounds, and kludges will happen. They won’t look the same in every langauge. Sorry but 1 to 1 parity here just isn’t going to happen.
You can try to beat how you express solutions into uniformity to increase the maintainability of your overall design. This will make reading the code easier. It will constrain the solutions available to you. But you might be able to keep the differences in design to a minimum.
If you can accept that a perfect 1 to 1 isn’t going to happen and simply aim to keep the two code bases similar enough that knowledge of one will be useful in the other then it’s ok to make some design choices simply to keep the two code bases similar.
But if you’re spending lots of time anguishing over this, it’s time to let it go.