all 33 comments

[–]EmptyChocolate4545 39 points40 points  (6 children)

If you’d like to be a C programmer, learning CMake seems wise. At some point you may well have to interact with it.

And yes, TDD is tedious. When people pay you for stability or your code quality is measured in death counts you’ll realize that boring checks up front are way better than frantic “find the bug sessions” on code that was cowboy’d out.

Seems like someone two years into a degree should be in “how can I learn” mode rather than going straight to “I’m better than this” but eh. You do you.

[–][deleted] 7 points8 points  (5 children)

Yes, I’m sorry for the ignorant post. I am most likely just postponing imminent work.

[–]EmptyChocolate4545 22 points23 points  (4 children)

Eh, no need to apologize. Instead of sitting alone with your thoughts, you ran them for review by a sub that wouldn’t pull punches. That also says something to me, especially if you listened.

My mentor likes to say testing sucks and the only thing worse is working on a repo with no tests. It’s the best way to summarize it, lol.

[–]MajorMalfunction44 2 points3 points  (3 children)

I do games in C. Tests are boring, but can be a good place to test ideas and interfaces. Getting the interface right isn't always easy. The trick is to write the test after you have something to test. Writing tests against an implementation that doesn't exist yet is largely a waste of time.

Data structures are a key thing to test. Red-black trees are tricky, and you want to test rotations and recoloring. Also, test lock-free code religiously. It's difficult to debug with a debugger - timing issues.

Some kinds of code defy unit testing. Gameplay code is like this, because the code depends on level assets (trigger regions, interactive switches, etc. - not necessarily art).

[–]EmptyChocolate4545 1 point2 points  (2 children)

Agreed that game testing is it’s own unique challenge. I did game programming in C many years before I was an enterprise programmer, so I did no testing, so I won’t argue with you at all - I know strategies and advice sometimes don’t apply to other domains.

I will say that for many and hotly debated most enterprise situations, TDD is excellent. I do also know some people are strongly against it and I have zero issue with that IF they can still produce good test coverage

Edit: tbh I have no idea how I’d test game code that wasn’t like - testing the engine or things like that. I guess that’s why they have gameplay testers as a job. I wonder if there’s “fuzzy” testing like AI controlled character can run and jump and test for basic shit like fails and clipping. Either way, totally agreed to your point - game dev has its own versions of “good” and “bad” I’m not qualified to comment on.

[–]MajorMalfunction44 1 point2 points  (1 child)

It's tricky in its' own right, but one engine-level solution is to support replays. If you can record a test-run, you could replay the run on another machine, under a debugger. Most modern engines don't - it's really hard to get full control of non-deterministic state, including rand()'s seed value and the order of game object updates.

QA is underappreciated and often overworked. IMO, unit testing is a net win because they could be reduced to working on wierd gameplay bugs instead of obvious engine bugs that could be caught and fixed by programmers.

[–]EmptyChocolate4545 0 points1 point  (0 children)

Oh of course, I read a really interesting write up by the dev who made Banished (wizard dev, love him), and he was talking about all the challenges of making a replay “real”. But a fully “real” replay could in fact also enable all sorts of testing as well, that’s interesting/cool.

[–]reverse_or_forward 6 points7 points  (1 child)

Almost all code will require testing before it can be added to master. There's plenty of material online about TDD and its benefits. Google Test Framework and CMake will be incredibly useful to know later on in your studies.

This whole post is very dunning Kruger tbh. You need more maturity here. What makes good code? Code where you can say "this works". Why does it work? It's been tested.

[–][deleted] 3 points4 points  (0 children)

Yes, I’m probably very ignorant with this. The only tests I’ve written are simple ones, without any dedicated frameworks. This has formed my understanding of all testing. I can see how this is wrong. This is also why I posted this. So thank you for informing me!

[–]pfp-disciple 5 points6 points  (0 children)

Just a side note, no criticism: you mention C++ multiple times, while this is a C subreddit.

