16

This question already has an answer here:

I've been recently assigned for a new high-performance C++ project (finance) together with 3 other guys who, like, me, refer to themselves as "primarily C/C++ programmers", meaning, all of us have also done Java & other stuff, we all have comparable experience (8 to 10 years) and have successfully collaborated for the making of other projects (not C/C++).

I soon found out we have such different mindsets when it comes to our "mother programming tongue" that it risks not only the good delivery of the project but also the general well-being of the team/office. Specifically:

They come from an electrical engineering/automation/polytechnic type of background, so their reasoning is intimately related to how hardware works, how bytes move around, processor workings, instruction caching, generally everything at the lower layers. They did embedded programming, ARM programming (I barely know what those are). I soon found out their practical experience is with mostly C, not C++. They think procedurally, not OOP.

I, on the other hand, have trained myself to think in a more abstract way, to apply principles such as encapsulation, low coupling/high cohesion for creating reusable, modular software. My speciality is the C++ programming language, with an accent on language constructs that help you get both fast and reusable, generic code. I think design patterns, idioms, concepts. Throughout 9 years of developing software I consistently witnessed how poor maintainability of software systems is by far the #1 burden of teams. I generously document my code, write careful interfaces. I embrace template meta-programming as a way to obtain fast and reusable products. I embrace the new C++11 standard features.

Where I see reusability and loose coupling, they see "complication". They want to "see it all there". They want to see char*, not some buffer class in interface methods. At one point one even said "I don't care how simple your interfaces are if your implementation looks complicated". The trouble is, we really are trying to transition from a monolithic style of systems to a reusable one - we are writing a library. Yet they don't wish to see their C-style structs being polluted with templated methods, typedefs and c-tors, even if neither makes their structs non-POD. They also don't wish to see static_assert(std::is_pod<...>). They love memcpy and pointers and generally stay away from references. They tend to think typedefs are somehow evil.

I really tried to make them see an abstraction for what it is. It is code together with data it operates on. By necessity, a library needs to define some interfaces for the user to be able to plug it into a larger product. They tend to see these interfaces as ways in which my code requires their code behave/look as I wish and doesn't allow them to do things their way, but without actually telling me a specific functionality they can't obtain.

