0

I write embedded software and I often find myself structuring my code such that there is one large parent class that contains just about everything. For example, consider you want to model a hardware platform that can use swappable toolsets where each tool had multiple uses, I would make something like this:

class platform
{
  toolA* a;
  toolB* b;
}
platform* p;

class toolA
{
  toolA_use1* one;
  toolA_use2* two;
}

class toolB
{
  toolB_use1* one;
  toolB_use2* two;
}

class toolA_use1{...}
class toolA_use2{...}
class toolB_use1{...}
class toolB_use2{...}

Then when I want to do just about anything I will "drill down" to the relevant method or variable of the relevant object starting with the top-level class, like this:

p->a->one->someFunc();

Essentially EVERYTHING is contained in the 'platform' object p. Sometimes I have called it 'd' and the class name was 'device'... and then I'd have things like d->IO->SPI->init(&SPI_Init_LCD), or whatever. I like doing this because not only is it an intuitive structure that keeps things organized but it also helps me quickly find what I'm looking for using the editors auto-complete if I forget what I called something so I don't have to go looking for it.

In reality I'll use descriptive names of course, I just don't think I can give a real-world example without giving away what I do (and likely who I work for, there aren't many companies making these things). I've been doing this so long I haven't really questioned if there is a good reason to do this differently... I'm questioning it now because recently I've inherited a large project that is not structured at all like this and I don't like it. It's "spaghetti"... everything is flat on the same level and interconnected to everything else rather than a hierarchy like I usually make (on top of the fact the previous author was using factories and abstract base classes for things that will only ever have one object instance...)

New contributor
CHollman82 is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
7
  • 3
    EIther you're thinking in statics, or in namespaces. In either case, based on your very limited description of the other codebase, it already sounds significantly more contemporary. But this is not meaningfully answerable without context of what is it you're actually trying to achieve, which you're being intentionally secretive about.
    – Flater
    Commented Jul 9 at 23:33
  • For example, the other project I'm inheriting has an "SPI" object to represent the SPI bus... there is only one SPI bus, there will only ever be one SPI bus... but he STILL made a "factory" class to create SPI bus objects and he still made an abstract SPI bus class that he overrides with... the real SPI bus class. It makes zero sense to me. I understand the purpose of abstract classes and pure virtual functions and I understand the purpose of the factory pattern... I think... but making those for a class that will only EVER have one instantiated object doesn't make any sense.
    – CHollman82
    Commented Jul 10 at 1:56
  • 2
    Based on that comment, the core issue here is clear, but the question has to be closed as off-topic as your comment indicates that you simply haven't learned OOP basics, let alone being able to judge when to apply it to a codebase. You're arguing that the way you think about things is correct without actually researching what programming style your coworker is applying, what the contemporary approach to software development is, and what the actual pros and cons of these approaches are. This is far, far too broad to be contained in a single Q&A post and this warrants active study.
    – Flater
    Commented Jul 10 at 3:50
  • 3
    I'm just an internet stranger and have no inherent authority to tell you what to do, but my honest advice to you is that it's time to stop arguing and start learning. Arguing why your approach is the right one when you only know your approach is an unproductive discussion format, as any counter to your statement just won't make sense to you because you haven't actually learned other approaches. Similarly, taking an "as long as my approach works why would I do it any other way?" approach is not helpful, it simply inhibits you learning something new, and keeps your horizon narrow.
    – Flater
    Commented Jul 10 at 3:54
  • 1
    In my experience, the "sweet spot" where OOP starts to show its benefits in a program is somwehere between 1K and 10K lines of code (it may depend a little bit on the programming language and how you count LOC). When all of your programs don't exceed that size, it does not astonish me that you have trouble to understand how OOP can help you.
    – Doc Brown
    Commented Jul 10 at 6:39

1 Answer 1

8

there is only one SPI bus, there will only ever be one SPI bus ... he still made an abstract SPI bus class that he overrides with... the real SPI bus class. It makes zero sense to me - CHollman82

And along comes, the fake SPI bus. That isolates things for testing. Not everything we model with software is real. There are plenty of reasons to complain about needless abstraction, virtualization, and indirection. But this isn't one of them. If you find no useful fake SPI bus waiting for you in the code base then your best argument against this isn't arguing about what is real. It's YAGNI.

I write embedded software and I often find myself structuring my code such that there is one large parent class that contains just about everything.

I write non-embedded software and I often find myself structuring my code such that there is one large parent class that contains just about everything. I just call it the Composition Root. This is not a God object that does everything. No, this just builds everything. Well, the long lived everything. This is where you build the stuff that lives as long as the program. This is where you introduce them to each other. You know, the object graph. Once they're built and know each other you can call start() on one of them and get the whole thing ticking. And since none of them know that the composition root exists none of them care when I change it. If that's what you're doing, you're in good company.

Essentially EVERYTHING is contained in the 'platform' object p. Sometimes I have called it 'd' and the class name was 'device'... and then I'd have things like d->IO->SPI->init(&SPI_Init_LCD), or whatever. I like doing this because not only is it an intuitive structure that keeps things organized but it also helps me quickly find what I'm looking for using the editors auto-complete if I forget what I called something so I don't have to go looking for it.

Well, you can do that. It works. It's not new. Not if it's what I think it is. This sounds very much like a service locator. I wont say you shouldn't do it. But look into what people say about this and what they say about the alternatives. Then decide if this is what's best for you. The embedded world is different. But it's not that different.

But then, I'm old enough that embedded doesn't feel fancy to me. It just feels old.

"In my day we felt lucky to have 8k of ram. So roomy"

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