|
| 1 | +# Tips on TDD |
| 2 | + |
| 3 | +The following notes are a digest of some of the concepts that I've learned from a great book - |
| 4 | +_"Test Driven Development By Example"_ by Kent Back. |
| 5 | + |
| 6 | +## On work |
| 7 | + |
| 8 | +👉 When working with code (but it works with other stuff too) create a list of items that you need |
| 9 | +to do. Keep track of it. Once something is done you can cross it out. When a new |
| 10 | +task/need/requirement/problem/case/ arises simply add it to the list. Focus on one item at a time. |
| 11 | +Thanks to this method you won't have to think about items that you need to do and you can focus only |
| 12 | +on the one thing that is important at a time. I've learned that this technique actually works for |
| 13 | +me. A simple sheet of paper will do. You can abstract away from this approach to manage your tasks |
| 14 | +and goals for the whole days/weeks/months. Personally I use the |
| 15 | +[bulletjournal](https://bulletjournal.com/pages/learn) system as one o my main tools in my daily |
| 16 | +work. |
| 17 | + |
| 18 | +👉 Whatever you do _"Play to your strengths."_ |
| 19 | + |
| 20 | +👀 We need tests in order to do refactoring. Without them we're bound to make mistakes. If there are |
| 21 | +not tests write them! |
| 22 | + |
| 23 | +👉 **You can use tests to experiment.** This approach is super fast. You should be able to quickly |
| 24 | +write a simple test and run it. It might take much less time than a long analysis/reasoning process. |
| 25 | + |
| 26 | +👉 Do not expect tests written with TDD to replace other types of testing! |
| 27 | + |
| 28 | +👉 If you cannot think of a good name for something, perhaps that what you want to do is not a good |
| 29 | +strategy. |
| 30 | + |
| 31 | +## On TDD process |
| 32 | + |
| 33 | +> "The goal is clean code that works." |
| 34 | +
|
| 35 | +TDD achieves this goal in a few successive steps (Kent's comparing it to the _divide and conquer_ |
| 36 | +approach). Traditionally we define the TDD iteration as a three step operation. |
| 37 | + |
| 38 | +### Write a test that fails ❌ |
| 39 | + |
| 40 | +First we want to write a test that fails. Kent advises to invent an interface that is most |
| 41 | +convenient to use. |
| 42 | + |
| 43 | +> "You are writing a story" |
| 44 | +
|
| 45 | +### Make it green ✅ |
| 46 | + |
| 47 | +Then we want to make this test pass. You want to do this as quickly as possible, even if that means |
| 48 | +creating a solution that is ugly or uses hardcoded values. Go for it. |
| 49 | + |
| 50 | +> "Quick green excuses all sins. But only for a moment." |
| 51 | +
|
| 52 | +There's a couple of things that might be helpful with this step. You can **fake the implementation** |
| 53 | +by returning a constant. Then you want to replace the constant with a variable. This way you're |
| 54 | +moving towards the "true" implementation one step at a time. When you know how to implement |
| 55 | +something up front you can write what Kent calls the **obvious implementation**. |
| 56 | + |
| 57 | +💡 **Triangulation** - is a rule that tells us that we can only generalize code for which we have at |
| 58 | +least two cases. It allows the programmer to think about different axes of variability of the |
| 59 | +problem. You can make different parameters of the problem vary and see how it impacts the design. |
| 60 | + |
| 61 | +👉 Cannot write a big test. Try writing a smaller one. Think on how you can split a given problem |
| 62 | +into smaller chunks. |
| 63 | + |
| 64 | +### Refactor 🔧 |
| 65 | + |
| 66 | +Then you have to **make it right**. This it the refactor phase. Remove duplication. Make the code |
| 67 | +clean and readable. |
| 68 | + |
| 69 | +## On writing tests |
| 70 | + |
| 71 | +👉 When writing tests, **write the assertion part first**. This way you have to ask your self _What |
| 72 | +is the correct result?_ and _How am I going to check it?_. |
| 73 | + |
| 74 | +> - Where should you start building a system? With stories you want to be able to tell about the |
| 75 | +> finished system. |
| 76 | +> - Where should you start writing tests? With the asserts that will pass when it is done. |
| 77 | +> |
| 78 | +> Don't you just love self-similarity? |
| 79 | +
|
| 80 | +**Remember that you are writing tests to be read by others**. Code is read dozens of times more |
| 81 | +often that it is written. (I've spent enough time in a legacy project to know this one) The same |
| 82 | +applies to tests. |
| 83 | + |
| 84 | +#### Test data |
| 85 | + |
| 86 | +**Make sure that the test data is not overcomplicated.** You want to **leave clues** for posterity. |
| 87 | +**Make sure that the test data reflects the intention.** A way to achieve it is to include the |
| 88 | +actual and expected values, and make the relationship between them be apparent for the reader. |
| 89 | + |
| 90 | +#### Tests as a litmus paper for bad design |
| 91 | + |
| 92 | +> The tests are a canary in a coal mine revealing be their distress the presence of evil design |
| 93 | +> vapours. |
| 94 | +
|
| 95 | +Kent describes a few indicators: |
| 96 | + |
| 97 | +- Long setup code - If you need to write a lot of setup code just to check a simple assertion, this |
| 98 | + means that your objects (functions, modules, etc.) are to big and they ought to be split. |
| 99 | +- Duplication in test setup - If it is difficult to find a common place for shared setup code, this |
| 100 | + might indicate that there are too many objects too tightly interlaced. |
| 101 | +- Fragile tests - This is when tests break in a unpredictable manner (are unstable). |
| 102 | +- Tests that take a lot of time to run. This is a problem because if tests take long to run, then |
| 103 | + you won't be running them often enough. |
| 104 | + |
| 105 | +## Other |
| 106 | + |
| 107 | +> Faking it doesn't sound dignified, does it? We'll simulate it. |
| 108 | +
|
| 109 | +> Development in this sense means a complex dance of analysis, logical design, physical design, |
| 110 | +> implementation, testing, review, integration, and deployment. |
| 111 | +
|
| 112 | +> [On where the TDD name comes from] THere is a naming rule that the opposite of a name should be at |
| 113 | +> least vaguely unsatisfactory. **If you don't drive development with tests, what do you drive it |
| 114 | +> with? Speculation?** |
| 115 | +
|
| 116 | +### Take a break |
| 117 | + |
| 118 | +When you're stuck and see that despite spending more and more time on a problem you just do not make |
| 119 | +any progress, just **take a break**. |
| 120 | + |
| 121 | +> Take a drink, take a walk, take a nap. Wash your hands. (...) Fatigue negatively affects judgement |
| 122 | +> which affects Fatigue. [It's a positive feedback loop] |
| 123 | +
|
| 124 | +Kent's tips on making sure that you get enough "rest" time: |
| 125 | + |
| 126 | +> - At the scale of hours, keep a water bottle by your keyboard so that biology provides the |
| 127 | +> motivation for regular breaks. |
| 128 | +> - At te scale of a day, commitments after regular work hours can help you to stop when you need |
| 129 | +> sleep before progress. |
| 130 | +> - At the scale of a week, weekend commitments help get your conscious, energy-sucking thoughts off |
| 131 | +> work. |
| 132 | +> - At the scale of year, mandatory vacation policies help you refresh yourself completely. |
| 133 | +
|
| 134 | +Note that sometimes when your working on a problem you want to press on and stay at your working |
| 135 | +position. Again this is just a heuristic and you need to work it out with your judgment. 💁♂️ |
| 136 | + |
| 137 | +### On Patterns |
| 138 | + |
| 139 | +> One of the primary insights of patters is that although it may seem as though we solve completely |
| 140 | +> different problems all the time, most of problems we solve are generated by the tools we use, not |
| 141 | +> the external problems at hand. Because of this, we an expect to find (and actually do find) common |
| 142 | +> problems with common solutions even in the midst of an incredible diversity of external problem |
| 143 | +> solving contexts. |
0 commit comments