Changes between Version 30 and Version 31 of HowtoGoodProgrammingTechniques


Ignore:
Timestamp:
Aug 21, 2025, 2:19:20 PM (3 weeks ago)
Author:
Thanatermesis
Comment:

BIG REWRITE with improved english and structure

Legend:

Unmodified
Added
Removed
Modified
  • HowtoGoodProgrammingTechniques

    v30 v31  
    33[[Image(/elive/images/maton.png)]]
    44
    5 = A list of programming techniques =
    6 
    7 I brainstormed / learned these over time, and would like to share them with you.
    8 
    9 == Programming Procedure ==
    10 
    11 I normally follow a simple steps procedure when coding, that should be done on every new function:
    12 
    13 1. '''Write''': I have the idea in mind, so I need to make it working first, this is normally ugly code but, the goal is to make it working
    14 1. '''Make it good''': Then I make the code better, including the methodologies of this coding like correct returning values, making a better structure and readable identation
    15 1. '''Understanding''': Good variable and function names is maybe the best programming tip that you can have, see the section of convention-names, this is a little slow procedure since thinking of best names to use requires some brainstorming
    16 1. '''Cleanup''': Now it's time to remove all the useless parts, the goal is to use the simplest solutions and procedures, they are usually the most appropiate ones, try to reduce the code as much as possible, this step consist in multiple reading of the function thinking on ''how it works'', you will discover on this step a lot of bugs in your code that you won't imagine that exists.
    17 
    18 
    19 
    20 == States ==
    21 
    22 When you are programming, you will see that your code needs to be intelligent, it needs to know ''what to do now'' and how to deal with specific situations, this is a lot more easy to reach with states, in short, '''put boolean states everywhere''' they are cheap!, this way we can always know how to deal in specific situations, but keep in mind we dont want a bloated code with confusing states, so we need to think of a good way to organize them in our code, for example, the prefix '''is_''' is one of the best ones to use, just think about the possibilites to have states (as booleans) marked like ''is_sources_get'', ''is_sources_compiled'', ''is_interactive''... So everytime your application does a specific thing, you can set or unset the affected variables to define the state/progress of the application to know what to do next. Your application can also have different ways of work, so you can prefix those states with '''mode_''', see for example ''mode_interactive'' or ''mode_editing'', another useful one is also the '''ignore_''' prefix in order to ignore steps on our application.
    23 
    24 It's important to think about the possible ''expected'' situations, since we are humans this is hard to acheive but we need to keep in mind every different situation, like ''if the file is deleted when...'' or ''if at the same time the user...''
    25 
    26 == Special Situations ==
    27 
    28 To have states and flags to know how to deal with situations is good, but it's even better if you don't need to do that! before dealing with any special situation just think if it's possible to deal with this element in a better way or totally avoid this need, try to always avoid complex coding.
    29 
    30 
    31 == Integration ==
    32 
    33 An application does a lot of steps, the process does something and then save it to the database, but in fact, you only want to save it in the database only and only if the entire process is successful, but how to know that on this actual step ? well, just create a boolean variable with a state or flag saying that it needs to do that in the end, and when the entire process finishes you have a function called ''final_steps'' that runs all the steps that needs to be commited if the entire process has finished succesfully, this is useful for example for remove temporal directories, for commit or send things, for umount or closing shared medias, etc...
    34 
    35 
    36 == Checks ==
    37 
    38 Your code should be perfect, but in fact, it is not... so don't assume that everything is OK, sometimes by an unkown reason something fails and you could have catastrophic disasters, in order to avoid a buggy application or catastrophic disasters, there's a simple rule: '''always check everything''', simply create short functions for that, for example i have one that is called ''check_directories'' with arguments passed by commas which you should understand what it does, another called ''check_variables'' and another called ''check_files'', I decided to stay with this name-convention, they are simple and they are in the group of ''checkers'' and to have them by the prefix files_ variables_ directories_ make no sense.
     5= Effective Programming Techniques =
     6
     7I've learned these techniques over time, and I'd like to share them with you.
     8
     9== My 5-Step Coding Procedure ==
     10
     11I follow a simple, five-step procedure for every new function I write:
     12
     131. '''Write''': First, I implement the core idea to get it working. The initial goal is just functionality, a clever thing is to keep in mind the core structure it should have in the future.
     141. '''Refine''': Next, I improve the code's structure, ensure correct return values, and format it for readability.
     151. '''Clarify''': I choose descriptive names for variables and functions. This step can be slow, but it's one of the most valuable programming practices.
     161. '''Document''': I add comments where necessary to make the code easy to understand.
     171. '''Simplify''': Finally, I remove unnecessary code and simplify algorithms. Reviewing the function multiple times at this stage often reveals unexpected bugs.
     18
     19
     20
     21== Managing State ==
     22
     23Managing state helps your code know ''what to do'' in various situations. A simple way to do this is to '''use boolean flags liberally'''—they are inexpensive and help your code track its status and decide how to proceed.
     24
     25To avoid a bloated codebase with confusing flags, organize them well. For example:
     26* The prefix '''is_''' is excellent for boolean states (e.g., ''is_sources_get'', ''is_sources_compiled'', ''is_interactive''). As your application performs actions, you can set or unset these variables to define its state and progress.
     27* For different modes of operation, use prefixes like '''mode_''' (e.g., ''mode_interactive'', ''mode_editing'').
     28* Another useful prefix is '''ignore_''' to skip certain steps.
     29
     30Anticipate expected situations. While you can't foresee every possibility, consider edge cases like, "What if a file is deleted while in use?" or "What if the user performs another action simultaneously?"
     31
     32== Handling Special Situations ==
     33
     34While states and flags are useful, it's even better if you can avoid the need for them. Before implementing complex logic for a special case, consider if there's a simpler way to handle it, or to avoid it entirely. Always strive for simplicity, always avoid complex coding.
     35
     36
     37== Deferring Actions ==
     38
     39Applications often perform a series of steps. For instance, a process might perform some actions and then save the result to a database. However, you should only save to the database if the entire process completes successfully.
     40
     41One way to manage this is to use a flag to indicate that a final action is needed. When the process finishes successfully, a function like ''final_steps'' can execute all the deferred actions. This is useful for tasks like:
     42* Removing temporary directories
     43* Committing database transactions
     44* Sending notifications
     45* Unmounting drives or closing shared resources
     46
     47
     48== The Importance of Checks ==
     49
     50Your code will never be perfect. Don't assume everything will work as expected. Unexpected failures can lead to catastrophic results. To prevent bugs and disasters, follow a simple rule: '''check everything'''.
     51
     52Create short, dedicated functions for checks. For example, you could have `check_directories`, `check_variables`, and `check_files`. Using a consistent naming convention, like the `check_` prefix, groups these utility functions together logically.
    3953
    4054
     
    4357=== Memory ===
    4458
    45 You don't have genius memory, you won't remember exactly "what this code does" or "why is this thing there", a good way to avoid this is by adding comments but sometimes you forget to do that or the comments you made are not sufficient enough, in most cases you think that you don't need it in this part of the code or that the element of the code is old and not-needed-anymore or similar things. What I personally do to accelerate the development process and to not think about it at the moment is to add on this step a function name "step_requires_fixme message", which is ran at the prompt/shell if I come to this state of the code it will asking me what im doing here or to verify something.
     59You won't remember exactly what a piece of code does or why it's there weeks or months later. While comments help, they can be forgotten or become outdated.
     60
     61Always keep your comments updated, now we have tools that automates this task.
    4662
    4763=== Visual Readability ===
    48 Readability is very important, but is not only a matter of using good names, it also depends of the visual appearance of the elements, for example:
    49 * If you have an '''else''' 40 lines away of its '''if''', do not use ''else'' but instead close it and start a new ''if'' in the place, is more easy to read
    50 * Align vertical blocks of similar elements by its columns
    51 * Whitespaces improves readability a lot, use them, if you combine them with foldings in your editor you will not suffer the side-effect of removing contents visually
     64Readability is crucial and extends beyond good naming. The visual layout of your code matters. For example:
     65* If an '''else''' is many lines away from its '''if''', it can be hard to follow. Consider closing the first `if` and starting a new one instead of using `else`.
     66* Align similar elements into vertical columns to make blocks of code easier to scan.
     67* Whitespace greatly improves readability. Use it generously. Combined with code folding in your editor, you can keep your code clean without losing sight of its structure.
    5268
    5369=== Visual Blocks ===
    54 Similar as previously said, we need to see visually the blocks of code, for example sometimes we have a big block of looping code, if you add a new feature you may not even see that you are in our even out of the loop, so you can insert code that should run inside the loop outside of it, on such case you can use a plugin in your editor to ''fold'' visually the desired part of the code, or put the biggest parts to external functions
    55 
    56 And similarly, the ''if''s blocks and other blocks has the same problem, they needs to be correctly visual in your eyes to know inmediately where it starts or finishes, or if you are simply in a block at all
    57 
    58 === Think less ===
    59 If you think less, you can read faster, for example:
    60 * Don't say ''equal or less than 2'' if you want to say ''less than 3''
    61 * Never use negatives, they are harder to think than afirmatives, for example:
    62   * ''if not accept'' becomes ''if ignore''
    63   * ''if is not disabled'' becomes ''if enabled'' (stupid but very common)
    64   * ''ignore'' is also a form of negative, use ''want'' when you can instead
    65 * write shorter and clever sentences
    66 
    67 
    68 == Convention Names ==
    69 
    70 Names in variables and functions are something very important, the convention to use is to be the smallest-size possible with a perfect understanding of its name and what exactly does, think on the structure like in object-programming languages, where the first name needs to be the biggest element and the last the smaller one, and in the end include the action, it should look like an hierachy in object-oriented elements.
    71 
    72 It is a good procedure to rename all the functions after the app is finished, by reading the list of all of them and decide the optimal names structure for the entire code, same for global variables.
    73 
    74 === Never create names like this ===
    75 * '''download_resource_now''': It doesn't make any sense or description, the action is in the first, now means nothing and resource nothing too
    76 * '''stmb_sizer_here_here''': The double ''here'' means that your code is so ugly that you don't even believe it, sizer is not easy to understand and if ''stmb'' is not the name of a library or evident element, it is almost impossible to understand what it means
    77 
    78 === The good way ===
    79 * '''cookie_download''': we know that we are talking about cookies, and we don't need to include ''now'' because ''download'' is already the action, in case that we will have 2 different kinds of download we should use ''download_foo'' and ''download_bar'', without keeping the possibility of a single ''download'' and having an extendeded one
    80 
    81 === The optimal way ===
    82 * '''myplugin_net_cookie_download''': Structuring everything entirely is the best option, all our elements should start by ''myplugin'' which is our entire work about, ''net'' means the section were we are those codes (let's say we have core, net, visual, and sound)
    83 
    84 In short, most of the times you will see that the names are written in inverse mode that is how you talk them, if you doubt, just imagine to have some similar possible names and you sort them, you will see how they are sorted and which part of the name needs to come before the other ones
    85 
    86 It is good to know what's exactly that variable, to know if we are dealing with a file, with a directory, or with a value, I personally use for that a suffix (ending in) in the variables like '''_v''' for values, '''_d''' for identifying directories, '''_f''' for identifying a file, there's also a good practice to use '''_''' as ''prefix'' for any local variable.
     70Visual blocks of code should be easy to identify. For example, in a large loop, it can be hard to see whether you are inside or outside of it, which can lead to bugs. Use editor features like code folding to collapse large blocks, or extract them into separate functions.
     71
     72Similarly, `if` statements and other control structures should be visually distinct so you can immediately see where they start and end.
     73
     74Add functions to long parts of the code inside the loops, but only when the loop is not an optimization-required one.
     75
     76
     77=== Think Less ===
     78Code that requires less mental effort is faster to read and understand. For example:
     79* Prefer `count < 3` over `count <= 2`.
     80* Avoid negatives; they are harder to reason about than affirmatives. For example:
     81  * `if not excluded` can become `if included`.
     82  * `if is not disabled` is better as `if enabled`.
     83  * Even `ignore` can be a negative. Consider a positive form like `if include_item` instead of `if not ignore_item`.
     84* Write short, clear sentences in comments and documentation.
     85
     86
     87== Naming Conventions ==
     88
     89Variable and function names are very important. A good convention is to make names as short as possible while remaining perfectly understandable. Think of a hierarchical structure, like in object-oriented programming, where names go from general to specific, often ending with an action.
     90
     91It is good practice to review the final code, brainstorm their names, and rename variables, functions and global variables once a major part of the application is complete. This helps ensure a consistent and optimal naming structure throughout the codebase.
     92
     93
     94=== Poor Naming Examples ===
     95* '''download_resource_now''': The action is first, `resource` is too generic, and `now` is redundant.
     96* '''stmb_sizer_here_here''': Prefixes like `stmb` are unclear without context, `sizer` is ambiguous, and repeated words like `here` signal confusion.
     97
     98=== Good Naming Example ===
     99* '''cookie_download''': This is better. It's clear we are dealing with cookies, and `download` is the action.
     100
     101=== Optimal Naming Example ===
     102* '''myplugin_net_cookie_download''': A fully structured name is often best. Here, `myplugin` is the project/module, `net` is the component (e.g., core, net, UI, audio), `cookie` is the object, and `download` is the action.
     103
     104Often, good function and variable names seem to be in the reverse order of how you would say them. If in doubt, imagine a list of similar names sorted alphabetically. This can help you see which parts of the name should come first.
     105
     106It's also helpful to know a variable's type from its name. Some conventions use suffixes for this, such as `_v` for values, `_a` for arrays, `_d` for directories, and `_f` for files (a form of Hungarian notation). Use a `_` prefix for unimporant local variables.
     107
    87108
    88109=== Big Applications ===
    89 Big applications are very hard to found where a bug is to fix it, very hard to maintain, etc, the best way to avoid these pains are:
    90 1. Keep everything modularized but independent, this means that every function, tool or feature, can be called independently without depend of any other thing, think about use external commands
    91 1. When those external commands or global tools/functions are called, make sure to include a debug entry showing how it is called, on this way you can easly reproduce the same callback outside the application
    92 1. Never delete or rename old functions, you will have tools that still depend of it, instead, replace it with the new function and add a warning line telling the user that this function is deprecated
    93 1. Never refactor changing the final behaviour, unexpected results will happen to applications that uses these functions
    94 
    95 
    96 == 7+1 rules for names that ''must-read'' from [http://www.makinggoodsoftware.com/2009/05/04/71-tips-for-naming-variables/ this article], summarized as: ==
    97 
    98 1. The variable name has to be as descriptive as possible. Don´t use generic names.
    99 1. The variable name has to be as short as possible.
    100 1. It´s OK to use abbreviations, but explain the abbreviation with a comment.
    101 1. Use proper Hungarian notation when necessary.
    102 1. Don´t use negative logic for your variable names.
    103 1. Be consistent.
    104 1. Map the application domain terminology with your names.
    105 1. Golden rule: Spend a few minutes thinking about your variable names.
    106 
    107 
    108 == The 5 steps coding procedure ==
    109 1. Write the feature and make it work
    110 1. Minimize the code (less lines, simple and short functions, less-complex algorithms, etc)
    111 1. Structure it correctly (spaces/readability, comments, begin-end parts, local variables, etc)
    112 1. Document (comment) the needed parts to make it easly understandable, is suggested to use doxygen syntax
    113 1. Convention names, take some time to decide the optimal names for your variables and functions
     110Large applications are difficult to maintain and debug. The best way to avoid these pains is to:
     1111. Keep everything modular and independent. Every function, tool, or feature should be callable independently without relying on other parts of the application. Consider using external commands to achieve this.
     1122. When calling external commands or global tools,  include a debug entry entry of the call with its arguments. This makes it easy to reproduce the call outside the application for debugging.
     1133. Avoid deleting or renaming old functions that other tools might depend on. Instead, mark them as deprecated, have it to call the new function with the updated parameters, and add a warning message to inform developers of the change.
     1144. When refactoring a function, do not change the final behavior. This can cause unexpected results in applications that use the function.
     115
     116
     117=== Remember ==
     118* Be as descriptive as possible.
     119* Don't use generic names.
     120* Don't use negative logic in variable names.
     121* Be consistent with the other elements.
     122* Map your names to the application's domain terminology.
     123
     124Golden rule: Spend a few minutes thinking about your variable names.
     125
     126
    114127
    115128
    116129== Wisdom ==
    117 1. The secret to building large apps is never build large apps. Break your applications into small pieces. Then, assemble those testable, bite-sized pieces into your big application.
    118 1. Reducing the amount of code in your product should be a goal.
    119 1. If you are changing more than 25% of a class or method, consider simply rewriting it. You will write the code more cleanly.
    120 1. Accept that you have no idea how this will grow. The key is to acknowledge from the start that you have no idea how this will grow. When you accept that you don't know everything, you begin to design the system defensively... You should spend most of your time thinking about interfaces rather than implementations.
    121 1. Write all your functions to be able to work independently without requiring extra data like global variables, this let's you to test them independently, or even re-use them elsewhere. ''Thanatermesis''
    122 
    123 ==== Common Excuses For A Software Rewrite ====
    124 * The Code Sucks
    125 * "We're So Much Smarter Now"
    126 * We Picked The Wrong Platform/Language
    127 
    128 ==== Why Rewriting Is (Almost) Never A Good Idea ====
    129 * It Always Takes Longer Than You Expect
    130 * Markets Change
    131 * Existing Customers Become Frustrated
    132 * Refactoring Can Cleanup The Code
    133 * You Don't Control The Rewrite, It Controls You
     130* The secret to building powerful apps is to never build large apps. Break your applications into small, testable pieces. Then, assemble those pieces into your larger application.
     131* Reducing the amount of code in your product should be a goal.
     132* If you are changing more than 25% of a class or method, consider rewriting it. You will likely write it more cleanly.
     133* Accept that you don't know how your application will grow. This leads to a defensive design. Spend more time on interfaces than implementations.
     134* Write functions that are self-contained and don't rely on global variables. This makes them easier to test and reuse.
     135
     136
     137==== Why Rewriting is (Almost) Never a Good Idea ====
     138* It always takes longer than you expect.
     139* Existing users become frustrated.
     140* Refactoring changes your code and behaviour.
     141* You don't control the rewrite; it controls you.
    134142
    135143
     
    177185
    178186
    179 == Extra ==
    180 
    181 * Always use local variables, don't share them externally or you can have catastrophic results
    182 
    183 * Never change the value of a local variable if your function is more than 15 lines long, for that, use a new local variable
    184 
    185 * Use a good powerful editor with good plugins, like vim with a good setup
    186 
    187 * trap signals, like exit errors etc
    188 
    189 * the simplest procedure/option is the best, do not think in complex ways to do supa-dupa-intelligent-features if they are not needed
    190 
    191 * Think on multi-work, if you use a temporary directory called /tmp/myapp, you could have conflict when another user try to use the same application which will point to the same location (so /tmp/user-myapp is a good option). Or also including the ID of the process is also a good method for avoid re-using the same directory if the application can be launched multiple times
    192 
    193 * [https://web.archive.org/web/20091103172142/http://www.makinggoodsoftware.com/2009/06/04/10-commandments-for-creating-good-code/ 10 rules for creating good code] that must be read until becomes subconscious
    194 
    195 * [https://forum.elivelinux.org/t/recommended-elive-programming-practices/2581 Recommended Elive Programming Practices] which is a list compiled (get it? hahahahahahahahahaha) by the community of Elive
     187== Extra Tips ==
     188
     189* Always use local variables. Avoid sharing them externally to prevent unexpected side effects.
     190
     191* In functions longer than ~15 lines, avoid reassigning local variables. Use a new variable instead for clarity.
     192
     193* Use a powerful code editor with good plugins (e.g., Vim with a good configuration).
     194
     195* Trap signals to handle exit conditions and errors gracefully.
     196
     197* The simplest solution is usually the best. Don't over-engineer features that aren't needed.
     198
     199* Design for concurrency. If you use a temporary directory like `/tmp/myapp`, you'll have conflicts if multiple users or processes run the application simultaneously. Use user-specific or process-ID-specific temporary directories (e.g., `/tmp/myapp-<user>` or `/tmp/myapp-<pid>`).
     200
     201* [https://web.archive.org/web/20091103172142/http://www.makinggoodsoftware.com/2009/06/04/10-commandments-for-creating-good-code/ 10 Rules for Creating Good Code] - that must be read until becomes subconscious