Idea: Innovation or absurdity regarding phoenix testing

Can you explain more on what you mean by good tests?

Also even if you build projects for yourself doesn’t maintenance play a big role?

Good tests:

  1. Make sure that when we add new features, we don’t break existing stuff.
  2. Help understand the logic better by looking at the test code.

As for projects for myself - for me it is not so important as for a commercial project. But even here it depends. If this is a library I’m open sourcing for other people to use - I will cover it with lots of tests.

3 Likes

Thanks for the follow up on my comment

My 2c. Tdd will probably not solve your problem, but it might. You can certainly code your entire program using tdd and assemble it and magically the whole thing works without orchestrating everything. This especially happens when an expert does tdd with the luxury of time.

The real world will hit, though, and sometimes you might be asked for a deliverable that you do not have the time to test. Sometimes you have no choice but to use tdd, when making the choice for what to do first is so overwhelming that it’s better to do strict outside-in starting with trivial responses and searching for corner cases. I do not religiously tdd because I’m up against time constraints and honestly I’m not disciplined enough and I’m not working with a team yet. My projects range from 20% TDD to 80% TDD and I’m currently doing one that’s 100% TDD.

For junior programmers, TDD and pair programming are excellent tools for building reliable and trustable code in a rapid fashion.

I had a junior before that I had learn elixir logging and develop a fault tolerant DHCP server which relied on elixir logger artifacts to restore state when crashed. I had him use TDD and write all the tests including tests for resiliency. He struggled like crazy since he was trained in a shop that did not treat it’s “engineers” well and had very poor programming practice and no tests or notions of resiliency, reliability, or SLAs (ironically it produced military equipment, so, go figure). But we dropped his code into the main code, it had a ton of namespacing conflicts, but it took me 15 minutes to resolve them and I had full confidence that everything worked as designed in the main system… And it did, of course.

2 Likes

Thanks for sharing this experience.

It turns out that TDD can save the day sometimes.

This sounds alien to me. I’m programming for many years and never saw a use or need for TDD. Design upfront is needed when things get complicated. For how to’s see http://www.budiu.info/blog/lamport.html and https://archive.li/2zZKy#selection-125.0-125.46.
“Spending a few hours thinking before writing code can save days of debugging and rewriting.” (Lamport)

4 Likes

Design will not always help you. Sometimes the system is already designed. The 100% tdd thing I’m working on is an implementation of raft: https://raft.github.io/raft.pdf the raft implementation is entirely defined in a single figure (Figure 2), and “thinking about design” does not, at least for me, disambiguate the coding entry points. I am scatterbrained enough that I will spend hours hemming and hawing about what the correct way to start and what if I do this and it messes up that, etc. TDD does, because you literally just start at the top, write your tests and progress forward with confidence.

3 Likes

So TDD helps you keep track of what you wnat to add and the same time you can verify that the new features won’t break the old ones?

Tdd doesn’t keep track of anything for you, honestly I use GitHub issues (or in the last job, jira), for small components it’s unnecessary because for the next few months I’m still solo coding (when I have a team again I’m going to start with a fixed feature list and tick them down). I just mean to say that tdd makes it easy to just start coding without having to decide what to do first.

With all due respect to Leslie Lamport I feel like for my personality planning too hard is dangerous because I am not that smart and I often uncover fatal conceptual mistakes which require refactoring. Uncovering those quickly and as a bonus having the tools to safely refactor built in are a helpful crutch for me to have in place and I never regret having done tdd. Late discovery and having to refactor blindly for me is a recipe for burnout; refactoring with tests conversely rewards incremental progress (those little green dots give me a huge dopamine rush) and consequently I haven’t majorly burnt out in about four years despite gross mismanagement at the last place I worked.

3 Likes

OK, thanks @ityonemo for the explanation and usage of TDD in your case

What I do when a piece of software is too complicated to write at once is as Lamport says:

The whole text is a highly recommended read https://archive.li/2zZKy#selection-335.0-335.409
Testing follows after writing specs and code. That can be an IO.puts / console.log till an end to end test, whatever I think gives me the most return of investment. I never felt the need for a unit test suite with x percent coverage to get enough confidence (hence maybe Robert Virding’s renaming TDD to terror driven development Is TDD Dead?).

1 Like

