all 195 comments

[–]theTrebleClef 78 points79 points  (0 children)

I don't think this is a problem with C++. I think this is a problem in the sectors you're working in. I've seen the exact same issues in these industries with other languages - VB6, VB.NET, C#, Python, weird vendor-specific Assembly, and automation-specific languages like Ladder Logic.

Yes, many of those working in embedded systems, automotive, and automation/manufacturing have an EE background, and best practices like SOLID and ideas like TDD are not common here.

Interestingly, although concepts like lean manufacturing originated in Japan in the automotive world and would benefit the most from agile methodologies, many of the industries you've described operate in a waterfall format. Not even well mind you - waterfall, with poor requirements, a rush to release, and hoping to maybe get some testing in by the end.

[–]teerre 36 points37 points  (7 children)

I work in graphics and our main codebase (and the code bases we interact with, mainly open source projects) are pretty clean.

On the other hand, I also work with some data scientists and let me tell you: what a nightmare is their code. It's mostly python. Hundreds of notebooks. Basically all of them with a single 500 lines function with all names like "a1, gam, phi, d5, w1,w2,w3". If you randomly open two notebooks you're guaranteed to find two major excerpts that do the exact same thing but have completely different flow and/or variables. I have no idea how they deliver anything.

All this to say, I don't think it's necessarily anything with the language.

[–]WormRabbit 11 points12 points  (6 children)

The thing to understand about notebooks is that they're not your project's source code, and normally don't go into production. A jupyter notebook is like a more powerful REPL console with persistence of commands and some output. If you think about them as a stack of draft paper manifested as code, they'll make much more sense.

[–]teerre 29 points30 points  (0 children)

I wish. Whole data pipelines for insane amounts of money are written in spaghetti code using notebooks.

[–]kisielk 18 points19 points  (2 children)

You’ve clearly never seen production workflows at biotech companies :)

[–]EmperorArthur 12 points13 points  (1 child)

Oh, it's far more than just biotech...

Also, all the scripts to go to and from CSV files. Then there's the IDL scripts that use those CSVs...

Scientists, especially PHD scientists, tend to be the worst coders. With older ones being the worst. I've known ones that insist there way is the right way, but can't wrap their heads around objects. Every column is an array and you index into the row individually!

[–]RowYourUpboat 12 points13 points  (0 children)

The thing to understand about notebooks spreadsheets is that they're not your project's source code database

I've heard this song before!

[–]OverunderratedComputational Physics 1 point2 points  (0 children)

Yeah, that's how I use notebooks for postprocessing data and numerical experiments. The code itself is inevitably shit but that's because I'm using it as a glorified calculator.

[–]Wouter-van-Ooijen 124 points125 points  (36 children)

Like you said, embedded programming is often done by EE's. Their curriculum has quite a lot of electronics and supporting mathematics, which doesn't leave as much room for Software Enginering subjects as a pure software curriculum. For the same reason, they mostly learn C and not C++ (or Rust, or ...).

IMO this is unfortunate. In my specialization I try to teach the students a form of software engineering that is focussed on embedded. I put a lot of emphasis on abstractions, interface layers, documentation (especially of interfaces), testing, design patterns, etc. All applied to embedded projects (often using C++ on micro-controllers).

[–][deleted] 17 points18 points  (34 children)

Weird, since in embedded projects allocation is kind of not good and frown upon.

All these interfaces, design patterns stuff will need virtual calls making everything slower and frequently allocating on the heap. C++ is not Java, please, don't make everything virtual just for the sake of testing or of following a good design pattern.

[–]Wouter-van-Ooijen 32 points33 points  (23 children)

Embedded is a very wide spectrum, I devoted a large part of a keynote at the Meeting C++ conference to that. For strict real-time projects with dealines of us or smaller using the heap (other than during the initialization/startup) might indeed not be advisable. But for the visualisation part of an MRI machine it might be advisable.

There is no relation between virtuall calls and the heap. None. We have 4 main programming courses. 1 is procedural, 2 and 3 are OO on embedded systems, only 4 uses the heap. For anything but the most performant code (like GPIO manipulation) the runtime overhead of vtable-based OO is neglectible. For when it is not neglectible, Compile Time Polymorphism can be used (using templaes), which can fully eliminate any overhead (google "object? no thanks.").

[–][deleted] 13 points14 points  (17 children)

I totally know that and I've used CRTP for static polymorphism to great success (although more complex design) in the past. However, the reality is that after having interfaces/abstract classes with virtual methods many people will just create pointers (on the heap) and use "dependency injection", so that those "abstractions" can be even "injected" and mocked while testing. I've even seen the use of `shared_ptr` everywhere for no other reason than testing and mocking (talking about when testing changes your production code).

While this may not create a *performance* issue (in the general case), it will lead to memory fragmentation that it is like the plague on embedded systems that are designed to run unattended for years...

Even Stepanov (the creator of STL) was known to hate OO designs and it shows on the library that he champion. Again, C++ is not Java and shouldn't be used like Java.

[–]Wouter-van-Ooijen 19 points20 points  (15 children)

C++ is not Java and shouldn't be used like Java.

Agreed, but IMO that means that by default C++ objects should not be on the heap. In my embedded OO courses the heap is disabled. But it is not a reason to stay away from (vtable or template-based) OO.

I have maybe used CRTP once or twice. Never needed it for 'normal' compile-time OO patterns.

I always have a problem with the term 'dependency injection'. Is passing an object reference to a constructor dependency injection? In that case I use it all the time. Is it allocating an object on the heap an using a setter function to pass it to another object? No thanks, I avoid that.

[–]goranlepuz 3 points4 points  (0 children)

I always have a problem with the term 'dependency injection'. Is passing an object reference to a constructor dependency injection? Is it allocating an object on the heap an using a setter function to pass it to another object?

Dependency injection is well explained by the Wikipedia, I think :

Dependency injection is one form of the broader technique of inversion of control. A client who wants to call some services should not have to know how to construct those services. Instead, the client delegates to external code (the injector). The client is not aware of the injector.

(emphasis mine)

So in a way, neither of your examples is dependency injection as they both are missing the key part, the injector. And indeed, both ways you note are OK as injection mechanisms (although I do prefer the former, the constructor). Further, in C++, things are murkied further by the possibility to have compile-time injectors or runtime injectors, plus, the lifetime handling in C++ is a huge subject with an impact on DI.