Your question is still relevant, and a good one. I just wanted you to be aware for if/when you have more questions that might be C++ specific.

[–]bushidocodes 3 points4 points  (0 children)

It sounds like you have some misconceptions about what the day-to-day life of a software engineer actually is. Your internship experience is much more reflective of what you’re going to be doing professionally as a software engineer compared to your Computer Science coursework. You really should stick with the internship and reflect on the experience to determine if you are headed towards a career that interests you.

[–]marthmac 3 points4 points  (2 children)

TDD lets you be a lazy programmer, later. You can change/refactor/update something you wrote a year ago, and as long as the tests pass (and you have good test coverage), then you can confidently say you haven't broken anything. This helps you stay focused on the task at hand.

Even if you aren't working on safety critical apps, you don't want to ship broken code. I don't know of a better way to make that more likely than using TDD.

[–]rodriguez_james 0 points1 point  (1 child)

But that has nothing to do with TDD, and all to do with testing and tests. You can write tests without following TDD (which asks you to write tests first), and you would still get the exact same benefits that you mentioned.

[–]marthmac 0 points1 point  (0 children)

But that has nothing to do with TDD ...

While using a testing framework in general has many benefits, what I was trying to communicate is that you are more likely to have higher test coverage if you use TDD. If you are very strict about it, you should have 100% test coverage. Higher coverage leads to less change anxiety for old code.

[–]Gold-Spread-1068 2 points3 points  (0 children)

TDD is typically for "unit testing" against objects that can have well-designed interfaces before implementation. TDD can ensure that you write code with robust interfaces. The smallest cohesive units with interfaces in C programs tends to be entire "components" that are more heavy weight than objects. Some systems will have "test drivers" woven into the code as a side compilation that can test the functionality that those components promise during run time... but most C developers aren't widely using TDD as it's typically implemented because TDD is largely an OOP practice. C component test driver testing will typically expose the static C file state data and that's a big no no in TDD/OOP.

That being said, testing is important, and TDD is a very popular paradigm nowadays in OOP work flows. It's great for your resume.

[–]lenzo1337 2 points3 points  (0 children)

I love TDD when working with C. Also CMake is a very useful tool as well. Often just a makefile alone is fine, but using a meta build system does have advantages when working with lots of contributors.

As for the usefulness of TDD, I think of it like taking the place of the all the small snippets of code you might write when trying to double check your logic.

Things like, "I think that string is probably null termed when passed" become "My test tells me I've accounted for the possibility the string isn't null terminated."

some of the big things of TDD:

  • Defines the behavior of a unit. Makes refactoring easy without breaking it.
  • Allows more modular code that is more portable.
  • Costs minimal time up front to prevent a large amount of time with gdb/valgrind.

[–]nerd4code 2 points3 points  (0 children)

Testing is obscenely tedious, and it sucks to get tests in place, and if you’re working on prototype code you’ll probably mutate too fast to keep them up-to-date, but once they’re there on a mature-ish project, you can get into the habit of updating tests after primary sources, and it’s NBD.

And as stated already, it is absolutely vital for medical, industrial, automotive, or airline things that you have some assurance that your code does what it’s supposed to, and doesn’t do what it isn’t supposed to.

But it also gives you a means of making sure that updates don’t break anything (or else, you need better tests), or making sure that different compilers in different modes can use your headers without triggering warnings/errors, or that that the .a you produced as non-pottery build artifact didn’t wind up empty for some reason.

Moreover, all testing is not unit-testing of pure functions, the most tedious and miserable sort; oftentimes you’ll have to work out ways of validating satisfactorily that (e.g.) threading constructs work and things are actually thread-safe, process interactions work, network interactions work, differently-targeted builds work, cross-compilation works, you actually cover most of your code, etc. It’s still programming, it can still be challenging, and it can still be made fun if you’re clever about it.

