The Pragmatic Programmer EP.8 — Things during coding

Natnicha R.
CodeX
Published in
8 min readJun 8, 2022

This episode will guide you what factors or things that should be concerned while you are coding.

Deal with your unconscious mind

When you witness something or are confronted with a circumstance, you might become uncontrolled. Because it is your instinct, which you acquired via repeated learning or were born with. As a programmer, while you are writing a program and you’re afraid of anything, for example, you are scared whenever you execute a query statement. Your brain is commonly trying to tell you something. You should find out why you feel like that and find a solution and cope with it by following steps:

  1. Find a root cause of the fear: There are two problems. One of them is that your brain is trying to tell whether it works or not, as a developer. Because you experienced about it. Another problem is that you are afraid to make a mistake.
  2. Listen to yourself: Your brain calls for attention to find the root cause of problems by reading all readable responses, for example, error statements, or wrong logical programming. You should step one backward and read what you are coding whether it is correct by business logic or not.
  3. Talk to your brain: Because you can not control your brain directly, the simplest ways to talk with them is to take them rest for a while by taking a short break, chatting with teammates, or taking a walk.
  4. Restart everything: We should think that it is just a game, don’t take it too seriously. When you become stuck with a piece of code, you just stash it away and begin prototyping instead. It’s a prototype, which implies it might fail and be discarded. Then, create comments to outline what steps you will perform. You can continue coding again until you are happy with your code or your experiment is working properly. At that time, you may discard your prototype and start with clean code.

Apart from that, you might be allocated to work on existing code. You can come upon a weird coding style or pattern. This is one way to gain new knowledge. Take note of it and apply it whenever it is suitable.

Stop and assess your feelings if you sense anything is wrong when you are grooming the business team, or if a requirement makes you feel unclear or difficult to achieve. Express your thought aloud. Trust your instinct to don’t let the problems come to you. It might hard to solve it.

Programming by Coincidence

Programming by coincidence is when you write code and it seemed to work by given the limited testing. But, actually, it may fail some other cases. For example, an application in the difference environment is work correctly now, but it just coincide, an error may occur some day.

Accidental implementation can occur whenever and wherever. it’s a routine that you may not even be designed to do, but it seems to work.

To prevent programming by coincidence, you should rely on document the requirement documents. If not, you should initial documents as much as possible. And, the important thing is that prove it by comprehensive test cases, not imagine.

How to Program without Coincidence

  • Aware of what you are doing.
  • Gather all core logic before start coding only if you understand clearly (can explain everything without any doubts).
  • Use the technologies or tools that you fully understand it because you know what bring it fails.
  • Plan, and follow the plan.
  • Don’t rely on any unclearly concept or assumptions.
  • Document the assumptions and limitations of your application.
  • Test your business logic in your code by assertion, may be in unit test.
  • Prioritize your effort. Spend time on the important aspects.
  • Don’t afraid to revise incorrect existing code. Heritage not always be sacred.

So next time something seems to work, but you don’t know why, make sure it isn’t just a coincidence.

Algorithm Speed

While you are developing code, you should concern about the speed of executing your code or resource consumption. This is why you should know how to assess the speed of your algorithm. Big O notation is used in computer science to assess algorithm speed.

Big O notation is a mathematical notation that describes the limiting behavior of a function when the argument tends towards a particular value or infinity — wikipedia

The notation represents by

O(...) where n is the size of records for a particular routine

It uses to express an upper bound number of possible times depending on the size of the input. The highest term relating to n will be got attention, while the other will be discarded. So, we can conclude that

O(2n²+100n) is the same as O(2n²) is the same as O(n²)

In fact, the algorithm-1 has O(n²) may super faster than algorithm-2 which has O(n²), but we ignore it because Big O notation will not tell you the actual number times but it only tells us how these values will change when we change the number of input.

Thanks to BigOCheatSheet.com

As you can see, the possible notation can be

O(1): Constant (access element in array, simple statements)

O(log(n)): Logarithmic (binary search). The base of the logarithm doesn’t matter, so this is equivalent.

O(n): Linear (sequential search)

O(n log(n)): Worse than linear, but not much worse. (Average runtime of quicksort, heapsort)

O(n²): Square law (selection and insertion sorts)

O(n³): Cubic (multiplication of two n x n matrices)

O(c^n): Exponential (traveling salesman problem, set partitioning) — The Pragmatic Programmer

Turning onto your code, you can estimate your code by this routine

O(n) simple loop: access element-1 until element-n
O(m x n) nested loop: loop in another loop where loops have m and n elements.
O(log n) binary chop: recursively analyze half of an input
O(n log n) divide and conquer: divide input into smaller parts, recursively determine that input, and combine the final answer at the end.
O(n!) combinatoric: any algorithm that accesses an input by n, n-1, n-2, n-3, …, 1 time