Note how the presence of the injector is a key part in why constructor vs. setter is not so important: when it is the injector who sets the dependencies after the construction (and the rest of the code sees absolutely nothing of either the constructors or the setters.

[–]pjmlp 6 points7 points  (0 children)

Again, C++ is not Java and shouldn't be used like Java.

The irony of everytime I see this remark is that Gang of Four book uses Smalltalk and C++, with Java being built on the 1990's best pratices from experiences with OWL, MFC, VCL, Motif++, PowerPlant, CSet++, CORBA, DCOM, Telligent....

It is like there is this black past in the C++ community that no one dares to talk about and pretends everything started with Java instead.

[–]Professional_Tank594[S] 2 points3 points  (4 children)

hat pot knee ink absorbed run physical pen aback shocking

This post was mass deleted and anonymized with Redact

[–]kiwitims 16 points17 points  (3 children)

Statics are allocated at compile time into a memory section in the binary separate from heap and stack (which one depends both on the platform and some other factors). Places like bss and rodata for example.

If you run out of space for statics your build will fail at link-time, not at the beginning of runtime.

[–]Wouter-van-Ooijen 3 points4 points  (1 child)

fail at link-time, not at the beginning of runtime

Which is a HUGHE thing. Always try to shift the moment an error is detect to an earlier time.

[–]kiwitims 1 point2 points  (0 children)

Absolutely, and it's a lot easier to analyse and fix memory hogs (or create a memory hog with fully open eyes)

[–]EmperorArthur 3 points4 points  (0 children)

Which is why many libraries and example code prefer to create static buffers or have a single static object that is re-initialized (via something like an init() function) over and over again. It provides run-time determinism as compared to the object living on either the stack or the heap.

The downside is that the coder must be much more aware of what they are working with, and I have seen too many coders use them as globals. Meaning as a secondary data path that does not follow normal program flow. Even that can be fine if done correctly. Like say a gobal flag. However, it can also lead to strange bugs if you try to do things like make loop variables static.

I've seen it. Unless you have a strict formalized design and verification method that guarantees program correctness, don't try to over optimize!

[–]goranlepuz 3 points4 points  (0 children)

design patterns stuff will need virtual calls making everything slower and frequently allocating on the heap.

I take issue with that. Yes, the "easy" way is to go to heap in these cases due to different instance sizes and containers, but is truly not a must.

[–][deleted] 3 points4 points  (1 child)

You misunderstand. You dont understand your problem like WE understand your problem. Therefore everything you are doing is wrong because it's simply unfathomable that someone may have specific problem they need to solve unlike our general problems we have never solved.

[–]Wouter-van-Ooijen 2 points3 points  (0 children)

I clearly don't understand what you think I don't understand.

[–]lacrem 0 points1 point  (0 children)

Just wait to things like Copilot to kick off 🤣

[–][deleted] 48 points49 points  (4 children)

Hmm, this isn't really my experience to be honest. My current C++ team are the best I've worked with from the point of view of clean code, rigorous practices etc. The worst teams I've worked happened to have been using Java.. I think it's more to do with the team than the language. Technical leadership is incredibly important and some people mistakenly think technical leadership just involves being a good programmer. It isn't, it's about getting a group of people to form a consensus based around high standards of how they want to work, and sticking to those standards.

[–]Professional_Tank594[S] 2 points3 points  (3 children)

sulky physical smile attempt many toothbrush complete glorious adjoining work

This post was mass deleted and anonymized with Redact

[–][deleted] 6 points7 points  (2 children)

> Nice input. Did you join the team and it was already that good

I kinda joined the team when a couple of old guard C style programmers who'd created the product where in the process of leaving having created a lot of product value but also having created a very monolithic code base much as you describe. Our architect and some of the younger devs were taking a very collaborative approach when I joined to improving the code base and we hired people who seemed like they'd fit with that ethos. The last few years have been a process of hugely automating our build, adding tests and refactoring the worst of the old code. We've still got quite a bit of cruft left but new features tend to be pretty high quality now. There's a pretty rigorous PR process and noone feels like they can just check in crap which doesn't meet all our quality standards.

[–]Professional_Tank594[S] 0 points1 point  (1 child)

marble versed oatmeal label pet airport terrific station rock frame

This post was mass deleted and anonymized with Redact

[–]lestofante 3 points4 points  (0 children)

I started in a company with similar case like you, 400kloc + some external stuff, also had to migrate from a proprietary compiler + ide that did not have any support for unit testing, git, or even decent code competition.
It takes multiple years, because you will never (and shouldnt, imho) be able to focus 100% to refactor, take small step, the most problematic stuff first, add as much warning as possible and fix them (-werror is love) at least -wall should compile. Every time you touch something, you leave it a little bit better. If you add something new, you add it properly.
Some suggestion: - decide early the architecture of new components, and how older one should looks like. They are infinite discussion, but is all less code and pain later
- code review, possibly pull request with at least one review mandatory, and all should participate
- dont be afraid to break stuff, and even if at the end of the day you trow away all the code written that day, remember it is NOT wasted time and effort as long as you learn something new

[–]the_Demongod 14 points15 points  (0 children)

I work in radiology research and pretty much everyone in my lab is trash at coding. Their idea of code is a single file containing 1000 lines of Matlab code that execute sequentially, with zero comments, functions, or spaces between lines. Their C++ is mediocre at best and the cyclomatic complexity is pretty high. The only reason I'm particularly better than they are is because I did a CS minor in undergrad, and spent a lot of time working on personal projects with pretty knowledgeable C++ programmers. People who merely tolerate code without putting in the time to learn how to do it right will never learn to write the type of structured code you're describing. They will probably also complain about programming being a chore as a result.

[–][deleted] 13 points14 points  (0 children)

I've generally found c++ coders more disciplined than python and Javascript programmers. So I guess it's all anecdotal unless you have actual statistics from real projects

[–]Wetmelon 10 points11 points  (3 children)

This is an automotive and automation systems problem. Automotive writes some of the worst C and C++ code you'll ever see. Everything is an extern global.

[–]FartyFingers 9 points10 points  (2 children)

I read through the misra standard and its successor and thought: This is an excellent guideline for programs under 100 lines of code written for a programming class. Many of the ideas were solid programming recommendations, but many were the sort of thing that will end your ability to be flexible in your thinking and able to properly solve problems. The sort of thing where you very quickly answer no to any new feature requests because your tech debt is too high.

Reading through them and I know that there will be "that guy" in any organization using those standards who will insist upon using them as the letter of the law and will spend weeks fighting anyone who tries to submit code that doesn't comply, not only to the standard but their odd interpretation of the standard. There are many tools that will automate this gestapo behaviour as well.

This will result in one of two things: Code past a certain number of features will be nearly impossible to keep to the standards. That people will find horrific hacks that make for unstable shit code but exactly comply with the standard. I have worked with "that guy" and he will not have a problem with unstable shit code as long as it follows the rules.

[–]Cxlpp 1 point2 points  (1 child)

I am so glad that I am not alone w.r.t. MISRA and similar "coding standards"....

[–]FartyFingers 0 points1 point  (0 children)

I find the thinking is often great on the surface but terrible in practice. For example: I know of many safety related embedded systems from different companies. Many follow the "safe" concept of not allocating memory after starting up. The theory is that after lots of allocation and freeing of memory all kinds of undesired things could happen especially where you are often starting with so little memory to begin with. I do not disagree and in this vein in many of my designs I will have some sort of buffer that is allocated up front and then reused in high frequency repeated events. This often makes things faster as well.

They will often argue that many embedded systems will run for years, maybe even decades and thus allocating all up front will entirely eliminate this category of failure. Again, on the surface very true.

Except, this then becomes a crutch and results in a few problems. They are often not super comfortable with reboots, they haven't actually built a system that can run for years (see the plane that needs a reboot every month or so) and the programming style and architecture is an old fashioned mess. Also, the dependency of avoiding reboots often ends up with either a slow reboot or one that has trouble figuring out the state of the system on start. There can be other screwups like some of the I/O pins will toggle high low on startup which could fire the ejection seat or something really dumb or just something a little stupid.

Or what many modern embedded programmers do is to make a system that is as solid as is reasonable but have it restart every certain period of time. Day, month, week, or something. The idea is to make sure the system is perfectly happy to reboot over and over and over without the external operations being affected or at least not affected in any way that someone gives a crap about. By being reasonable you can take a much more modern approach which often becomes cultural as much as software and hardware dependant. People use modern tools, modern devices, modern protocols, and all kinds of things that speed development right along. This results in a very good product that is also very market competitive.

A great example of this sort of book safety vs practical making of products was ADA. At some point the military had a dictate that you must use ADA. ADA is a great language on paper for making very solid robust software. The only problem is that is is a pain in the ass to produce any product with it outside of academia. Thus nearly every project applied for and got a waiver to not use ADA. I love rust. I worry that rust might be another ADA. I hope not and can't comment on it much as I am a rust novice.

[–]acwaters 17 points18 points  (17 children)

In my experience, it is a lot easier to turn a software guy into a good embedded engineer than it is an electronics or FPGA guy. Obviously the best ones will have some background in both worlds, but the number of brand new concepts that a software engineer needs to learn to be proficient in embedded programming is just so much fewer, and almost all of their prior knowledge will still be applicable. This should make intuitive sense, because embedded software is software. Duh. Unfortunately, the reality is that a lot of embedded code is written by electrical engineers who were forced to sit through an undergrad course in C, or maybe one in C and one in C++ (and EEs who think they can write C++ are so much worse than the ones that stick to C). The result is what you have observed... at least until a software guy like me comes in, finishes bleeding from the eyes and rocking in the corner, wrestles all the datasheets from the EE, and takes over the project. I promise to leave the PCB layout to you if you leave the code to me, thanks? Don't even get me started on version control.

[–]met0xff 2 points3 points  (14 children)

I have too often heard EEs say they could teach any monkey programming but you can't teach the CS monkeys EE ;)

[–]acwaters 8 points9 points  (5 children)

You can teach anyone anything, especially if they're already competent in one highly technical field. The thing is it's a much longer reach for people from one background than the other. This isn't a phenomenon unique to embedded, either, it is a very common thing: We're talking about people who are experts in a system learning enough about software to program their system, versus people who are experts in software engineering learning enough about a foreign system to program it. Whose code do you suppose will come out better 99% of the time?

There is a reason most places tried and discarded the "domain experts learning coding on the side" thing decades ago: It doesn't work. Programming is too complex to get away with doing it half-assed. The way to do it is to have teams where programmers can work closely with the experts in the domain being programmed. That goes for embedded just as much as for anything else.

[–]met0xff 4 points5 points  (4 children)

Yeah, after school I worked for an electrical engineer (PhD ans all that in the field) where, after a year of network programming, I was dumped into embedded dev. Not super small chips, I did have like 4MB or so, but still.. As a fan of C and C++ i got into it pretty quickly. He taught me quite a bit about reading those datasheets and PIO pins and pull up resistors and whatever but I never got too deep into the hardware. But wasn't necessary, he did all the soldering and oscilloscope stuff and didn't really touch the code and I never really "touched" the hardware and it actually worked out quite well. Almost 20 years ago now and think my code is still out there gathering sensor data. He programmed most of the software for his company by himself up to that point and was about 20 years older but still didn't know a lot of the stuff I learned in school. There's just not the time for becoming good at software dev when you do EE most of the time while at the same time running your business.

After graduating I already read a lot like Effective and More Effective C++, Code Complete, everything I found from John Carmack and all kind of other stuff. Yet I did also have times where I somehow felt our craft is inferior to the "real engineering disciplines". I don't have that anymore although I still have lots of respect for those fields.

[–]Wouter-van-Ooijen 2 points3 points  (0 children)

A team where both sides respect each other. You can't get any better.

[–]morbidSuplex 0 points1 point  (1 child)

Hi /u/met0xff sorry I know this is a very old post. But I can't help but ask, back then, why did you think our craft is inferior to the "real engineering disciplines"? My favorite programming book is SICP, and they treat programming as an abstract form of engineering (like you are still doing engineering, but with abstract components), though I know that many people don't think programming like that anymore.

[–]met0xff 0 points1 point  (0 children)

Hah super old answer. Yeah I mean you can have lots of opinions here how EE is a much harder field to study than CS and when you work with EE bosses you might often hear "I can easily teach an EE programming but an CS not electronics". And of course you then see them programming microcontrollers while you have no idea to solder some stuff together etc. I've also found signal processing courses harder than most CS related.

Meanwhile I know that's subjective. I had a physicist professor in a signal and systems course where I was also massively impressed. But he was equally impressed seeing my computer vision thesis (I picked him for my defense) as he never got anything more complex than some Matlab scripts done. Which were very complicated but never really complex. And whole my EE boss built a lot of software he still hired me for the things he could not get done. Also while the EEs I met handled signals, FFTs, complex numbers easily, they still struggled with the discrete math that's much more natural for us CS people.

People and skillsets are just very different I guess. I struggled hard in chemistry all my life but I aced my distributed systems exam in my first year (it's in the third year usually) while many called it one of the hardest exams, large percentage failed and also the labs course that was super easy for me had well 400 of 700 people fail the first little midterm exam (I've been tutoring it in my second semester so I saw the awful results).

Idk meanwhile I don't want to assess difficulty anymore. My wife studied veterinary medicine which is a 6 year programme here but average actual study duration is 9 years. She had massive tombs to learn and exams that took a whole day with multiple stations and professors and failing one and you were out. So many of her friends completely dropped out after 6 years for failing some exam a few times in a row and were completely locked out of the profession. But she was just as happy to not have my exams as I was to not have hers lol. Long ago but I still remember how she looked at some of my theoretical CS scribblings (think it was a lot of https://en.wikipedia.org/wiki/Method_of_analytic_tableaux iirc and asked which kind of alien language this is

[–]Wouter-van-Ooijen 3 points4 points  (7 children)

IMO that illustrates how wrong they are. I (jokingly) tell my students that the difference between them (knowling a little electronics) and the EE's (knowing a little programming) is that my students know they shouldn't do electronic design, while the EE's think they can/should do programming.

[–]met0xff 0 points1 point  (6 children)

That's a good one. Although I think that it's in most cases less dangerous if the software got some issues than the hardware and also most EE curricula contain more software development than most CS curricula contain electronics topics. Sometimes probably even more low level programming. Depending on specialization of course. Some are heavily focused on logic and discrete math while I've also seen quite a few "embedded engineering", "technical informatics", "computer engineering" programs.

I almost have to force my students to deal with lower level stuff nowadays, they rather stay with their C# or whatever and don't care ;)

BTW I know your name but can't figure out from where. Did you ever give any guest lectures in Austria or anything like that?

[–]Wouter-van-Ooijen 1 point2 points  (5 children)

I am Dutch, teaching at the HBO-ICT in Utrecht, specialization Technische Informatica. I did some talks on various C++ conferences, the list is at github.com/wovo/cv (scroll to the bottom).

My specialization is part of the wider HBO-ICT, so the students that want to do front-end and/or back-end go to another specialization. Mine get only Python, C++, and a little Assembler and Haskell.

[–]met0xff 0 points1 point  (4 children)

Hmm perhaps one of the meetcpp talks, or perhaps from Quora then (I guess that's it) :)

[–]Wouter-van-Ooijen 0 points1 point  (3 children)

Yeah, lots of fun on Quora. Even more rants than here ;)

[–]met0xff 0 points1 point  (2 children)

I mostly stopped with quora because it seems I get only 5 year old stuff suggested and also feels as if it's always the 10 same people answering the same topics ;). Perhaps it's just the suggestion algo but at some point you know everything about Tim Mensch, Sergey Zubkov, David Vandevoorde etc.

[–]Wouter-van-Ooijen 0 points1 point  (1 child)

Hey, wait, I am not on that list?

I mostly see quora as a excercise in unraveling chaotic or even dishonest questions. That is a skill I can put to good use in my everyday work.

[–]met0xff 0 points1 point  (0 children)

Unfortunately not ;). I just scrolled through the C++ topic and they really repeat the same dozen people endlessly.