Make no mistake, I'm no ignorant when it comes to performance. I know about cache lines, branch prediction, the overhead of method virtualization, heap allocation, hash lookups. I'm good with complexity of algorithms (though that doesn't matter so much here), data structures, inlining and some other compiler optimizations such as RVO. I believe with a modern compiler a reusable, layered OOP C++ product can get within 10% of the performance of a C-only monolithic product, when carefully written and optimized.

I honestly believed we would complement each other in our thinking.

What are your thoughts? Please don't be too harsh, we need to make this work.

marked as duplicate by BЈовић, jwenting, Dan Pichelman, Arseni Mourzenko, mattnz May 27 '14 at 7:29

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

  • 8
    What does your team lead advocate for? – Telastyn May 11 '14 at 20:38
  • 2
    "Reusability", "library", and "low-coupling" is among goals expressed. Speed also is. He seems balanced re. the speed-readability trade-off, i.e., in his words, will not "sacrifice readability/proper design for every nanosecond". Note, the bar is still very high on speed. – haelix May 11 '14 at 20:43
  • What is the reasoning behind using C++ for writing the libraries? You said that it is for finance software. What benefit will you gain by using C++ over using a more business-oriented language like C#? – Stephen May 11 '14 at 23:33
  • 2
    @Stephen you must understand this is performance critical work. We want the best performance a general-purpose language can offer. Also note, this is a system (multiple servers talking to each other), not an application. – haelix May 12 '14 at 8:38
  • @haelix It sounds to me like you're trying to apply outdated OOP methodology to something that doesn't need or want it. There is nothing wrong with procedural thinking. Procedural programming usually produces much cleaner code than Java-style OOP, which you asid you were familiar with at the beginning of your post. – Miles Rout May 13 '14 at 22:02
11

Ok, I'm going to take a crack at this since nobody else has yet.

My experience is perhaps somewhat similar. I transferred from the software department to the embedded software department at my workplace a little over a year ago, and I have definitely heard echoes of the sentiments you're expressing here.

Here are a few observations I made that are along the lines of what you've listed here. These represent viewpoints of the different groups.

  • Embedded programmers love the stack and RAII. Why use smart pointers, etc. if you don't need them. The heap is evil. They're actually kind of right about this.
  • Software programmers tend to love interfaces because they see the power that abstraction brings. Sometimes hiding information is better. Dependency inversion improves testability.
  • Embedded programmers often do better functional testing, software programmers do better unit testing.

My general takeaway? The embedded/EE background often times comes with lesser ability to architect (especially large-scale systems), and the software background tends to be more prickly about things that don't matter and more of a focus on theoretically improving performance rather than measuring and improving it. Your mileage may vary.

From a team-building perspective, I've found that building respect for the mutual viewpoints is crucial. It's been my goal and I think it's gone quite some ways.

From a C++ usage perspective, I'd like to make a few, perhaps painful, suggestions. Please take all of these from the perspective of things I noticed different between software and embedded software approaches, not as mere flame-worthy editorial on style.

  • While performance is important, it is unlikely this is on an embedded device. That means that if you're dealing with a modern computer, many of the typical embedded tricks don't quite apply. That said, some still do and it would be good to talk with the team to see which ones they think do. Knowing these upfront means you can architect with them in mind!
  • There's a difference between shiny things like metaprogramming and simply having reusable interfaces. Frankly, I find that from a reusability standpoint, you will get the most out of having good sane interfaces. This is worth fighting for... but...
  • While I'm a fan of some template metaprogramming, I tend to find the statement that you "embrace" it as a possibly suspect indicator... Do you really need to push metaprogramming? Or possibly traits? Or possibly lambdas? Or hardly any C++ 11 features? I understand that these are some of your favorite tools, but are they really worth picking a fight over? I'm frankly not sold that these increase resuability all that much. They do increase programmer productivity and other things, but this seems like a place where some compromise may be good.
  • There's a place for plain old data and a place for classes that are not blittable. Generally speaking, stick with some simple convention like structs vs. classes and call it good: do you really need is_pod if you do something like this?
  • I would argue references are worth pushing, especially if you're doing a lot of stack-based programming (which you are, right? RAII and all?). In the past, I too thought references were evil because I didn't properly understand their limitations and correct usage. Just show them you don't have to worry about NULL pointers for a good chunk of your code and maybe they'll agree.
  • You may want to talk about threading upfront. Embedded programs often do lots of work on a single thread with a scheduler, whereas higher level software opts towards many threads. Arguably the scheduler way is faster in certain respects (especially when combined with multiple threads), but the reason I bring it up is that how your work slices up may drastically change depending on which way you go. Scheduled work tends to happen in horizontal slices, threaded work in vertical ones. Also, I have often seen a bit weaker approach to locking on the embedded side, due to the often singly-threaded nature; this may be worth double-checking too.
  • Templates can often be great (hooray for the STL!), but there are definitely tricky syntax things here - I'm looking at you, typename keyword. Also, make sure your .h/.hpp etc. convention is stated clearly. I've seen mixed opinions from embedded programmers about templates - usually more about code size and complexity rather than speed, though. Try not to write code that your teammates won't touch.
  • I'm torn about typedefs. On one hand, they can help abstract away a type and make some things easier. But I've seen code with lots of typedefs in it and it was quite hard to pick up and read. The four places where I've seem them used to good effect are 1) publicly scoped for abstracting hardware-related types, 2) privately scoped for types of header fields so you can do sizeof and still be ok, 3) privately scoped for iterators, 4) publicly scoped for function pointers. Use cases beyond these have often made me start to see cross-eyed if not done sparingly.

Of course, you put two programmers in a room and you get three opinions. I realize that. But on the boundary between embedded software and software, these are things I've noticed. I hope that they are helpful. (But I've preemptively put on the heat-retardant suit, just in case.)

And one last thing. Along the lines of building up mutual respect and admiration, it may not hurt to meet them halfway and perhaps look at things like Template based register access and start a friendly discussion about something like this.

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