Becoming a Better Programmer
Whit
Posts: 4,191
All,
As a self-taught programmer for my hobby projects, I've developed the ability (most of the time) to figure out something - code wise - that works. But I am never sure if there is a better or simpler way of doing the same thing - "the right way."
What I would like to learn now is how to be more efficient, more elegant, and how to produce code that is considered "good form." I can work in BASIC, PBASIC, Spin, and have a very elementary understanding of C. I know that time and more experience always help, but I would also like some theory, rules of thumb, or instruction.
Looking at well-written code always impresses me so much and I learn new tricks that way, but I wish I could be a little more systematic in this study.
Any legitimate short-cuts, tips, or suggestions would be appreciated! Till then I will keep hacking away at it...
As a self-taught programmer for my hobby projects, I've developed the ability (most of the time) to figure out something - code wise - that works. But I am never sure if there is a better or simpler way of doing the same thing - "the right way."
What I would like to learn now is how to be more efficient, more elegant, and how to produce code that is considered "good form." I can work in BASIC, PBASIC, Spin, and have a very elementary understanding of C. I know that time and more experience always help, but I would also like some theory, rules of thumb, or instruction.
Looking at well-written code always impresses me so much and I learn new tricks that way, but I wish I could be a little more systematic in this study.
Any legitimate short-cuts, tips, or suggestions would be appreciated! Till then I will keep hacking away at it...
Comments
Like you, I'm mostly a self-taught programmer. I think the thing that has helped me the most is never being afraid to start completely over on a coding project if I think of a better way to restructure the solution. When I'm in a hole, I just quite digging, climb out, and begin anew. I've learned more from my mistakes than any instruction could ever have taught me.
-Phil
I write lots of code lately with my current job, and If at any time there needs to be a change in code I need to be able to address it quickly. I'm big into state machines and perhaps I am old school that way but generally when I plan out my code I create a flow chart. My flow charts are constructed in a way that each node is a "fall through" in it's own right and each node has it's own index or address. The nodes control which index is assigned based on the flowchart condition or event, and a dispatcher of sorts jumps to the currently active node. This fall through-dispatching method allows for other state machines to be introduced and run independently because they would have their own independent index counter and dispatcher.
The main point is being able to wrap you head around the code and find where you are or where you need to be in code relatively easily.
A current project I am working on has several different programming areas that at any time need to be changed or modified.
- R&D stage Schematic and PCB development ... Program and circuit design proof of concept
- The main board has a PIC micro programmed in pure assembly
- The touch screen display has it's own native code that needs to communicate bidirectionally with the PIC micro (flawlessly)
- The images used in the display need to be created somehow and compiled into a native display friendly format
- The SD card used in the display must be properly formatted and contain the necessary image deck(s) to work with the display program
- There is also the real world mechanical aspect of driving motors, relays, SSR's, light's, reading sensors, etc.
... This is just one project, the same scenario is true for any other project, since the company is migrating many of their machines to touch screen displays.
Each machine has a different operation and a different set of code instructions. Good programming techniques allow you to switch gears from one project to another efficiently.
...and yes, I am also self taught.
I'm atypical, I like the shortest most compact code possible, with plenty of comments . I don't usually name pins, or name variables with SYMBOL. Internal variable names B0, W2 and HIGH 5 are more readable to me. Not the best for sharing with others though. Sometimes when I'm writing code for a magazine article I'll conform a bit.
I'm weird that way. Of course this flaunts convention and flies in the face of Parallax's own fine recommendations at https://www.parallax.com/go/PBASICHelp/Content/LanguageTopics/Reference/ElementsStyle.htm
Be verbose when naming constants, variables and program labels. The compiler will allow names up to 32 characters long. Using meaningful names will reduce the number of comments and make your programs easier to read, debug and maintain.
* Comments, comments and more comments - sometimes as much as there is code.
* If you find you are writing similar code several times, consider re-working it to use a subroutine, even if it has to have arguments to cope with variations.
* Use 'meaningful' names for subroutines, e.g, CreateFile so code reads something like IF A ==B THEN CreateFile
* I've fallen into the habit of prefixing variables with their type, e.g, intCounter1, fltTemp, boolState
* I declare lots of constants with meaningful names, e.g. notLit = 0; isLit = 1, or switchPos1 = 1; switchPos2 = 2, etc., allowing me to write something like IF switchPosition == switchPos1 THEN...
* Look at other people's code and 'borrow' any approaches or techniques that help.
A friend of mine posted a picture on facebook of the stack of paper that represented the code for the Apollo Guidance Computer, which was about 6' tall. Since the AGC only had room for 36 Kwords of ROM and 4 Kwords of writable storage, that ~16K pages of code only had a maximum average of about 2-1/2 lines of code per page, leaving *lots* of room for comments ! Perhaps we can learn something from NASA.
As a side note, we have increased storage density by a factor of nearly 1 trillion (10^12; I'm not British !) since then (the 72KB ROM was 1 ft3, and the 8KB RAM was 2 ft3).
Another self-taught programmer here...
In my opinion, the three most important items for becoming a better programmer are sizing variables appropriately, commenting the code you have written, and using established or distinguishable naming conventions for your variables and functions.
Concerning variables, if you only need a byte to hold data, then use a byte to hold that data. In other words, do not use a long to hold a bytes worth of data, unless you have a very specific reason for doing so.
When it pertains to comments, I like to document items of importance, the flow of a program or thread, and code that is hard to comprehend.
Naming conventions on the other hand, are always open for debate, and are often chosen to suit the needs of an individual programmer and his style of writing, but it is wise to adapt a generally well accepted naming convention, if you will be writing code for someone else or if someone else will be reviewing your code.
A little over six years ago, Parallax made a small push for Gold Standard Objects for the OBEX, which lost steam as quickly as it developed. The idea was a good one, but due to lack of community support, it fell to the way side.
Anyhow... there was a thread pertaining Gold Standard Objects, in which I discussed naming conventions for variables and functions. There are likely to be some folks that would disagree with what I wrote, but the concept of naming convention is discussed and you should be aware of naming conventions, if you want to become a better programmer. For further discussion, refer to: https://forums.parallax.com/discussion/137491/gold-standard-objects-up-for-commission/p2
Additionally, there are two trains of thought pertaining to naming conventions, which is to name everything as short as possible, in order to be more productive (faster writing of code) or being verbose, in order to make it easier to read and comprehend (slower writing of code). I personally prefer code that is verbose, but that is just me.
For example
I prefer nStepIndex++ as compared to stpIdx++.
I guess the best way to build a better mousetrap is to keep building mousetraps...
@idbruce and @erco - thanks for the links and the reminder that there is a lot of great advice on these forums and in Parallax resources. I need to go back and look around.
Don't believe everything you read on Facebook. Certainly don't jump to any wild conclusions from it, like 2.5 lines of code per page or voting for Trump.
I have long suspected there is something bogus about the claims made about that picture.
Today we can find out. We can download the original AGC source code and check: https://github.com/chrislgarry/Apollo-11
In there I find a total of 130667 lines in the assembler source code files.
There are 34256 lines of purley comment (Starting with "#").
There are 14763 blank lines.
That means there is only 81648 lines of source text.
The ratio of comment lines to source lines is about 40%.
Now: Old computer line printer paper, as in the famous Hamilton picture, has 60 lines per page, if I remember correctly. So printing out the entire AGC source would amount to 130667 / 60 = 2177 pages.
That is less than the 2500 pages in a box of regular printer paper today, which is less than a foot high, about 25cm or 10 inches.
So what is all the rest of that stack of paper? Well, I guess there were a few AGC versions, for different missions. They might have included test code and so on.
Also, assuming one machine instruction word is generated by one assembler instruction then we ain't going to fit 81648 instruction words in the 36Kword memory. But, as far as I can tell that source code repository holds both the code for the Command Module AGC and the Lander AGC. So only about 40 thousand lines of code each. Not all source lines generate code, they are literal definitions and so on. So, I think this all adds up.
Anyway, poking around in AGC source I'd say it looks pretty good. Almost every line carries some useful comment about what and why it is there.
In my experience of working on projects were the 8080/86 assembler source is a stack of paper only 10 inches high things can become very non-trivial to even find!
Many of you point toward this idea!
On the other hand:
"Perfection is the enemy of the good"
- Voltaire
"Were it not sinful then, striving to mend,
To mar the subject that before was well?"
- Shakespeare
(Or "If it ain't broke don't fix it")
We should not strive for perfection. It's unattainable, hence depressing when you don't get there. It's expensive. It's time consuming. Before you get done everyone will have lost interest, including yourself.
Yes, I'm sometimes guilty of perfection hunting. Tweaking code formatting, tinkering with variable/symbol names, refactoring this and that. Then realizing the whole approach is dumb and start doing it over. It's a ridiculous life sucking loop of despair....
Then there are the bridge designers who remove everything they can, on reaching perfection the bridge collapses. See recent Florida incident.
My first programs were written on an Apple ][ and a TRS 80 Pocket Computer.
My most used program on the TRS 80 Pocket Computer added feet, inches, and fractions. My Dad and I - both architects - used it until calculators became available for that function. You can get one now for less than $15.
My first programs were on a Monrobot XI, an IBM 1620, and then on a DEC PDP-12. I guess I must be a bit older than you are.
I had to get into programming via an actual course (A Level Computer Science) because there were no computers around at the time. That was only introductory, BASIC and some assembler. Most of the course was other things, numerical analysis, statistics, computer architecture.
Everything else I had to pick up on the job as best I could. Sadly I was just that bit too old to be a teenager with an C64 or such.
Over the years, I have examined a lot of code written by other people. It is noteworthy to say that some of the best and most interesting code that I have ever examined, was poorly documented, lacked proper naming conventions, and was generally very difficult to get a grasp of what was occurring during run-time, unless of course by stepping through the program with a debugger.
There have been many times, that I would rewrite someone else's programs with comments and proper naming conventions, just to get a better handle on program flow, for alteration purposes.
Brilliant code can often be the most difficult code to read, because the brilliant programmer that wrote it was to lazy to make it neat or understandable to others Just remember that programming brilliance doesn't require naming conventions or documentation
I suppose a person could say that just because code appears to have been written by an amateur, doesn't mean that it actually wasn't written by a well seasoned professional programmer
I also had a Timex Sinclair PC and a C64.
Here is another walk down memory lane!
Think I still have an unused box of my custom printed fan-fold paper.
Oh the fun days of 17" fan-fold printouts
In the low 80's I started putting my code listing on microfiche.
Things got better, and I became more productive, once I learned to be brutal with myself. If it doesn't work, it can't be correct, so quit making excuses and look for the mistake!
Also, regarding commenting, I typically comment the beginnings of spin methods, just to say what the parameters are and what it does with them. I comment every line of PASM code, because assembly isn't as easy to read as a higher-level language.
-Phil
Programming is a lot like writing. The more you do it, the better you can be, given you are willing to explore, take some risks, laugh at the laughable.
I like to make it work, then make it work better. Often, I'll then rewrite it with all the things I learned.
As for "the right way."
Good luck with that. Seriously.
I'll express a contrary view here and say there are two cases:
Case one, work for hire, "official" in some way. In this case, "doing it right" means doing it in a way that conforms somehow. And again, this is like writing, formal writing of some kind. This is also true for something intended for others, or a shared effort. Communication is probably the best thing you can do. Doing this requires more. You have to make it work, and make it work in a way, or presented in a way that is also defined. This can be two problems, or something like a meta problem, instead of just the problem, whatever it is.
Case two, and by far the more fun case and majority case for me, is I wrote it, whatever it is, for my reasons. I like to share, and I do, and it's freely given. In this case, I will write it the way I feel makes sense, and that is a balance of time, purpose and enjoyment. The right way might just be making something I wanted to happen, happen. Beyond that, there are few worries. Others can take it, rewrite it, improve on it, whatever. In this case, making it "better" or "right" may be more work and that may or may not be worth doing. It's your call, your time, your pleasure. Do what makes the best sense, and point back to "given freely" for those who may want more. You might not. We all have agency here. A lot of this is getting at the problem, avoiding meta problems. Make your stuff happen. That's why you started.
On comments, I like narrative ones, not so much functional.
X := input*5
Commenting that in the functional way would be something like, "X is made equal to input from DAC multiplied by 5." Kind of useless really. People can see that.
In the narrative way, the comment would be, "Scale DAC value to better match lookup table entries."
Those are far more valuable, and require fewer updates to comments. Many of them will even work when a comment is old. The intent is there, and getting at intent is probably the hardest part in all of this. True for me. I will often look at code, and I'll comment it in this way first, to understand, then to use, modify, build on, learn from.
One thing I often miss and want to do more of is to check limits, specify where it works, where it doesn't, and with what or how. Doing more of this will help you, and others who may encounter your code, to make better use of it. It also helps your thinking. Prior to writing something, thinking through those comments, or even just writing them out, can really help your focus. Each thing you write, function, procedure, whatever, gets a more clear, more useful, more understandable definition.
If it's not needed, playing code golf isn't going to add value, unless it is somehow needed. Compute time, RAM, that sort of thing. Make it work, then make it work better, then make it work faster and or smaller. Refactor, rewrite, all apply here.
If you aren't having some fun, you are doing it wrong, or need to get paid.
Also, if you want to share, do it unabashedly. Bad code, or crazy code, whatever, is still code. It can still be used, learned from, talked about, and all that. The more you share, the more you learn about all these things and how to better communicate. It's a good thing.
Same!
I still have a Pocket Computer. It's the fold out one, 2kb RAM, little 20 char LCD.
For years I had a pile of sheet metal layout tools running on it. Computations of various kinds. Moved those into a CAD system, and then didn't need to do much else, so there you go.
I also used it for statistical process control. I would input measured values over time, get back tolerance compliance data. This worked very well. I rarely had parts come back. Company adopted a lean scheme a few years later.
Like many programmer I like to copy and paste, say the existing Address-List-Window is quite similar to the new wanted Object-List-Window. So I copy the Address-List and start changing it into the new wanted List, removing and adding code.
Later on the duplicate finder would show me the stuff both lists have in common and I am often able to refactor the code out into modules used by both lists.
Modular programming is very helpful to allow reuse for other projects and shorter listings. I worked for companies that had the rule that no source modul was allowed to be longer as a printed page without explicit permission, I personally found this too restrictive.
I really do like to read @JonnyMac's code, he is good at keeping code duplication out by using short sub-routines, has a consistent naming, shares a lot of useful code and is a cool guy on top of it. One can learn a lot of good coding style by just reading his sources.
There are usually rules how to program provided by your employer, say if CamelCase should be used (or not), if variables should be prefixed with a type (or not), programming for a living since 30++ years I can easily adapt to the wanted style, same goes for the used languages and overall project structure.
What is common is the importance of descriptive names for everything, I almost HATE programs where I find variables using I,J,X or other single char names, every professional editor I use has code-completion, so longer names take not longer to type, but increase the readability in any language.
Very early in my life I programmed in COBOL, a very, very, very descriptive language with a lot of text to type and a quite restrictive overall source structure, but if done right one can read COBOL sources like plain English, not needing much comments.
As @potatohead mentioned commenting what the source code does is USELESS, a programmer can read that right out of the source code itself, the comments need to show WHY things got done to archive WHAT.
As @Phil said a short description on top of some code describing parameters, results and GOAL is most efficient.
Enjoy!
Mike
I just want to say I agree with this too. Useless comments just add fluff and make it harder to read (remember "word problems" in math class and having to sort through the fluff to find the real problem?).
Also, the best thing I do to learn how to program is hold a code review. This is difficult, of course, because no one has time to ever read someone else's code. But I learn more from code reviews than anything else (preferably reviewing code I've written, but I certainly learn from reviewing others' code too). So, I'll put this offer out there: if you ever write some C/C++ code and want a review of it, let me know.
And for anyone new to code reviews: be aware that getting a code review can be a very scary thing sometimes, and you NEED to have thick skin. You won't learn jack squat if someone comes in to look at your code and just says "yep, looks good!" So the best possible outcome is that they give you lots of (constructive) criticism - just don't get upset or distressed when that happens.
Almost 900 lines of code with almost no comments. When I looked at it wondering how and where I might add useful comments I could not find any such place. So I did not.
What that is is my attempt at creating a RISC V core for FPGA in a high level description language. My dilemma about commenting it is this:
If one knows ones RISC V instruction set, and knows what this code is implementing (see picture here: https://forums.parallax.com/discussion/168355/sodor-spinal-a-risc-v-core-in-spinalhdl, and know ones Scala language and the SpinalHD library, then there is nothing to say comments. The variables used and their names are just taken from the block diagram, as are all the blocks in the code so there is nothing to say.
On the other hand, if one is not familiar with RISC V and the given block diagram and Scala/Spinal then no amount of comments in the code is going to help!
Perhaps some brave soul could take a quick look at that code and tell me if my conclusion re: comments makes any sense.
I'm quite a supporter of commenting code. But often I have a downer on it because many times the comments are worse than useless, simply repeating what you are reading the code anyway or out of date or wrong or misleading.
I always find one of the hardest part of programming is thinking up names for things. Drives me nuts sometimes.
My understanding of that code is not good enough to comment more fully than I am, which may be good for this discussion. But, what I did take a while to study began to make more sense.
If I wanted to work with that code, and I do actually, but time..., I would get my references, and start mapping it all out. Once that was done, I would likely leave myself some notes. Build it, test it. Then continue from there.
Frankly, the product of that exercise would be better as blog post where the sum of the reference material, my observations and some detail related to the code would make for a nice leg up for others who may have similar interests.
I find I like comments more when there is a lot of math, or its assembly language where references to hardware, circuits all are necessary to understand things. Narrative style on those is a big win.
Or, when it's a hack, or some unorthodox use and or abuse going on.
On something like this, the intent is fairly clear, and likely more clear given more thought and review. This is descriptive language after all.
Honestly, about the only comments I can think of would be a summary of the state of the project, limitations, plans, gaffes, etc...
Theory of operation essentially. Maybe what it might be good for, and you may have those things somewhere too. I didn't look.
yes, me too.
Mike
Yep. I could not agree more.
Like many here, I am mostly self-taught. Still, I have had teachers and mentors. I think in all things we learn, it is good to look for a person that has the skill(s) we desire and ask them for guidance. I've been lucky through my career to have the opportunity to work with really bright people, and I have unabashedly asked for their guidance at every opportunity. Likewise, this forum is a constant source of programming nuggets to be mined, and I'm grateful that so many gifted programmers willingly share their tricks and techniques.
Another lucky thing for me is that I get to do a lot of focused programming -- between EFX-TEK and Adventure Sports HQ (EFX-TEK partner), I am constantly writing code for the Propeller. This gives me the opportunity to learn from my own mistakes/experience. While working at Toro I was instilled with the belief that we should always strive to improve our products. By the time I release code to a client or the public (library, magazine code) it has undergone many changes. And those never stop. I will frequently see a comment in the forums that causes me to go back and reconsider something I've written in a different manner -- that just happened today.
Thanks for taking a look. I think most of that is in the README file. As shown on the front page of the repository: https://github.com/ZiCog/sodor-spinal Including instructions on building and running it if you ever want to play.
I should probably add the block diagram and other docs I'm working to, seems that is getting updated by the original Sodor project so the link I have there to it will soon be to a version out of sync with what I have done.
I can't really add much here, others have covered most things, but I will add my two cents to a couple things...
Comments:
For high level languages (anything not ASM) I generally write "self documenting code" with good variable names and function names. So comments are not super common, mostly just to explain the trickier bits.
For ASM(PASM), I will typically comment every line, or small group of lines, because it's pretty much impossible to make ASM self documenting.
Above all else, ALWAYS update your comments when you change code, never ever skip this, nothing is worse than a comment that is wrong.
Naming:
I'm with heater, the hard part is coming up with names for things. I tend towards longer descriptive names. It's the main reasons I made OpenSpin able to have 254 character symbols, for var names and method names in spin.
Controversial Things:
Tab should insert spaces, K&R style {}'s is wrong, 6502 over Z80, etc.
However, above all else, be consistent. nothing worse than trying to read code that is inconsistent in it's style, naming conventions, etc.
Self-taught I am...and like others, I've taken formal classes and had the advantage of pretty solid mentors.
One of those mentors made this suggestion:
https://www.amazon.com/BASIC-Style-Programming-Proverbs-programming/dp/0810451158
Regards,
DJ