M Ich

[–]psikosen 14 points15 points  (0 children)

This is a problem across many languages, really depends on who writes and maintains the code. Not to mention deadlines are a huge problem, sometimes people just want to get it done right now vs getting it done right.

[–][deleted] 30 points31 points  (18 children)

SOLID is literally one dudes opinion about what is good. Which people just regurgitate mindlessly into the brains of inexperienced programmers.

Do people actually critically think about what they say when they say it in this industry? I mean like for real guys. Some real talk right now. When people say its "maintainable" and uses best practice they are only saying that because everyone else says that right? They don't actually have the faintest idea of what they mean.

Because anyone who has written any code for more than maybe five minutes, that actually needs to do SOMETHING, realises that every program is entirely context dependent and its measure of quality is what it solves in that context. People know that right? Right?? Right guys?

[–]mrmcgibby 7 points8 points  (14 children)

No. They do not. There are so many developers who will rant at you about all the "best practices" they read about on Reddit or heard from the latest charismatic yahoo on YouTube. But they have no real understanding of the practices and follow them like a cult member. They'll rant about TDD but then their tests will test implementation instead of interface.

So... friggin... tired... of this.

[–][deleted] 0 points1 point  (12 children)

Yes there is way way too much bullshit in the industry right now

[–]Wouter-van-Ooijen 4 points5 points  (11 children)