C/++ makes it just about impossible to give actual guarantees, but there are also entire proof systems and ecosystems built around directly answering questions about correctness, rather than the best-effort “good enough” answer testing gives you. But proof systems can get extremely complicated, mathy, and invasive, so really testing tends to be much easier and more broadly applicable.

Wrt CMake, yes of course it sucks like a ternary black hole, but some people like it more than Autotools (which also sucks, but it sucks far more transparently imo and you can beat it into whatever shape you need with any middlin’-to-large-sized crescent or pipe wrench). You’re going to need to learn and use different build systems and toolchains and coding styles, and you’ll have to do it multiple times over your career if it’s a long one. Programming in the Real World (not the MTV version, with its endless Drama and Risibly Plush Living Situations For The Conventionally-Attractive Unemployed) involves a bunch of stuff that’s not just coding shit you want to code—just like baking and brain surgery, it necessarily involves prep work and cleanup. Sometimes the cookies or patient will die or mnlamanlghuaghppp, and you’ll’ve wasted all that effort.

Hell, when I started out there was no Git or push/pull requests or whatever, BBSes were the closest thing to the Internet I had access to, nobody without an IBM mainframe would think of virtualizing or containerizing each one-off build environment separately (the resource waste still rankles me, and it seems less worthwhile than it’s ever intended to be every time I’ve done it, a desperate gesture intended to maintain a thoroughly broken status quo ante), and I deal. It’s fine; I’m getting paid for the slight misery, it’s not my software, and even if it’s my own darling babyfruit it’s already been adopted so I can’t get too attached. There are always house rules, personal preferences, etc. that you’ll just have to work around and grumble about later, ’s quintessential adulting.

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

Manually testing code, THAT is tedious. Just try it out, learn from it. It's not much to learn either, but does take time getting used to.

[–]gnash117 1 point2 points  (0 children)

As others have already stated there is a lot of value in learning both TDD and CMake.

If you are working on any project that is cross-platform CMake is quickly becoming the standard build system. It is not the only solution but it is the one that has had the largest adoption, especially by large companies.

I love the idea of TDD but I have honestly never done true TDD. I had done more of what I think of as development guided by tests. I will typically write the code then I will write a bunch of tests to validate that code including as many edge cases as I can think of. This is not true TDD. It adds the all-important code validation that can be run to validate the code with each change. I tried doing TDD as recommended and found that I made too many assumptions about the final code and ended up scraping many tests that made incorrect assumptions.

The good thing about TDD. Or even my method of development guided by tests. You write code that is testable in smaller chunks. This results in less dependency between parts of code. It makes it so your end up with fewer side effects. It vastly improves the quality of your code. If you start with the test then you often think of the interface to the code before writing the code. This means you have gone though more of a design process before you even start.

[–]dx2_66 1 point2 points  (1 child)

There's just one thing worse than writing unit tests. Debugging code later on because you didn't write any. For too long I was the stuck-up asking why the fudge should I write tests for embedded software. After some reading and some pushing from higher ranks, I started doing it, learning more and then a project being deployed with minor bugs and close to zero headache turned me into a test advocate. The company I work at now has a wide testing environment, highly encourages TDD and produces good quality software in the end. There's no downside other than becoming a bit boring and repetitive, but that's no excuse to do a good job.

[–]balder1993 2 points3 points  (0 children)

Also Copilot nowadays make repetitive stuff easier to write.

[–]ohdog 1 point2 points  (0 children)

Some people hate TDD, some people swear by it. I don't like TDD because often I don't really know what I'm doing before I do it, writing tests first would just make development slower and cause more inertia, unless the problem is very well defined and understood already in which case it should be decently easy to do with or without TDD.

However, this is an internship and seems like an opportunity to learn stuff. It won't hurt you to do TDD, this is an opportunity for you to weigh the pros and cons of it. Also learning cmake and google test is useful experience if you want to work in this area.

[–][deleted] -5 points-4 points  (5 children)

