- I started a txt file, added ideas to it every so often, then I felt I had enough material to shape into a document, the difficulty came in figuring out how to group the principles.
- Some are my own, some are well-known, and some are a mixture. I also provide some links at the end.
- Do offer additions/alternatives/your views. Cheers.
- An idea in isolation may say little. But many ideas en masse may say a lot.
- Consistent style, whatever the style is. (Develop your own style for your own code. Maintain someone else's style for a group project.)
- Use comments. (Especially for code that you use rarely e.g. once a quarter. Especially for anything that gave you a surprise/took a while to debug while coding.)
- Use a consistent style of indentation. (Note: in my view Allman style indentation is clearer than K&R style/one true brace style.)
- Text barriers between sections of code e.g. '=========='. (I use 3/5/10/15/20/30/50 equals signs.)
- Brevity is generally good, but not if it reduces clarity. (It may be better to avoid succinct but cryptic code.)
- Use a consistent case for variable/functions/method names. (In some languages you have to.)
- (All of the above points make it easier to maintain a script, or decipher a script you've never seen before.)
- I tend to have a system/set of rules for everything. When I'm unsure of how to present something, I follow the system. If the system doesn't have a rule for something, I reflect on what the rule should be. If I disagree with something in the system, I change it. (E.g. one minor change was changing the variable names 'vPrefix'/'vSuffix' to 'vPfx'/'vSfx', I replaced these in every script.) (One question was: I use 'o' for objects, 'v' for other variables, but what if a function parameter could be either of the two: I call it 'v', and do IsObject(), and create a new 'o' variable if necessary, that way round because there's less overhead to create a 2nd object reference versus copying the contents of a string.)
- I tend to split comments/log info/files with one file/folder per month/year.
STYLE (VARIABLE NAMES)
- I do the following, but they are just suggestions.
- Prefixes: variables v. functions. A clear distinction between variable names and function names, e.g. use prefixes for both, or end variable names with digits. E.g. vMyVar / my_var / var1, MyFunc. (E.g. outside of AutoHotkey, variables and functions can have the appearance 'XXX(Param1)', so being able to distinguish between variables/functions can be useful.)
- Prefixes: type. Prefixes to indicate a variable's type, e.g. similar to Hungarian notation, but not necessarily the same. E.g. in AutoHotkey I use 'vCamelCase' for strings/numbers and 'oCamelCase' for objects.
- Prefixes: global. Use a prefix to indicate any global variables. E.g. 'g_'. I use 'vGbl', or 'AX_' to mimic AutoHotkey's 'A_'.
- Use meaningful variable names e.g. 'path' v. 'p'.
- Collect a list of common variable names. Having such a list makes my code more reusable (you can just copy and paste blocks of code), and reduces the amount of time spent on choosing variable names.
Some example variable names:
Code: Select all
oAcc,oDict,oWB,oXl [for specific object types] oArray,oChild,oElt,oElts,oFunc,oTemp vChrSize,vWA vCol,vRow vColBGR,vColRGB vCtlClass,vCtlClassNN,vCtlExStyle,vCtlStyle vCtlX,vCtlY,vCtlW,vCtlH,vCtlR,vCtlB vCurX,vCurY vDate,vDateC,vDateM vDelim,vSep vDHW,vSCS,vTMM [A_DetectHiddenWindows/A_StringCaseSense/A_TitleMatchMode] vDuration,vElapsed vEltClass,vEltTag vLimW,vLimH vMax,vMin vPath,vName,vDir,vExt,vNameNoExt,vDrive vPfx,vSfx vPID,vPName,vPPath,vPVersion vText,vTemp,vInput,vOutput vTitle,vUrl vWinClass,vWinExStyle,vWinStyle,vWinTitle vWinX,vWinY,vWinW,vWinH,vWinR,vWinB vYear,vMonth,vDay,vHour,vMin,vSec,vMSec [also: vNow,vToday,vWDay] vAddr vAttrib [file attributes, see FileExist function] vCaseSen vCount vData vDelay vDoRecurse [and 'vDoXXX' generally] vDQ [double quote] vDummy vEnc [encoding] vIndex vIsMatch [and 'vIsXXX' generally] vIsReady vItem vLen vList vLog vNeedle vNum vOcc [occurrence] vOffset vOpt [options] vPos [position] vPrompt vRegKey vRet [return value] vType vUnused
- Prefixes. By using variable/function names with prefixes it makes it easier to rename variables and collect information. (Using prefixes makes it easy to text replace and grab things without replacing/grabbing the wrong thing.)
- Comment blocks. I prefer to start every line with a comment character, over using a comment block, e.g. it's easier to parse, and if you grabbed the line in isolation you'd know it was a comment.
- Autocomplete drop-down lists. These can be useful, however, using hotstrings can be faster (for words/lines of code), and can work consistently across multiple editors.
- Syntax highlighting. This can be useful, however, it is worth considering how readable code is when syntax highlighting is not available. E.g. choices for function/variable names can aid readability.
- Editors/IDEs. It's good if you can code without too many knickknacks to assist you. I use basic editors, but a lot of hotstrings/text functions written in AHK.
- Consider avoiding syntax that is unique to a language. Write in a way that is more readily translatable.
- Consider compatibility. Forwards/backwards/two-way compatibility. Write in a forwards compatible way. (Where two forwards compatible alternatives are available, consider using the more backwards compatible way. E.g. in AutoHotkey use the Length method rather than the Count method.)
- Write in the same style in all programming languages. If you want to take advantage of a rare technique in a specific programming language (e.g. for performance gains), wrap that technique in a function.
- Test something even if the documentation description seems obvious, or the task simple.
- It's hard to make any statement in IT that doesn't have caveats/exceptions.
- If the behaviour of something is unclear, the reader will infer their own assumptions/expectations.
- Constants. State the names/values for all of the constants that you use. E.g. WM_COMMAND := 0x111. These are useful for debugging and as Internet search terms. Winapi constants that I can't find online I usually find in .h files that came with Visual Studio, within C:\Program Files (x86).
- Modifications. If you copy and modify someone else's code, state with a comment that you've modified it.
- Links. Consider adding Internet links to code e.g. for lists/discussions/source code/Winapi functions without standard individual MSDN pages e.g. Gdip/msvcrt/undocumented functions. I usually omit links to Winapi functions that have a standard MSDN page.
- Keep a record of links, they are gold. Keep text files with webpage titles/urls. (I have AutoHotkey scripts to copy Internet Explorer titles/urls to the clipboard, and append them to a text file. I backup my AutoHotkey forum posts for text searching. I use Bing to search for obscure AutoHotkey posts.)
FUNCTION DESIGN (WRITING FUNCTIONS)
- Function names. Some patterns that I use:
ItemOperationProperty(Item, ...) [sometimes UtilityItemOperationProperty if I'm adding functionality to an external process]
E.g. Is/Get: ItemIsProperty(Item)/ItemGetProperty(Item)
E.g. Set: ItemSetProperty(Item, NewValue)
E.g. EditGetText/EditSetText (Edit control get/set text).
- Parameter order. I use consistent first parameters based on a function's name, ProcessXXX(PID, ...), WinXXX(hWnd, ...), CtlXXX(hCtl, ...). There can be exceptions sometimes.
- The principle of least astonishment. Consider any assumptions that people would make about functionality. It's good to either meet those assumptions, or warn that you've made a different choice.
- Small general functions over big specific functions. You might want to write a function for a very specific task. However, it can be better to consider splitting it up into functions that are more widely reusable. There can be exceptions.
- Function candidates. Regular three-liners are candidates for functions, even two-liners. If you use a small amount of code three times or more, consider making it a function. You could possibly just use hotstrings for this.
- Function candidates. Avoid writing complicated code twice. If you use a big amount of similar code twice or more, consider making it a function.
- Function candidates. Wish-list functions. If you wished that a certain function already existed, or were surprised that it didn't already exist, consider making it a function.
- Write two versions of a function. A less-readable higher-performance function, and a more-readable lower-performance function. The simpler function can be used to test the more complex function.
- Medium-length function names. Use function/method names that are neither cryptically short nor unnecessarily long. E.g. too long: lastIndexOf/toUnsignedString/equalsIgnoreCase. E.g. too short: stoi.
- Global variables. Functions could use global variables for defaults, but ideally you'd be able to override those defaults by specifying a parameter, and not be required to temporarily edit any global variables. E.g. in AHK: A_DetectHiddenWindows/A_StringCaseSense/A_TitleMatchMode.
- Letters v. numbers. It's better to use letters for options, they are more memorable, cf. numbers that have no meaning. E.g. AutoHotkey's Loop File: 0/1/2 v. F/FD/D. You could also use powers of 2 (including 2**0=1) with friendly constant names, that can be combined using bitwise-or.
- Comments/examples. For any function, consider adding comments regarding what is expected for each parameter/the return value, and consider adding a one-line example showing how to call the function. The example can be useful to demonstrate typical parameter values and a suggested variable name for the return value. Without the example, the function could be quite opaque.
- Hide away low-level functionality. Ideally, in my AHK scripts, DllCall/NumGet/NumPut shouldn't be visible, such code should be inside a function.
- Pseudo-multithreading. If a task in my main script takes too long, I make it into a function, and run it as a separate script. You can achieve multithreading by using RunWait, or checking if various process exists, or communicating between scripts via messages/ini files or some other intermediary.
Some further more specific points:
Thoughts on AutoHotkey - AutoHotkey Community
parameter order - AutoHotkey Community
- Backup. E.g. I have a script that copies just a small number of important files (modified since the last backup) to a folder.
- Handles. Check that you deleted the handle. Close what you opened. Avoid leaks.
- Recursive functions. Recursive functions exist, but generally I don't use them.
- Unused characters. When dealing with delimiter-separated strings it can be useful to identify/keep track of a character not present in the string.
- Loops: first/last items. The first and last item often need special handling. Sometimes you can simplify the logic by adding a last item as a dummy item. See also: the 'off-by-one error'. E.g. checking for consecutive duplicate lines, you check the current line against the previous line, but for the first line, there is no previous line.
- Loops: unused characters. When comparing items, you can use unused characters/strings that will definitely not match items in the list.
- Combining date variables is unreliable. E.g. A_YYYY A_MM on New Year's Eve/Day could return January with the incorrect (previous) year. E.g. the month variable updated, but not the year variable.
- Machine code functions can be useful for bit/byte manipulation, that would otherwise be slow in the target language.
- Some functions open and close access to something each time. Things can be faster when you dictate the opening and closing.
- Benchmark tests. Compare the speed of two approaches, by doing them multiple times (e.g. thousands) and comparing the durations.
- Use hotstrings (text expansion) for variable names, lines of code and blocks of code.
- I often write some basic code, then improve it, then improve it again etc. (The same applies to comments.)
- Acquire as many wish-list request ideas as possible before beginning a project. It can be easier to add in more functionality at a later date, if you had anticipated it, writing your code in a flexible/adaptable way.
- ... Although: use software, and you get more ideas. Often it's evolution, one idea leads to another.
- No update is better than a bad update.
- Adding self-contained features (e.g. functions/A_ variables in AHK) is usually easy.
- Changing the syntax/parser can lead to bugs.
- GitHub exists, but I don't currently use it much.
- Tests. Creating/running tests is the solution. I avoid using updated software until people have had time to test it.
- Test code. Write test code to confirm that your code/functions work as stated. Do this.
- Small-scale tests. Test the system on a small amount of dummy data.
- Test before sharing. Test your script before sharing it with others, even the simplest script, this will save you time by avoiding a prolonged back-and-forth.
- To-do list. I use the label '[CHECK]' for code I want to double-check. I often write a to-do list at the top.
- Compare versions. Use WinMerge (or equivalent) to compare code, before/after.
- Website updates. When working on websites, try the website on different browsers/on a mobile phone. Note: websites can be slow to update on Chrome.
- Use MsgBox to preview things. MsgBox paths/targets/urls/JSON before doing the first FileMove/Run/download/API call etc.
- Hidden characters. You can use Ord to help identify hidden/problem characters e.g. zero-width space, see the 'characters that look similar' list:
jeeswg's characters tutorial - AutoHotkey Community
- Fixed-width fonts. Using a fixed-width font, e.g. Courier New, gives each character the same width, which can be useful sometimes.
- In AHK, I turn on #Warn, and use MsgBox/SoundBeep/FileAppend/ListVars/ToolTip/the special Clipboard variable. I also use a custom function to print to console.
- Create a to-do list. Break things down into subpoints. Some small/research tasks, e.g. writing pseudocode, can be useful/important to do and yet easy wins.
- I view projects as taking a finite or an unknown amount of time. Either I have all of the skills already or some research will be required.
- Sometimes you can do more by switching between projects. As lethargy sets in, you can move to a different project.
- Doing multiple projects at the same time can be useful, because something in one project may be relevant to another project.
- Grouping a to-do list. Sometimes I group somewhat-related items together or organise items in a chain, where vaguely related things lead into one another in a satisfying way.
- Some programmers have good taste. Good taste is everything.
- If you want a good language, consider writing a language aimed at beginners. This is necessary but not sufficient. (E.g. the following have some good features: AutoHotkey, BASIC, Excel functions/macros, Python.)
- Use 0-based/1-based indexes for whatever's more intuitive. Note: 0 is useful as a not found indicator. Use 1-based indexes for character positions (the nth character in a string, e.g. finding a needle string in a haystack) and the nth item in a linear array. 0-based indexes can be good for character selection e.g. EM_GETSEL (e.g. to specify selections starting before/after characters, not just which characters are selected, i.e. sections v. posts), and offsets in binary structs (e.g. and offsets in binary structs (e.g. this slice of data starts 4 bytes after the beginning of the variable).
- It can be easy to add in new functions to a language, any bugs exist only within the functions, but adding new syntax features is more complicated and risks introducing all manner of bugs.
- Ideally a language should be easy to parse.
- Ideally a language has a simple syntax, with reasonably short memorable built-in function names. (E.g. it is better for a language to not be too dependent on autocomplete drop-down lists.)
- Different syntax choices can increase/decrease readability. (Also, consider how readable code is when syntax highlighting is not available.)
- When I want to understand something in IT I normally try to write a simple 'hello world' script for it and then try playing about with it.
- E.g. for AutoHotkey:
- Can I get a script to send a click at regular intervals.
- Can I get the script to start/stop via a physical keypress/key combination.
- Can I write to a text file.
- Can I identify in some way what the current window is.
- Can I get text from the clipboard.
- Can I get the current date.
- And then ... let's have a look through the documentation's index.
- Learn by searching. You can learn a lot by typing things into search engines. By aggressively googling. E.g. multiple keywords, error message text.
- Measure. RegEx is handy as a universal measure of a good programmer.
- Sources. With 2 sources for the same thing, I feel more sure of what the situation is.
- Learn one language, learn them all.
- Types. You could learn a language like AutoHotkey or Python, get good at it, and then move on to C++ quite easily. The one major difference is that with C++ you have to be more specific about string/number/object types, which can potentially clutter code and detract from the real code.
- 10% of core features in a programming language will be needlessly difficult to work with. Often I will write custom functions for such situations.
- 'Toy' languages. I don't see any particular dividing line between scripting or programming languages, between Excel VBA, Python and C/C++, it's all programming.
- Core concepts. When learning a new programming language, I start with strings/maths/dates/objects functionality, and also try to interact with the Winapi. Programming languages are basically: assignments e.g. var := 3, if statements, loops and functions.
- Learn by doing. Sporadic then systematic. I think it's a good approach to learn sporadically/haphazardly, to learn it when you need it, and then to learn systematically, to fill in the gaps and increase your overall understanding.
- GUIs. I was used to programming in terms of: perform these actions in this order. I was unsure of how GUIs would work, and what system I would prefer. For me, it turns out that writing lines of code to create GUIs is more intuitive and simple than trying to program 'visually' by clicking on things etc. So, I write a few lines of code to create the windows/controls, and I create some functions/subroutines that handle certain events (e.g. handle a control being clicked on, or the enter key being pressed), and that's it.
- Better safe than sorry.
- E.g. when writing demo scripts, only set an Edit control's text if it's empty.
- E.g. create/write to a file that is unlikely to already exist e.g. use the current date/time in the file name, yyyyMMddHHmmss.
- E.g. if creating multiple files, place them in a new folder, instead of the folder that contains the script.
- When testing forum scripts, check for commands such as FileAppend/FileDelete/FileOpen/Run.
THE GOLDEN RULE
- Avoid maintaining two versions of the same thing.
- (A caveat is to make the two versions increasingly comprised of identical components.)
- (Sometimes it's better to start again from scratch, rather than try to amend something.)
THE GOLDEN RULE OF OOP (A PERSONAL VIEW)
- Don't use OOP. Keep functions and data separate. Store information in linear/associative arrays or structs. Apply functions to those arrays.
- (While OOP is not automatically a negative, it generally overcomplicates things. It is overused and misused.)
CULTURE PROBLEMS (A PERSONAL VIEW)
- We have culture problems: OOP, the Ribbon, appearance over performance, OSes lacking in customisability.
- Also, there are too many programming languages/web frameworks/content management systems/Linux distros.
- Also, another problem: creating a new programming language when we should have created new functions/a new function library.
- If you're writing a program or operating system, make it automation-friendly. E.g. support multiple WM_COMMAND or WM_USER or other messages.
- If you're creating a computer keyboard, make it AutoHotkey-friendly. E.g. make it so that the Fn key can be detected in AutoHotkey's KeyHistory.
[C++: small updates]
Oral History of Bjarne Stroustrup - YouTube
some of the things people are most excited about [about] C++11,
actually, [are] not the advanced features, [they're] some of the simplifying features
[Python: Python redone would use curly braces]
Oral History of Guido van Rossum, part 1 - YouTube
if I were to design a new language today ...,
if I would use indentation ...,
every other language ..., all curly braces-based
LINKS (MULTIPLE PRINCIPLES):
Zen of Python - Wikipedia
PEP 20 -- The Zen of Python | Python.org
Category:Software development philosophies - Wikipedia
List of software development philosophies - Wikipedia
Computer Programming Principles - Wikibooks, open books for an open world
LINKS (INDIVIDUAL PRINCIPLES):
Principle of least astonishment - Wikipedia
['If it ain't broke, don't fix it.']
Bert Lance - Wikipedia
[my paraphrase: 20% of the people produce 80% of the stuff]
Pareto principle - Wikipedia
Don't repeat yourself - Wikipedia
[off-by-one e.g. sections v. posts]
Off-by-one error - Wikipedia
Not invented here - Wikipedia
Order of operations - Wikipedia
LINKS (INDIVIDUAL PRINCIPLES) (FURTHER):
KISS principle - Wikipedia
Necessity and sufficiency - Wikipedia
Feature creep - Wikipedia
You aren't gonna need it - Wikipedia
[As an answerer, I will…]
Stack Overflow Culture | Jon Skeet's coding blog
Hofstadter's law - Wikipedia
Ninety-ninety rule - Wikipedia
LINKS (AUTOHOTKEY FORUM):
your personal AutoHotkey style guide - AutoHotkey Community
which languages should I learn to learn DllCall and Windows API Functions? - AutoHotkey Community
Thoughts on AutoHotkey - AutoHotkey Community
parameter order - AutoHotkey Community
Debugging tutorials - AutoHotkey Community