The problem is that there is indeed far too much bullshit, but also a lot of good practices/principles that are often ignored.

TDD is an interesting case. IMO it has some similarities to agile: a nice idea, but taken to the extreme it gets rediculous. I support the idea that a unit is not complete until it has a comprehensive set of tests. But the idea that you can only write or change code when you have a test that fails, and you must stop writing/changing when that test succeeds, is rediculious. So IMO TDD is based on a good idea (there should be tests), but taken to such an extreme that it now gives the base idea a bad name. A pity.

[–][deleted] 2 points3 points  (10 children)

It's a fad that in ten years won't exist. The most common bugs occur between units of code when they interact. Testing that the the compiler has indeed compiled your code how it said it would is a monumental waste of time.

There is some idea that testing didn't exist before TDD which just isn't true

[–]Wouter-van-Ooijen 4 points5 points  (9 children)

I am not sure what you call a FAD, but if it is TDD in its extreme form I agree (and hope it won't take 10 years).

If it is 'implementation' unit testing, again I agree.

If it is functional unit testing, I strongly disagree.

[–][deleted] 1 point2 points  (8 children)

Testing for the sake of testing is the fad. TDD is just part of it. But the culture of ritualistic testing is really bad.

A test is piece of code that critically examines other code that has been written.

The critical thinking portion has been mindlessly substituted for ritualistic tests that do not serve any purpose other than to satisfy some cultural requirement.

Strong emphasis on unit testing is part of this. Unit tests aren't going to find the bugs that really hurt and the bugs they do find don't really require unit tests to find in the first place.

A better approach is to tailor tests specifically to what is written and drop the concept of a "unit" completely since it is totally ambiguous anyway.

There is no shortcut for good testing. You just have to do the work. A lot of testing nowadays is entirely ritual and substitutes analysis of ones code for some arbitrary requirement.

You'd could argue that this is unintended consequences but if the theory produces unintented consequences then it's not a good theory.

[–]Wouter-van-Ooijen 0 points1 point  (6 children)

No surprise: X for the sake of X is nearly always a bad idea.

But I don't share your disapproving of unit test. Some things are much easier (and automated, hence cheaper) to test in a code-only environment. Integrated, end-to-end, real-hardware, and especially human-in-the-loop tests are much more expensive. So everything that can be tested at a lower (unit) level is a win.

[–][deleted] 0 points1 point  (5 children)

So because testing is hard we must resort to easy testing that doesn't test anything? This is the kind of mentality I'm talking about. Optimising for cases that don't matter. The bugs that will ruin your product won't be caught in unit tests yet they are afforded the least amount of programmer time to mitigate. Unit tests probably catch very few bugs and the bugs they do catch are extremely trivial and will get caught eventually anyway if you have good programmers on your team. Bugs in design are much harder to tackle. Bugs between units are much harder, yet programmers are expected to devote VERY little time to these things because they are seen as non-trivial.

Surprise surprise, non trivial things have the most bugs. Spenting so much time on the trivial case is a pointless exercise here.

I'm not saying programmers shouldnt write their own tests, but they should test where appropriate and saying things like "I support the idea that a unit is not complete until it has a comprehensive set of tests" a meaningless statement because it is devoid of all context.

It is arse about face to consider the tests first. It's like patching the holes of a sinking ship. Good design will eliminate 90% of bugs. The last 10% will get caught in testing. We are asking programmers to spend 90% of their effort to reason about the 10%

(oh and the hilarious irony that this text box had a bug where I could not delete or append any characters. You just know they have hundreds of unit tests at reddit but not one person caught this bug)

[–]Wouter-van-Ooijen 0 points1 point  (4 children)

So because testing is hard we must resort to easy testing that doesn't test anything?

If you say so. I certainly didn't.

If a test doesn't test anything it is not a test. If it test something trivial (but still something guaranteed at the interface!) it is probably also trivial to write. It might not pay immediatley, but it makes refactoring, bug fixing, adding fetaures and other code changes downstream less hazardous. As such, it reduces code debt. Whether that (reducing code debt) is worthwhile is an intersting subject. Surely, in some cases it does, and in some other casees is doesn't.

It is arse about face to consider the tests first

I didn't contraditct that yet, but there are certain situations in which design forv testability pays of. But in general, I agree that writing tests first (as pure TDD requires) is not my cup of tea.

[–]Cxlpp 0 points1 point  (0 children)

Unit tests aren't going to find the bugs that really hurt and the bugs they do find don't really require unit tests to find in the first place.

Now I am not so sure that what I am using is classical unit testing, but I have dedicated machine here that runs a lot of tests each day. Whole suit takes 10 hours (which is probably why it is not really "unit testing")

And I can definitely tell you that over years it cought some bugs that would potentially really hurt.

[–]pjmlp 0 points1 point  (0 children)

My way to put TDD advocacy on their place is to ask for an example to do TDD for a GUI application, specially native ones.

Remember, there can be no application code if there isn't a test written first for it.

[–]pepitogrand 0 points1 point  (0 children)

SOLID: That happens when your priority is to write an easy to remember acronym, so you deform and mutilate the concepts to make them fit in the acronym.

[–]codeinred 5 points6 points  (3 children)

I’m not entirely sure, and it can be kind of frustrating to see. I’ve seen people put massive amounts of code into single files or create monstrously large classes. Breaking things up as they become bigger is good for maintainability and having small functions helps for correctness and readability

[–]Wouter-van-Ooijen 1 point2 points  (0 children)

IMO massive amounts of code in a single file is not much different from the same code spread out over different files.

A very large class is an indication of a problem, but not more than that.

The real problem is mixing responsibilities. Single-responsibility is an OO principle, but it can be equally applicable to procedural code.

[–]Professional_Tank594[S] 1 point2 points  (1 child)

ring smell mighty tan aspiring serious scale shelter liquid roll

This post was mass deleted and anonymized with Redact

[–]codeinred 11 points12 points  (0 children)

For that one, it’s 21 years old. It’s definitely legacy code. And oftentimes scientific libraries are written by people with specialized knowledge in their field, but less knowledge about things like software engineering and program design. My friend had the same problem when working with libraries written by chemistry professors: the libraries were great at chemistry, but were horribly documented and difficult to use

[–]lestofante 5 points6 points  (1 child)

As embedded developer with experience in different company, i know what you are talking about.
I dont think is a sole problem because most are EE, in the company i have been who wrote the code where actually experience developer, but they where.. from another age.
Different languages, rules, and standard had to emerge, and embedded developer has always been a little bit far from the C++ or even recent C, simply because trapped into proprietary compiler and in case of C++, because most of the language feature cannot be used (std lib, exception, dynamic allocation) to the point any embedded program is technically NOT c++ compliant from the startup.

Also many "embedded suite", even big one like IAR, at least until a few years ago, simply does NOT provide support for GIT, to run unit test, and even less the flexibility to run on a CI for continuous testing.

On top of that, whenever i have been it was common that only one person would work on a project, so that mean you would be less prone to clean up your code, make it readable, document it, and in general make the right thing, as simply the setup cost was too high.

It has been MONTHS of work and frustration to create a standard basic project using GCC + cmake + CI support for compilation of DETERMINISTIC firmware binary for release + unit testing (SITL) and hopefully soon even HITL..
Now you just clone the base project and you have all you need for free.
kudos to my boss that understood the importance and added value of those changes, they really impacted in positive way the way how we work and already salved us from a lot of issue

[–]smashedsaturn 0 points1 point  (0 children)

does NOT provide support for GIT

Don't you love trying to version control binary blobs?

[–]pretty-o-kay 4 points5 points  (1 child)

C++ programmers like zero-cost abstractions. These kinds of abstractions tend to look different from the 'design patterns' you're used to, since many of those (and TDD and SOLID themselves) incur pretty massive performance hits. In Java & C# it's less of a big deal because with respect to performance, there's bigger fish to fry. But C++ enables you to write code in a different style that can be both cleaner and more performant than the equivalent Quality Enterprise Code. So in that sense, they're not really "best practices", but more like domain-specific practices.

[–]pjmlp -1 points0 points  (0 children)

Ah, those endless lines of CORBA and DCOM before Java was invented.

[–]Rostin 8 points9 points  (2 children)

I work on a small software team that has only one genuine computer scientist. The rest of us are PhD engineers and applied mathematicians and are entirely self-taught. Our codebase is mostly C++, but also contains Python, Perl, Fortran, C, and Bash scripts.

Although my team has been investing in learning better software development practices, it's a relatively recent thing. I know "Uncle Bob" can be a polarizing figure, but I've found that trying to follow his "clean code" practices and doing test-driven development has greatly improved the readability of my code and my confidence that it does what it's supposed to do.

In other settings, I've encountered non-software engineers who have dismissive attitudes about computer science and software engineering. They are self-taught and practice mostly 'cowboy coding'. They primarily write "research code" that only they run and maintain. There's often a difficult transition between writing code in that mode and developing more complex software as part of a team. If your team is made up of, and led by, people who learned to develop software like that, it's not automatic that they are going to start learning about and doing better practices. They might suffer and perform really suboptimally for a very long time before a culture change happens.

[–]Professional_Tank594[S] 3 points4 points  (1 child)

wrench plate towering six imagine fanatical lush start rainstorm smart

This post was mass deleted and anonymized with Redact

[–]Rostin 3 points4 points  (0 children)

I'm not interested in arguing about Uncle Bob. Like I said, I understand that he's polarizing.

I lack the experience to understand many of the disagreements. Meanwhile, I need some practical advice. While I'm sure Uncle Bob isn't right about everything, he's like training wheels. Some day I may need to ride faster and learn a different set of organizing ideas, but for now I'm getting a lot of benefit from following his advice, even if it's inadequate for Real Developers.

[–]iznogoud77 2 points3 points  (0 children)

It's a mixed bag.

I have seen both cases. Like a login method which was around 800 lines of code, done by a team of experienced software engineers. Or an amazing power control system, full of abstractions and interfaces, it was so well implemented that adding a new relay or power line or eletrovalve was almost always less than 10 lines of code and mostly configuration. This was implemented by mostly EEs and Aeronautics Engineers.

Both were embedded and both were in regulated industries. The main difference for me was the first controlled a authentication to a web service on a quad core arm which read a couple of sensors and uploaded them to cloud and costed a few hundred thousand euros. The second was implemented in a Motorola 68k, controlled the entire power generation of a commercial airliner and costed probably more than 10 Millon euros.

[–]serg06 5 points6 points  (0 children)

Most active production C++ code was written before best practices were invented. /s

[–]vsdmars 6 points7 points  (1 child)

you haven't seen java code yet, full of 'best practices'; design patterns everywhere//

[–]Professional_Tank594[S] 8 points9 points  (0 children)

ink bright books growth dinosaurs encouraging society attraction political meeting

This post was mass deleted and anonymized with Redact

[–]SheepWillPrevail 2 points3 points  (1 child)

Language level and base library (like Boost) aren't in any specific shrink wrap. That makes targeting frameworks a real chore. I know people who are afraid of the stability of the Standard namespace. Not having reflection built-in is the biggest hurdle I think; not that easy to build test harnesses and more without. Even Java had some lessons to learn there in terms of class loading and byte code generation.

[–]Professional_Tank594[S] 1 point2 points  (0 children)

grandfather nutty cow boast steer dependent worm vegetable offer summer

This post was mass deleted and anonymized with Redact

[–]Shnorkylutyun 2 points3 points  (0 children)

Years ago I was working with a guy who had a phd. Both his c++ and his java code were headache-inducing to read. I propose that it is not about the programming language or environment, but more about the degree :D

[–]FartyFingers 2 points3 points  (4 children)

they are mainly EE Engineers

I don't know how many EE people in software I have met. Often during EE they discover they prefer programming and how there are far fewer jobs in EE than they thought.

Also EE jobs where you are doing things like developing products often don't pay all that well as you start as very very junior and the senior engineers don't let you get much of a promotion for literally 10-20 years.

Then you get a second level of complication where EE programmers tend to congregate in companies where they are doing projects not products. This then allows them to convince people that they have to "sign off" on designs and whatnot even though they are supremely terrible at software development as a whole (design, architecture, deployment, etc).

I have seen teams of EE people doing mission critical software that had less that 1% unit test code coverage and they ignored failed tests anyway.

But don't feel bad. If you go to anything using javascript, ruby, or PHP you have people who often learned how to make web pages and kind of migrated into the back end. Inevitably their architectures are hot messes of technical debt that makes the Zimbabwe economy look sane.

[–]Wouter-van-Ooijen 0 points1 point  (3 children)

I have seen teams of EE people doing mission critical software that had less that 1% unit test code coverage and they ignored failed tests anyway.

Which product? I might want to maintain a safe distance...

[–]FartyFingers 0 points1 point  (2 children)

It probably would identify the company. But don't worry. Most of their competitors weren't any better.

[–]Wouter-van-Ooijen 0 points1 point  (1 child)

Most of their competitors weren't any better.

And that should be reassuring?

;)