Aware of the algorithm you write the code by estimating your algorithm speed. Let’s allow code profilers to help you.

Refactoring

It’s neutral that your code changes over the time. It’s code evolution.

Rewriting, reworking, and re-architecting code is collectively known as restructuring. But there’s a subset of that activity that has become practiced as refactoring

Refactoring is defined by Martin Fowler as a:

disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior. — The Pragmatic Programmer

Refactoring is a small task. It will be completed within a day. Unit testing is the most critical thing to do before you begin refactoring. Unit tests are required for each function or refactoring target to guarantee that your code continues to perform appropriately after refactoring.

Next question is how often we should refactor. The answer is often as you can. You can refactor them at anytime if you discover that your code duplicated elsewhere, the knowledge is outdated, requirement has been changed, need to use by somewhere else, need to improve system performance, or even need to add a small piece of code to be able to write more test cases. However, the authors of the book advise that you must accomplish the following three things when refactoring:

1. Don’t try to refactor and add functionality at the same time.

2. Make sure you have good tests before you begin refactoring.

3. Take short, deliberate steps — The Pragmatic Programmer

Coding by Testing

Testing is the process of validating and verifying that software works under certain circumstances. However, the key advantages of testing are not just in terms of execution time, but also in terms of how we think about the tests.

If we are continuously thinking about testing, we will consider how we may design a software structure that is testable code, what we should test, how we test, and so on. Here is a well-known tool for motivating us coding with testing.

Test-Driven Development (TDD)

Using a simple cycle, TDD compels us to think about testing before we start coding:

  1. Imagine a function you would like to implement.
  2. Create a test that specified the function’s expectation.
  3. Run all tests. You will see that only one test fails that is the function you just wrote.
  4. Implement the smallest piece of code as possible to bring your test passes.
  5. Run all of your tests again to verify that they pass.
  6. Refactor to improve your code.

Simply repeat the steps above until your application meets all of the requirements (see Design by Contract). At that point, you will find all parts of your application will be guaranteed by test cases. Before we begin, we should know which direction we should go. It’s not Top-Down or Bottom-Up, but End-to-End. Start with simply End-to-End. Then, restructure them into appropriate layers, with the test confirming that each modification passes by the same logic.

Property-Based Testing

Apart from the requirement testing, property-based testing is somewhat you should perform to give your application more invariants. An outstanding example is testing by length and the result in each element for sorting lists.

After run this test, you will see:

Behind the scenes of hypothesis (hypo alias) is that this library helps us in randomly selecting 100 inputs according on a chosen data type.

As a result, if hypothesis found a value breaking your function, you should include it in unit tests. Because, at the next running testing time, the library may or may not choose this value.

Security Awareness

A basic security should be concerned during coding. We can simply apply it in order to let your application secure and healthy.

  1. Minimize Attack Surface Area : The more sophisticated your application, the more vulnerable you are. Make it simple to reduce risky hole.
  2. Least Privilege: Allow only minimum authorization, if someone asked. Don’t grant them all to be an administrator.
  3. Secure Defaults: Maintain your application’s security as the default, even if it’s uncomfortable, for example, hide password when typing with an asterisk. Some people may wish to see whether it is right or not. If you are in a public area, it will protect your password from prying eyes.
  4. Encrypt Sensitive Data: Never leave sensitive information in plain text, such as password, national ID card number.
  5. Keep Security Updates: Always keep all of your working PCs’ security patches up to date. It may be in danger if it is out of date.

Naming Everything

It is unavoidable in programming that we are frequently tasked with naming variables, functions, packages, files, etc. Because we strive to figure out what the point is.

There’s some science behind the idea that names are deeply meaningful. It turns out that the brain can read and understand words really fast — The Pragmatic Programmer

For example, you should explicitly declare a variable by let seller = assign(role) rather than let user = assign(role). Alternatively, define a function like def requestSummaryReport(Financial criteria) rather than def getData().

It is acceptable, however, to declare a variable that is well known in a specific language culture, such as i, j, k for loop increment variables in C-Programming.

The most crucial aspect is consistency. All teammates should understand the meaning of each word and use them in the same context. Many teams utilize dictionaries to list out the special terms to the team.

Lastly, carefully specify the name of everything making sense because renaming consumes a lot of effort to figure out what it really means. It’s even difficult.

Please note that all examples shown above are samples to only emphasize understanding the concept. It may be simplified to comprehend, not correctly by the language syntax.

Thanks to The Pragmatic Programming book for the above knowledge, if you are interested in reading this book, click here for more detail.

--

--

Natnicha R.
CodeX
Writer for

Software Engineer, Backend Designer, Algorithm Developer