I am an Electrical Engineer now training and working as an embedded software developer, so I have little formal computer science and software design training. I have until a few months ago only worked in C and functional programming, but started recently working with C++ and OOP for Embedded Linux with a team whose development guidelines I question. Performance is not an issue is this project.
I have to use classes as interfaces in our submodules, i.e. a library interface header declares a class that should be instantiated by the processes that use it (at the moment no other library needs it), and whose methods compose the API. I also cannot use global variables, i. e. the class has to encapsulate all data that it may need. I had never seen such a thing - I am used to building and using APIs with "standalone" (to the lack of a better word) functions (init()
, open()
, get
/set
/reset()
, doSomething()
, ...), having some global variables with file scope, and seldom some extern
(I am aware the use of globals and extern may be frowned upon depending on the situation and am OK with my use of it). The problems I have found so far with this approach:
Conditional access: usually I created a mutex variable with file scope, initiated it in the
init()
function and used it in the getter/setter and where else needed. Now I have a class modifying an external resource that will be instantiated in multiple processes. Can in such an architecture a conditional access system be implemented at all? At the moment my solution is to have a dedicated task to deal with the shared resource and processes requests from the objects sequentially (the objects will limit themselves to sending the request to the task).Code repetition: since the classes are hermetic there are some functions and data that got repeated. For example I have three classes translating related (but different) input values and then writing the output to a database. The db write function looks very similar across the classes and in my previous approach I would have created a single standalone function to handle those operations. I could construct a subclass for this, but I think the added complexity and difficulty to read does not justify it in this case, especially considering that is not the practice in our code base. If I were to adopt that route I would, for this relatively simple feature, have 3 subclasses implementing only one method - and that is too pedantic in my opinion.
My approach before the code was reviewed was the API with standalone functions and I used classes in the library internals to try and capture the relations between the data. As a (simplified) example I had to go from:
/*+++++
file translation.cpp
++++++*/
class translation1{
int CurrentTranslation;
public:
void translate(int);
int getTranslation();
};
class translation2{
int CurrentTranslation;
public:
void translate(int); //translation is different from translation1
int getTranslation();
};
...
class translation1 Translation1;
class translation2 Translation2;
...
void init()
{
...
}
void translateAll(int one, int two)
{
Translation1.translate(one);
Translation2.translate(two);
...
}
saveToDatabase()
{
one = Translation1.getTranslation();
two = Translation2.getTranslation();
....
}
to:
/*+++++
file translation.h
++++++*/
class translation1{
int CurrentTranslation;
public:
translate(int);
int getTranslation();
saveToDatabase();
};
class translation2{
int CurrentTranslation;
public:
translate(int); //translation is different from translation1
int getTranslation();
saveToDatabase();
};
...
I find the last approach contaminates the class with methods unrelated to the data.
Being new to OOP I feel I am being molded and tainted by an approach to the paradigm that I feel is not correct, so I am looking to understand how does it relate to the industry accepted practices and, on a secondary level, with the industry best practices. What other limitations can I expect from this development approach?
Do my struggles stem from the change to OOP, from bad development guidelines or are limitations of the OOP paradigm itself?