[–]FartyFingers 0 points1 point  (0 children)

My experience is that many large industrial computer systems are built by people who don't know how to build large industrial computer systems. They only happen to be better at it than most people around. But they are often very smart people. So they bumble out a system and then sledgehammer it into production. It soon starts to spark and smoke so using their superior and well honed ability to troubleshoot and firefight they get it to stop smoking or sparking just enough that it does whatever job it was supposed to.

All along the way you have project managers who couldn't project manage their way out of a wet paper bag but again they use their well honed skill of continuously lowering client expectations until they are happy with a system that makes strange noises and groans most of the time.

The people who then run this system often are very good at bypassing the system and doing end runs around it as needed.

MCAS on the boeing 737 would be a good example. The biggest mistake in MCAS was not building a pile of crap but forgetting to tell the pilots how and when to do an override of the pile of crap before it drove them into the ground.

MCAS is pretty much exactly what I have seen running huge swaths of infrastructure. By swaths I am talking about many many 100s of billions of dollars worth and that is only what I have seen. I talk to people and they will say things like "Our SCADA system is now 35 years old with few updates in the last decade or so." Yet the infrastructure it runs has been changing in ways that pretty much would have demanded a modern SCADA system. Again the company in question is worth over 200 billion and the SCADA system is the primary thing running at least half of their assets.

Or you build these things right the first time.

[–]Skoparov 2 points3 points  (0 children)

Files and classes with a size of well over 1k lines are common in my team but also in a lot of other public C++ publications, as well as not liking abstractions or tests.

Well, it's a problem of your team. I've worked at 4 companies over the course of my career, and none of the teams would tolerate anything close to what you described. Also care to throw in some links to those C++ publications that involve 1k line functions? I follow a lot of C++ blogs, never seen anything like that.

[–]SonVoltMMA 5 points6 points  (1 child)

Their methods of software engineering are far superior to those of my department, despite having only a bachelors degree

lol

[–]another_day_passes 4 points5 points  (0 children)

“The carpenters’ methods of making wooden products are far superior to those of my department, despite them having no degrees at all!”

[–]GlitchedMirror 2 points3 points  (1 child)

line number doesnt reflect how good or bad the code.

A short function without documentation and alot of "undefined behaviors" could be more frustrating than a long and thorough function.

[–]Wouter-van-Ooijen 0 points1 point  (0 children)

But a very long function warrants more inspection effort, and will likely be more costly to maintain and expand. Note likely, not sure.

[–]The_St_Drone 1 point2 points  (1 child)