Here’s my 2 cts too (I think we’re going to be rich altogether!)
Tests is my what makes my motto “Code & Forget” viable.
They give me confidence about what I coded, this can be push to production without fear.
And I can break my code and my test will tell me what’s impacted.
And if I come back 2 years later on a project, I don’t have to remember how to test it, tests are still here.
And one thing I’ve encountered recently: writing test sometimes yell at me “You’re doing it wrong”. not because code is bad, but because the api is bad. It’s awkward (and a little bit funny) to write tests the way you want to use your project and realize that it’s not user friendly.
I’m lazy and the less I write / read code, the happier I am. Tests and documentation helps me to NOT have to read the code to understand what it’s done

2 Likes

A comment on what Lamport said:

I have found that working on what it should and how it should do it often go together. Working on the “how” can give you a much better understanding of the “what”. And once you get the “how” working, or at least a POC prototype, it will let you see if the “what” was what you really wanted.

BTW I think what Lamport said is correct.

6 Likes

Thanks @domvas for your opinion and experience also for the motto

I would also like to add that humans are not machines so your motto goes well with that idea. You can’t remeber everything especially if you work on several projects.Then TDD can really help a lot.

Thanks @rvirding for contributing to the thread and share your experience and impressions regarding this subject.

Interesting, can you give an example? I for example sometime ago wrote https://github.com/StefanHoutzager/decimal-input.js , in the readme you can find the what, the how followed after that (I did not write it up so it’s buried in the code).

A simple example is the actual development of Erlang and of our of ideas of how to use it to build systems. Our target implementing was telecom switches. While Mike Williams had worked on this before we got a lot of very useful feedback from a user group who was using Erlang in an architecture study. They came back with a lot comments on which of our ideas were good, useless or bad, which we could then use to work on and improve our ideas. This at the same time as we were developing Erlang, its implementation and how it should/could be used. These 3 “levels” evolved together.

We found that it was better to provide “tools” rather than solutions as our solutions weren’t always very good. :grinning: That is why many of the language basics are so very simple as they then allow you to build the solutions you need. The hard part was in getting the right simple basics.

We definitely agree with Dijkstra:
“Simplicity is a great virtue but it requires hard work to achieve it and education to appreciate it. And to make matters worse: complexity sells better.”

9 Likes

When I look back at the development of the library I mentioned the development, including design of what and how, went like this. In this case I’m the only user/developer.
I wanted decimal formatting for inputs. What would be the most userfriendly workings? I have seen formatting/validation (of invalid characters) on blur and on key press/cut/paste in other applications (in my case a desktop application, I had not seen decent versions in web applications). Most userfriendly I found the last option. I looked for a decent libray: none (recently I found one that could be good, but it’s react specific). I started finding out what the exact workings were in this desktop application input field and wrote them down as the what. I added and changed some of the workings. For example:

After writing down a couple of what’s designing and developing can start. One does not have to wait until the requirements are completed. To fulfill the first requirement I need, among other functionality, to get the position of the decimal separator, and before that which character it is. I can write functions for that without much thinking and writing down of the how because it’s not that complicated. Maybe I have to add a requirement about what is required to see if a decimal separator is needed and what character is to be used for that. Etc. So design of a single what comes before thinking about it’s how as far as I see, but the list of what’s do not have to be complete before one starts thinking about the how and writing functions. And while thinking about a how indeed a new what can come to mind.

1 Like

I rarely write tests first because I’m usually exploring different angles to a solution. I write tests once I’m confident that I’m onto something. I find premature unit testing to really slow down design because it over-commits to early design choices.

One of the immediate benefits of an automated test is that you have a great feedback loop as you make changes. For example, if I’m building some particularly complex validations for an Ecto schema that maybe requires me setting up a bunch of structs and state, then I might write a test straight away and have the test IO.inspect… I don’t even care about asserting anything at this point. I may even write some modules in the test file itself and see how different structures work together… without any assertions.

That’s not even a test, but it helps me work better (esp. when paired with the console). Once I’m happy with the direction then I’ll flesh it out with the actual tests.

In the end you will have your own personal style of how you develop software, but there are standards if you want to keep some semblance of quality. The important thing is you write tests at some point.

3 Likes

Thanks very much @BitGonzo for proving some guidance and also your work flow with examples.

1 Like