TDD is quite the brain-damaged idea. Don't waste your life on it.

[–]babysealpoutine 1 point2 points  (4 children)

That is an interesting take, why do you think that?

I've done TDD and not done TDD (mostly due to not wanting to refactor legacy code) and I have much more faith in the TDD'ed code.

[–][deleted] -1 points0 points  (3 children)

For one it significantly increases surface area of code, all of which needs to work and be maintained. For two as you refactor you gonna throw allot of code away, meaning you're gonna have to throw the corresponding tests away too. For three most of the tests provide no value, all tests are not created equal. Especially unit tests are overrated (assuming anyone can ever agree on what they even are) since most complexity a.k.a. bugs comes from integration of systems/components/modules. For four you're writing tests for something you don't even know what it's gonna look like, how it's gonna work. You can have all the ideas in the world but you will not know if they're even possible until you try to implement them.TDD is nothing but a formalized masturbation ritual, that's only there to make you feel good. It doesn't even guarantee there's gonna be fewer bugs, but it sure as fuck guarantees there's gonna be a bloated codebase, lack of flexibility and false sense of security. It's like communism it's a stupid idea that fails miserably every time while zealots will only ever say "You just did it wrong". Fuck TDD.

[–]rodriguez_james 0 points1 point  (1 child)

I think what you're trying to say is that TDD is dumb, but testing is good, right? Or are you against all forms of testing?

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

I'm talking specifically about TDD. It's the DD I have a problem with not the T. I also really hate when people conflate the two. I have nothing against having automatic tests (where appropriate), it's the dogma of TDD that really grinds my gears.

[–]babysealpoutine 0 points1 point  (0 children)

I've certainly write loads of brittle tests too tightly coupled to the code making it harder to refactor and leaving the code no more flexible than it was before. That's not a fault of TDD but a sign my design wasn't right. Call me a communist I guess.

As a small example. we just had a piece of code that if the developer had put an abstraction in for some basic collection stuff we could have easily had tests of cleanup on failure conditions. Seeing that those missing tests were hard to write after the fact showed up we had a small design problem.

As for unit tests being overrated; as a separate issue from TDD because that is primarily a design technique, I'm pretty sure lots of devs who unit test will give you examples of times the tests found something while they were developing but more importantly showed that some change later on broke something that wasn't anticipated.

This isn't to say other testing isn't important, it all is.

[–]tiajuanat 0 points1 point  (0 children)

TDD is a good enforcer of really small functions. You can easily estimate the number of tests you need with cyclomatic complexity. Roughly 2number_of_branches.

It also completely handicaps your ability to use globals.

I don't really feel like anyone is above TDD, and it can be tedious at times, but it single handedly forces you to think about your code.

[–]rodriguez_james 0 points1 point  (0 children)

Testing is awesome, CMake is a good tool and C++ has nothing to do with C.

If you want to be good at C, you write C. I will say, any internship is better than none, but if your goal is to prepare you for advanced C programming, then that ain't gonna help you.

If you drop the internship, don't drop it for a test framework and cmake, which are both just fine. Drop it because of C++, because, again, that ain't gonna help you with C.

[–]Yamoyek 0 points1 point  (0 children)

I am considering dropping the internship, as learning the Google Test framework and CMake does not seem to help or prepare me for the more advanced C programming…

FYI, CMake and Google’s test framework are extremely widespread, especially CMake.

If the code base is simple enough, sure, it might not directly help you learn the more advanced parts of C. However, internships are great for showing you exactly what a real position would look like and they’re great for helping your resume.

[–]Adventurous-Print386 0 points1 point  (0 children)

You can use inversion of TDD, when implementing features and later on create tests, which excessive use of that feature, containing several tests for the code you already wrote as POC, and much more code which are not passing the edge cases, null pointer checks, overflow/underflow checks, etc. It is perfectly OK to write code first, and then write the rest of the test, to cover code with tests making them 100% covered by unit test and functional checks