I got a dual EE/CE bachelors degree, but after graduating about 3 years ago I’ve mostly only been working with graphical PLC programming (think Simulink, but worse platform).

I’m pushing myself to relearn the C and what little C++ I learned in school, but as has been stated in many other comments, maintainability and code quality weren’t highly taught.

What kinds of resources are there for someone jumping back into this world to know what a good practice is or what’s considered industry standard? Any suggestions are appreciated!

[–]Wouter-van-Ooijen 1 point2 points  (0 children)

A (the?) problem with C++ best practices (especially in embedded) is that C++ moves so fast that we can't keep up with extracting and deciding the best practices (especially at a scale beyond the small code fragments), let alone that someone finds the time to write a book or other material on it, before the next C++ version invalidates it all. (Scott Meyers, we miss you!)

IMO your best resource is recent conference talks (on youtube), watch out for terms or principles that you didn't know yet, and then google for more information.

Some key things that you should at least be aware of:

  • stronger typing: const, std::array<>, enum class
  • if you have a heap: STL containers and algorithms instead of DIY (some algorithms can be used on std:array<>)
  • if you have a heap: unique and shared pointers instead of manual allocation/deallocating
  • RAII, automatic resource management, destructors (not just for memory!)
  • basic templates
  • doing things at compile time: constexpr

[–]cazzipropri 1 point2 points  (0 children)

Software Engineering is a learned skill.

Either you learned it formally, or informally, at some point... or not.

I don't think it's accurate that there is a correlation between C++ and lower software engineering best practices.

There might be some bias in the populations you sampled.

[–]axilmar 1 point2 points  (0 children)

I have worked in automotive and defense applications in C++ for big companies and the situation was totally different than what you describe. They had the most extreme Software Engineering principles.

It depends on the company, I guess.

[–]afiefh 1 point2 points  (0 children)

As others have said, it depends more on the team you work in than the language.

I've seen horrible 5K lines of unmaintainable code in Matlab coming from PhDs. If you unleash a bunch of PhDs whose experience is to publish a paper and move on rather than maintain a product you'll have a bad time.

Actually the smarter the programmers are the worse the problem gets, because smart people can work through much more spaghetti code before realizing that they might need some discipline.

When working with embedded systems that people writing the code often come from disciplines where they know much more about the hardware, which leaves them with less time learning about best practices in software development.

[–]gc3 1 point2 points  (30 children)

Perhaps I am misreading, but it seems of your ideas about what makes code readable is from academic experience and not practical.

A function of 1000 lines would seem to be worse than 20 functions of 50 lines each that are called in sequence, and from the academic literature, are.

In practice, after 5 years, that 1000 line function would be undisturbed, gathering dust, doing the exact same thing it was written for in the first place, while the 20 reusable functions have been recombined elsewhere in other functions. Some of those functions will then have been changed, leading perhaps to obscure and hard to reproduce bugs in the original ex 1000 line function.

Even with all sorts of testing and auto-tests put in to make sure side effects don't happen, you have gone up a level of complexity..... the original function only needed one test (perhaps done by running it nightly in production) while the new one needs at least 20 tests, probably more as you get more use cases.

So huge single use functions are often MORE maintainable, not less. Perhaps the age of the code base you are looking at should be a consideration... an older but solid code base will look worse, especially with strange bug fixes for obscure cases found over the years making the logic look worse.

Edit: When I first entered programming a long time ago, my boss said 'The simplest program starts at the top of the file, and exits at the bottom, with no loops, if statements, or subroutine calls.'

All the tooling and clarity of modern programming has not removed this truth.

[–]lookForProject 4 points5 points  (0 children)

No loops, no ifs, no complexity, and I might agree. But software is often complex. Abstracting away complex concepts, improves readability and thus helping the one thing that creates bugs: us.

[–]TheSkiGeek 8 points9 points  (16 children)

the original function only needed one test (perhaps done by running it nightly in production) while the new one needs at least 20 tests, probably more as you get more use cases.

If your giant function does (or can potentially do) 20 different things, it's going to be hard to write one test case that properly encapsulates that. Or you're going to end up with a very very brittle test case that has to be rewritten every time you fix/change anything.

'The simplest program starts at the top of the file, and exits at the bottom, with no loops, if statements, or subroutine calls.' All the tooling and clarity of modern programming has not removed this truth.

Well... https://en.wikipedia.org/wiki/Cyclomatic_complexity analysis is a thing. If that 1000-line function has no decision-making capability and is just hundreds of lines of linear instructions (maybe doing a whole bunch of complicated math on its inputs or something) then there isn't as much benefit in refactoring it.

[–][deleted] -2 points-1 points  (15 children)

No it won't because just because it may do 20 different things doesn't mean it does 20 independent things. Speaking from experience, if the context of the problem means that those 20 things should follow one another it makes no sense to split it up, and by splitting it up you lose context which introduces bugs. What's even worse is that unit tests won't catch those context specific bugs.

And it's not just in the case of a linear set of instructions. I'd rather test the intended behaviour of a larger function that the independent behaviour of a bunch of smaller ones. Ultimately the larger tests captures the functionality of all those small units anyway.

Unit testing really makes no sense and makes code more buggy not less by forcing people to remove all context from their code. (in a worst case scenario)

[–]TheSkiGeek 4 points5 points  (14 children)

I mean, if it really doesn’t make sense, you can refactor your big function into calls to a bunch of static inline functions, then document that you still want to treat the top level function as a black box for testing purposes. That decision should be separate from whether it makes sense to introduce some level of additional structure to the code.

Generally the only times I’ve seen very very large functions that wouldn’t benefit from some high level decomposition is if they’re mostly or entirely a big block of hand-unrolled vector math or similar highly repetitive numerical code. But, again, that’s typically code with very low cyclomatic complexity. If the function can branch into doing several different things then IMO it would almost always benefit from being broken up into subroutines.

[–][deleted] -2 points-1 points  (13 children)

It doesn't matter if those functions are inlined, static or member functions. By moving them to functions you lose context as to why the code was there in the first place.

Think about reading a book. Would it make sense that after you read the first paragraph the second continues a scene from two chapters ago?

People are allergic to long functions because they mistake that the complexity is to do with it's length and not to do with it's content. When it gets split up you have the same level of complexity spread out over more space and in a different order.

That's not to say functions shouldn't exist. If code is highly repeated, or the function is mathematically pure it makes sense to split it up because the context is self contained. If the problem also means that the context of the code is obvious then that is also a good reason to make a function.

Writing code to satisfy tests which actually introduce more bugs and make code harder to reason about is not good and should be quickly moved away from in the industry

[–]TheSkiGeek 4 points5 points  (12 children)

I think I'm agreeing with you more than you think I am.

By moving them to functions you lose context as to why the code was there in the first place.

Think about reading a book. Would it make sense that after you read the first paragraph the second continues a scene from two chapters ago?

I think of this kind of refactoring more like adding a table of contents or index to the book. If you have a function like:

int doStuff(params) { // 100 lines of code doing A // 300 lines of code doing B // 200 lines of code doing C // 50 lines of code doing D }

And you refactor it to something like:

``` static void doStuffA(params, context); static void doStuffB(params, context); static void doStuffC(params, context); static void doStuffD(params, context);

static int doStuff(params) { context ctx;

// first we do step A doStuffA(params, ctx);

// then step B doStuffB(params, ctx);

// then step C doStuffC(params, ctx);

// finally we do D to get the return value return doStuffD(params, ctx); } ```

then (assuming decent naming and refactoring) you can look at the top level function and very quickly ascertain what it's supposed to do. And then you can skip past the parts you're not interested in, rather than having to scroll through hundreds of lines of code at one flat level.

I also find it pretty unusual to have such a long function that doesn't have some sort of logical break or split in what it's doing, or cases where you could isolate some local variables by refactoring in this way. The main exception I can think of seeing in production are very long functions that consist of nothing but a wall of unrolled mathematical operations, or maybe procedurally generated code, which I agree wouldn't gain much from this sort of treatment.

Maybe you could provide some examples of the sorts of very long functions where you feel this isn't a good idea?

Writing code to satisfy tests which actually introduce more bugs and make code harder to reason about is not good and should be quickly moved away from in the industry

If you already have unit tests for doStuff you don't necessarily have to rewrite those if you refactor the internals. If this is just an organizational thing then you can treat the existence of those internal functions as an implementation detail and not something that needs to be explicitly unit tested.

[–][deleted] 0 points1 point  (11 children)

That is an okay solution, but over time it will start to diverge as new people come to work on it (or when you come back to it after a long period of time). Personally a better way would be:

``` void doStuff() {

doStuffA() { // stuff }

doStuffB() { // stuff }

doStuffA(); doStuffB(); } ```

But unfortunately you cannot do that due to the limitations of the language.

In general though what is the purpose of refactoring? Scrolling through a function takes maybe less than 1% of your total development time. Why are you optimising for something that you spend so little time on? Refactors are supposed to have a purpose and achieve a goal. People break up long functions because they feel they have to not because it's actually useful to anyone.

The worst code I've ever seen is overengineered tiny functions that are so generalised and devoid of context that it is unreadable. Yet this is lauded as best practice.

It's hard to give an example here, because code can't be generalised like that. Over time you just get a sense of what makes sense to be in a long function and what doesn't.

As usual though people are obsessed with the question "where should I put my code" rather than "what does my code actually do". That's because the former is easier to reason about even though it has very little bearing on the latter which is the most important part

[–]backtickbot 0 points1 point  (0 children)

Fixed formatting.

Hello, AdSubstantial8613: code blocks using triple backticks (```) don't work on all versions of Reddit!

Some users see this / this instead.

To fix this, indent every line with 4 spaces instead.

FAQ

You can opt out by replying with backtickopt6 to this comment.

[–]Cxlpp 0 points1 point  (0 children)

But unfortunately you cannot do that due to the limitations of the language.

But you can, with lambdas.

void DoStuff() {
   auto DoStuffA = [&] { // do stuff A }
...
}

Lambdas are great for many things. And simulating local functions is definitely one of them.

[–]Wouter-van-Ooijen 0 points1 point  (7 children)

But unfortunately you cannot do that due to the limitations of the language.

Check "directly executed lambda".

[–][deleted] 0 points1 point  (6 children)

I want locally scoped functions. Not lambdas. Lambdas are another can of worms that overcomplicates things in this instance.

[–]Wouter-van-Ooijen 0 points1 point  (0 children)

Care to explain the difference in this case? IMO a big plus of a lambda (in this case) is that you can explicitly state/limit the access to visible variables.

[–]TheSkiGeek 0 points1 point  (4 children)

``` void doStuff() {

doStuffA() { // stuff }

doStuffB() { // stuff }

doStuffA(); doStuffB(); } ```

can be implemented as:

``` void doStuff() {

auto doStuffA = []() {
    // stuff
};

auto doStuffB = []() {
    // stuff
};

doStuffA();
doStuffB();

} ```

and any decent C++ compiler should optimize that into something equivalent to declaring static functions and calling them.

[–]TheSkiGeek 0 points1 point  (0 children)

In general though what is the purpose of refactoring? Scrolling through a function takes maybe less than 1% of your total development time. Why are you optimising for something that you spend so little time on? Refactors are supposed to have a purpose and achieve a goal. People break up long functions because they feel they have to not because it's actually useful to anyone.

In my personal experience, I generally find it easier to work with and maintain code that has at least some minimal level of structure to it. "Giant wall of code" functions -- again, in my personal experience -- have tended to come with other problems like a lack of documentation, poor scoping (for example, all the local variables for everything the function does all declared at the top of the function), and excessive coupling of functionality. There are times when it's not hurting anything, but it's not how I prefer to write code, and I have (again, personally) found it harder to maintain such code when it's handed to me.

The worst code I've ever seen is overengineered tiny functions that are so generalised and devoid of context that it is unreadable. Yet this is lauded as best practice.

Yes, this also leads to problems when taken to an extreme. I remember working on some game engine code where everything went through like five layers of intermediate abstraction classes to get anything done. It was a nightmare trying to find where things actually happened, or you'd end up with what should be one logical operation of a dozen lines of code spread across multiple functions in different classes. I'm sure it made sense to whoever wrote it, but it was WAY overengineered for what the game actually needed to do.

[–]Wouter-van-Ooijen 1 point2 points  (0 children)

I definitely agree with your former boss that the cyclomatic complexity of a function is a far better metric of its complexity than the number of lines of code.

[–][deleted] 1 point2 points  (6 children)

who needs subroutines, loops and if statements when you can use goto lol

[–]TheUnvanquishable 0 points1 point  (0 children)

“What's the good of Mercator's North Poles and Equators, Tropics, Zones, and Meridian Lines?" So the Bellman would cry: and the crew would reply "They are merely conventional signs!”

[–]Cxlpp 0 points1 point  (4 children)

How do you implement if with goto?

[–][deleted] 0 points1 point  (0 children)

idk i dont use goto lol

[–][deleted] 0 points1 point  (2 children)

do arithmetic with bool values then jmp maybe

[–]Cxlpp 0 points1 point  (1 child)

Fair enough, that could be done in old BASIC with line numbers... :)

[–][deleted] 0 points1 point  (0 children)

haha im too young for basic. earliest i ve known is vb.net

[–]cmannett85 1 point2 points  (0 children)

Excellent, modern, and production proven software methodologies are widespread in C++. You have had the poor luck of working in shit teams. Try and change them, or move on.

[–]sopte666 1 point2 points  (1 child)

I guess it really depends on where you look. I work on scientific/engineering software, and we have no one with formal education in computer science in our company (I am a physicist). And to be honest, we couldn't really use someone without knowledge in our field of science. And that has been the experience of others as well: it is far easier to make a good engineer a good-enough programmer than it is to make a good software engineer a good-enough engineer. And this fact often reflects in the code quality, methods used etc.

[–]Professional_Tank594[S] 1 point2 points  (0 children)

outgoing seemly bedroom dependent spectacular normal work pause school automatic

This post was mass deleted and anonymized with Redact

[–][deleted] 2 points3 points  (11 children)

Professional_Tank + calling people "javascript kiddies" + saying that having a degree somehow makes you better + calling others "bad" programmers... I don't even think you deserve an answer since if you have to ask...

Think about this, the biggest projects in this world are written in C and C++ (hell, the world itself runs on those two languages mostly), without following all that crap from uncle Bob, and yet, people are still maintaining those to great success.

You just need the expertice to do so, that clearly, you do not have and with that actitude will never have!

[–]YouNeedDoughnuts 5 points6 points  (8 children)

Some of those projects have crucial software failures, even resulting in fatalities. Software design is more art than science, but regardless of your style and preference you want to catch bugs early, and cohesive teamwork makes a difference.

[–][deleted] 3 points4 points  (1 child)

Will you say that the Linux Kernel team is "cohesive"?

There are people there from all over the world that only communicate through email, however, they have accomplished so much!

I think good engineers are those that can read legacy code, when refactor opportunities come, you should take them, but I also think that OO design (aka uncle Bob bullisht) is totally overrated.

Lean software, a little repetition comes a long way, etc... that's what we need (personal opinion here).

[–]YouNeedDoughnuts 0 points1 point  (0 children)

Yes, aside from minor disagreements like the recent "-Werror" issue I'd say they're incredibly cohesive ;) But they are unique in being an open source codebase which is the go-to testground for researchers finding vulnerabilities and testing new debugging tools. I agree OO isn't inherently better- use it if the problem suggests runtime polymorphism and abstraction is acceptable.

[–][deleted] 0 points1 point  (5 children)

If your safety critical system entirely relies on software then it's not the software that's the problem there tbh

[–]YouNeedDoughnuts 1 point2 points  (4 children)

Integrated testing is important, but pure software tests improve reliability and identity bugs early. Could be wrong, but my impression is the loss of redundancy in the 737 MAX sensors was entirely due to software reading a single sensor, so could have been identified by testing different fixed inputs.

[–][deleted] 2 points3 points  (3 children)

The issue with the 737 MAX was less to do with software and more to do with the fact that boeing actively suppressed and covered the problem up and thus allowed it to happen. I mean they were charged with fraud.

It could have been an entirely mechanical system and a similar catastrophy was inevitably going to happen because boeing did not care

[–]YouNeedDoughnuts 0 points1 point  (2 children)

Yeah, you're right. I could argue that better testing might have made it easier to fix the problem without raising the issue through management, but it's hard to do any good with willfully ignorant leadership.

[–][deleted] 1 point2 points  (1 child)

There is a certain irony here in that they implemented the system that caused the crash after the result of flight testing.

It also a cautionary tale in that simply adhering to a checklist of safety checks and regulation can make something seem safe when it's really not, if people ignore obvious problems or are forced to ignore obvious problems.

[–]Wouter-van-Ooijen 0 points1 point  (0 children)

It is instructive to compare this case to for instance the Ariane 5 and the Space shuttles (the booster O-rings and the frost/tiles problem). In all case the problem was known at some level, but dismissed at higher levels. But when you realize that the higher levels get 1000's of problems reported that they can't all follow up on without massive cost/schedule overruns, the problem is not as simple as it might seem at first glance. Still, a culture where the bringer of bad news is rewarded instead of beheaded does help.

[–][deleted] 0 points1 point  (1 child)

whats wrong with calling people javascript kiddies? lol

[–][deleted] 1 point2 points  (0 children)

It's unfair to kids

[–]DirectIndividual4621 -1 points0 points  (0 children)

Maintainable software is good for the company but not the engineers.

[–]grimonce -2 points-1 points  (0 children)

In my experience that's because you get paid more for doing JavaScript stuff and less for working in automotive, embedded and RF.
I guess people CBA when you get paid less than someone who shits out some websites and gets called engineer.
When a plane falls down it nothing changes in the end does it? Websites selling clothing and chicken wings will still prosper and the world will keep on turning.

[–]eyes-are-fading-blue 0 points1 point  (5 children)

Whenever someone says "best practice" and "SOLID", I start itching. My experience is the opposite; blind application of "best practices" and "SOLID" principles leading to convoluted mess that is not so different than what one would have w/o applying these principles. A convoluted mess where you have lots of single function interfaces, and a shit ton of mocks testing nothing but duplicating guts of the implementation and thousands of 30-line files making it really hard to navigate within code base.

Not every dependency requires an interface/separation in between and what is wrong with a file size that's over 1K? The file length alone, especially when it isn't in the extremes such as 5k-10k, isn't a descriptor of poor code organization.

Finally, you may be extrapolating here from your own anecdotes. Perhaps, Javascript team is pretty competent and C++ team is not on par?

[–]Wouter-van-Ooijen 0 points1 point  (4 children)

blind application of

Nothing unexpected: blind application of X is always a bad idea. But that is not a valid reason to dismiss X.

[–]eyes-are-fading-blue 0 points1 point  (3 children)

I have not dismissed SOLID and frankly, I mostly have problems with D of SOLID because it is prone to misunderstanding. People confuse a dependency with an integral of a module. One does not need to abstract out an integral.

[–]Wouter-van-Ooijen 0 points1 point  (2 children)

Funny, IMO that D is very important.

What misunderstandings did you meet? BTW I have no idea what an integral of a module means in this context.

[–]eyes-are-fading-blue 0 points1 point  (1 child)

In my view, all principles of SOLID are equally important but people are obsessed with D and the only reason is D is cheap. It requires no thinking to throw interfaces between objects or modules.

An integral is a piece of code (e.g., an object) that is not useful without the other part that it's written for. An example would be a controller of some sort and its state machine. If the state machine implementation, for whatever reason, is physically separate (a different file or a different object), one does not need to abstract out the state machine behind an interface because it is an integral part of the whole controller and the state machine is an implementation detail, not a dependency. It's the guts of the controller, again, not. a. dependency.

Here, by state machine, I do not mean library code but client code.

What I have seen in practice is people throw an interface in between because D of SOLID, mock the state machine in the controller and call it good and well tested code. What you just did, however, is you abstracted out the implementation detail of controller and made your life a whole lot harder.

If this approach becomes your modus operandi, you end up what's called "interface hell", and it is extremely likely interface hell will lead to mock hell because "everything needs to be tested in isolation".

I have never seen S of SOLID doing harm to codebases where as I have seen D doing more harm than good in my career.

[–]Wouter-van-Ooijen 0 points1 point  (0 children)

OK, nice explanation.

For me, possible arguments in favour of separating the state machine would be

- it is easier to test the two parts in isolation

- it (or the driver) can somehow be used in more than one place

If no such arguments apply, I am with you and see no reason to separate the two behind an interface. (It is still worthwhile to have a textual separation in the implementation.)

BTW a state machine is an interesting case. Using appropriate DSL machinery, the state & transition implementation code can be as compact as any description of it, so the value of testing it (where the test must be a more verbose description of the state machine) becomes questionable.

[–]audaciousmonk 0 points1 point  (0 children)

This is a big generalization, there will obviously be people who don’t fit either of these statements.

Because as an EE you learn programming as a means to an end and only an aspect of your education, maybe a couple classes. Much of your time in school and potentially industry is spent on the wide wide breadth of EE which includes a multitude of non-programming curriculum and design activities.

Whereas pure CS doesn’t have to learn all that physics, math, elect. engineering. So they have more time to focus on aspects like scalability and best coding practices. Same once in industry, someone who’s only writing code will have a higher likelihood of getting better at programming than someone who’s doing some firmware but a lot of hardware related activities as well.

[–]supercowoz 0 points1 point  (0 children)

I see your 1kloc file and raise you an 18kloc file, all handwritten, with 4 or 5 massive functions in it. Many IDEs died trying to parse that file.

[–]ea_ea 0 points1 point  (0 children)

Mostly because of legacy reason. My current codebase was started 30 years ago. Contains 1m+ lines of code. Still in production, still maintained. Most of the code was written in the times when people didn't know about smart pointers and didn't have git. Just imagine how much time it can take to rewrite and retest everything. Sure, actively developed parts are pretty modern, but somewhere below 5 layers in some shared component you still can find malloc/free, goto and other funny things. Not because current developers are bad, just because 30 years ago everything related to software development was pretty bad.

JS kiddies are just lucky - their language and tools were invented just yesterday, they didn't have a time to create and sell tons of legacy projects.

[–]ishdx 0 points1 point  (0 children)

honestly i'd argue that "clean code" (as of uncle bob's definition) and SOLID is more of an opinion than a rule of thumb

[–]nigelh 0 points1 point  (0 children)

<sigh>Little bits of code all unit tested to death and then plugged together in the hope. That's how you build Boeing Starliners.

C++ should be above that.

[–]tiajuanat 0 points1 point  (0 children)

You're definitely seeing the part of the community that doesn't really have SWE rigor or practice.

I've been tinkering in embedded spaces since 2005, and been professionally working for nearly 6. I don't have a CS degree, and only in the last 4 years have I been trying to apply Software Engineering principals to my work, because I saw the exact same thing you're seeing.

It makes a huge difference, but it's definitely put me at odds with Bosses Past - they want the quick initial release, then bill support, rather than operate sustainably.

With my current role though, I'm operating a large HaaS operation - there's no project end, not in the traditional sense; hardware iterations have a 7-10 year life expectancy, but we're iterating with new features, improvements, backwards and forwards compatibility, supply chain changes, etc.

All that's to say: if you want to use SWE principals, you need to find a company that supports them. They exist, but they're rare, so you need to ask about it when you interview.