Working With Git
Thinking About Software
From University to a Job
This page is the culmination of 20+ years software development experience, distilled into nuggets of wisdom and guidance for the up-and-coming software developer.
There is not cheating in life, but if you take in the guidance of this page (while it is in draft or when it is finished) it will help you be a step ahead of many other developers.
If you want to ask questions or discuss any points on this page, just email me at email@example.com.
Expected Completion Date: Some time in 2019.
Last update: 02 March 2019.
- There’s no such thing as best practice.
It’s just good practice in a given context.
Likewise, there’s no such thing as a bad practice.
Good and bad practice are:
1) Someone’s opinion.
2) The result of laziness and not wanting to think about hard choices.
- Think defensively. Tools will fail you. Take a backup.
Git can stuff up. Hard drives die. A global find-and-replace can have unintended consequences.
For example: If you’re doing a tricky merged in Git, make sure all your local branch changes are committed and pushed. That way if the merge goes bad to you can simply blow away your local branch and pull from origin again.
- Don’t Repeat Yourself (DRY).
This is a good principal to apply to the whole of life, not just code.
DRY, in the context of code, means “if you’re writing the same code multiple times in different places, create a function that can be called instead”.
Duplicate code means more complexity and duplicate maintenance.
- Optimise, but not before you need to.
This is often stated as “don’t prematurely optimise”.
Again, a good principal to apply to life.
It’s OK to do get something working inefficiently the first time round. The idea is to get it working. In doing so you will learn things.
No software is built right the first time. It generally takes 2 or 3 or more iterations. Add optimisation to those iterations.
- All software must be maintained.
- Software does not live in isolation.
- The aim is to less code.
Less code means less complexity, less that can go wrong, less to test, and less to maintain, (also: less work).
- Test. Test. Test. Then test again.
- Repeat back: Repeat back requirements to the person(s) giving them to you, in your own words. This is especially important if the language isn’t your first language (for example, Indian or Chinese is your first language, and the requirements are in English).
This is a something I have my entire career, even as an English speaker receiving requirements from other English speakers.
Something experience teaches you: people miss important details when giving requirements.
Details are forgotten or not thought of. Requirements are not reviewed before delivery. Or maybe ideas or assumptions are wrong and need to be challenged.
So repeat the requirements back as you understand them, and ask questions.
To borrow (and slightly grammatically correct) the motto of a non-English speaking developer I work with: “Before starting any work , we must be clear with the requirements”. I couldn’t have said it better myself.
- Repeat and ask multiple times: It’s OK to repeat back requirements multiple times. Or ask the same question multiple times.
Sometimes details are missed the first time. And the second time.
Or something may have changed in the meantime and you haven’t been told.
In fact, always assume details are missed or being changed until the final product is delivered.
- Use //TODO: Comments
TODO comments are a powerful way of leaving reminders for yourself and telling other developers what’s happening.
I use “Remove”, “Obsolete” and “Implement” all the time.
Using TODOs is a quick way of leaving notes and task reminders in code without breaking your flow. Quickly stub out functions, “if” statements or blocks of code where you don’t want to get get stuck in the details right now but know you need to come back to.
Examples might include:
//TODO: Obsolete // Add this to obsolete code you may want to remove later.
//TODO: Remove // Add this to commented code you want to remove later, after testing.
//TODO: Implement // As you’re writing out function or code block placeholders.
//TODO: Harden // If some needs more exception/validation/scenario handling (i.e. code hardening is required).
//TODO: Bad // If some code may do bad things in edge cases.
//TODO: Test // If some code needs better bettering.
- Compact code is hard to read. Use white space and indentation.
Code is read by humans. So it needs to written cleanly and clearly. White space around lines, functions, and blocks of code helps with layout and readiblity.
In the modern age, white space costs very little (if nothing) to the compiler.
I generally add 3-5 blank lines between functions.
I add group related code then 2 lines between groups within functions.
Vertical white space (blank lines) helps when needing to quickly scan code. It works well in conjunction with lots of comments too.
Indentation is horizontal white space. Again, it helps with scanning code and identifying blocks of related code (e.g. start and end of “if” statements and functions).
Tabs vs Spaces is an age old arguments. Don’t waste time on it. I recommend tabs because if you’re using a decent, modern IDE (as you should) then you can set tab sizes to whatever you want.
The key thing to remember is: your code will be read by other people. And other people read differently to you (the may be dyslexic, had poor vision), so be respectful of that.
- Use descriptive variable/function/class names.
- Don’t get fancy or compact with code. Write long and clear.
Code is meant to be read and understood by humans.
Usually the person reading it is not you, so fancy code makes it harder for them and takes more time.
Even if you are reading it again, chances are you will need also help understanding it in 2 months time.
Compilers don’t care how fancy your code is, but humans do.
Spread you code over multiple lines, use descriptive variables, write long-hand if you can, add comments.
The key: do everything you can to help other developers understand your code.
- Comment. Comment. Comments – Write lots of comments!
Anyone who says “get rid of that comment” should be kicked out of the industry! (I’m serious)
Along with TODOs, comments are one of the greatest tools in a software developer’s kit.
The do 2 things:
1) Help other developers – this is the main reason to write comments.
2) Add a bit of documentation directly to the code.
Comments should be added everywhere – to classes, functions, enumerations, variables, “if” statement branches, blocks of code – everywhere!
The thing to understand about comments: comments should “tell the story” of what the code is “meant to do”.
Even something as simple as if(person.Age > 18) should have a comment “People over 18 are allowed to drink” within the branch of the if statement. This shows the business requirements behind the code, but it also means if you accidentally write if(person.Age < 18) and a bug is raised, whoever reads the code later can see there’s a difference between the implemented code and the intended outcome.
I sometimes even write a blank “else” in an “if” statement, even if nothing happens, with a simple comment like “nothing happens here” just so everyone if wasn’t accidentally forgotten. It also helps my subconsciously think through all use cases of the code.
- CSS (Cascading Style Sheets): Start with a global class, in an external stylesheet, that can be used everywhere.
Then override using CSS specificity only as needed.
But always in a CSS file.
Use inline styles with caution.
- Use a good IDE (Integrated Development Environment).
IDEs are a developer’s best friend. They don’t really need to be fancy to give you a productivity boost, but if you’re writing software in a basic text editor, you’re doing it wrong.
Look for an IDE with features like: global find and replace; syntax colouring; intellisense (if you can get it); language-specific error checking; setting tab width.
- Assume all input data cannot be trusted.
This includes data coming from users, APIs and databases.
Assume it is dirty.
Assume it has problems.
Review and validate.
Working With Git
- Learn and understand the core actions
- Creating repositories
- Adding/removing files for a commit
- Viewing file diffs
- Viewing file change history
- Submitting pull requests
- Completing pull requests
- Understand branching strategies
- Regularly merge from parent branches
- Commit and push to origin before merging
I recommend committing and pushing all local work to origin before you merge.
If something badly screws up with the merge then you can delete your local branch, pull from origin again, and retry the merge. This has saved me a number of times in the past.
- Create backup branches locally
Thinking About Software
- All software has entropy.
It will change and decay over time.
Why? Because software does not live in isolation.
It relies on infrastructure, platforms, tools, and dependencies that will change, which in turn cause the software itself to change.
From University to a Job
- Where’s what you need to boost your changes of getting a software development job:
- Know how to use Git.
- Learn commands for: creating repositories, branching, adding/removing files for a commit, commenting, committing, pushing, pulling, merging, diffing, viewing file change history, submitting pull requests, completing pull requests, stashing and unstashing.
- Learn about branching strategies. There are many out there. Consider what you think is a good strategy.
- Learn about merge conflicts and strategies for avoiding/resolving them.
- Learn the git command-line, but you can also use GUI tools (they can be much easier and quicker for visualising large projects and handling merge conflicts).
- Have a sample project in a public repository (e.g. GitHub or Bitbucket).
It can be big or small, but you should be passionate about it.
Use this to demonstrate you’re code, that you are proactive, and talk about it in interviews.
This is your demonstration of experience.
Include supporting files and assets in the repo.
- Start learning about:
- Application Security
- Visual Design & UX/Usability (particularly if you want to work on consumer-facing products)
- Find one language and learn it well. You will need to learn multiple languages in your career, but start with one you can focus on.
- Know how to use Git.
Random Notes that Need Review
- Pay attention to detail
It shows in your communications.
Re-read what you write before you send. Does it make sense? Will it make sense to the recipient.This is the heart of “pay attention to detail”.The second part is: learn language and communication.
If you don’t, you’re not going to go far.
You don’t have to be perfect. Even small improvements and changes are noticed.
- Read (or listen to) lots of books.
Not just technical and software books.
Reading across topics (history, philosophy, politics, general interest) improve your understanding of the world and people.
- Write it down & make notes
After you have figured something out, write it down. That includes:
Technical processes. Step by step instructions. Exactly what you did. Every command. Copy errors. Show screenshots.
It doesn’t have to be pretty or formatted. Just make sure you and others can find, read and understand it a second time.
Whenever you go through a process, makes notes at each step. Take screenshots. Write down commands. Write it in sequence. Make logs. Save logs.
Writing it down is good for you as well as to share with others.
It is also the first step of DevOps. That’s right! Congratulations, you’re now doing DevOps!
Clear communication is perhaps the most important skill in software development.
Understand the verbal and written language of your customers, users and colleagues.
You cannot achieve great things on your own.
- Context switching makes a great developer (a great “anyone” really). But it’s a skill you have to be aware of and develop. Want to develop. Because it’s difficult and take a long time (or from an early age) to develop.
Also: Put yourself in other people’s shoes.
- do not get developers to *QA* test their own work
No matter how good, or how much experience, when you spend as much time as a developer deep in the code:
a) they’re going to miss things when testing.
b) the last thing they want to do is QA test their own code (or write test cases, or think through scenarios).This is why you need TEAMS.
– TesterAll working together as a unit, contributing as one, working as one.
- Code formatting is important
Be mindful of spacing in code.
Block/chunk your code. Use white space to separate.
Use indentation. Keep it consistent. Aesthetics are important for the next person to be able to read it.
Forget where the opening curly branch should be (if it’s in your language). Learn and deal with different styles – it’s not the end of the world.
If your language is not based on indentation as part of the syntax, then ABSOLUTELY use indentation to help other developers read your code,
The whole idea behind being an awesome developer is “helping other developers read your code” (that’s aside from the other whole idea of “building a system that is easy to use, secure and can last into the future”).
Take care aligning code. Even 1 line out of alignment can be a pain.
Every single line of code you write should be thought of as code someone else will have to read. Your job is to make it as easy as possible for others to read and understand your code.
- Be mindful of consistency, even casing.
Be consistent with a language, but… it’s not that but a deal.
However, things like “Dinner_count_template” stands out (that leading “capital” D where 99.9% it’s lower case can be a real bother (we all have OCD in us).
- Test. Test. Test. Test.
- You’re always going to screw up. Or miss something. Or misspell something.
You’re in a rush, or you’re cross-eyed from looking at the same code all day.
It’s not a problem. It’ NOT.
But take time occasionally to go back and review code.
Ask your boss/lead. If they say no… fuck ’em – you’re a better developer, so take the time anyway.
- Push back on people who want you to cut corners (testing, thinking, getting up and having a coffee or a chat or discussing ideas with others). That’s your job. The people who criticise you don’t know your job.Push back on customers who make unreasonable requests.Push back on unethical requests.We all overlook stuff. If you see a hole, ask about it.Whenever you’re given requirements, try to approach it from different angle and scenarios. If all the scenarios seem to be given, run through them all and try to find new ones.
Every scenario is never covered at the start. Even with multiple people looking at it, things will be overlooked. If you even remotely think you see something overlooked, speak up.
Only fucking stupid managers and leads will shoot you down (unfortunately, they are more common than not).
- Make you code readable. Put yourself in the shoes of others who have to read and understand your code.
- Audit system actions.
Don’t audit PII or sensitive data. Don’t audit data that won’t help.
Make audit logs easy to find and read.
- Clearly document information about your software
– Networks configs.
– Server configs.
– Access points and type and styles.
– Authentication credentials.
– KB information
– How to resolve issues
– Patterns and practices
- Enclose your HTML attribute values with quotes (single or double)
- You need to learn to adapt and read different coding styles. Not enforce your own preference – realise that everyone has their own preference, and a good developer is one who can read different style.
Otherwise you’re just a gamma Nazi.
- Develop, setup and use your DevOps systems from the start. That needs testing too. You don’t want to get to deployment and have to debug issues in it.
Don’t take shortcuts into test environments. Same shit all the way.
- System migration
Test and verify before and after the migration.
The bigger the system the more you need to do.
Run test in parallel.
Verify after importing. Check, check, check.
Make sure you have support of experts.
- Test your work. Again and again and again. There is never too much testing.
- Debugging – work the problem slowly, incrementally, methodically. Small change. Test. Get it working. If it’s broken, try to find what changed since last working.
When you ask someone for help with an error, given them as mix information and context about your problem as you can.
- Use StackOverflow / StackExchange network
Don’t do it for reputation. But create an account and ask questions.
Do as you’re asked.
Learn from elders.
You don’t know everything.
Someone else pays the bills, so they’re in charge.
Decisions are usually made for reasons you don’t understand, and sometimes you won’t be told.
If you want to do it your way, start your own company and be the boss.
- Name things clearly:
– classes, functions, properties, variables
Never ever, ever, ever be afraid to ask.
Only dicks push back on you.
Even the smartest, most experienced people know they don’t know basic stuff and will ask.
There is so much to know, you can’t know if remember it all, do ask
If you don’t understand the basics then your teacher is to blame, not you.
Don’t prematurely optimise. Wait until the need presents itself, then optimise for the situation.
Obviously, you need some tools and approaches available, but keep them in the bag until they are needed.
- You will suffer from Impostor Syndrome sooner or later.
- Welcome to the real world. You’ve left university. You now know nothing.
- Code is not “self documenting”.
APIs are not self documenting either.
You need to write comments/documents that tell others: what the code is for; how to use it; what to pass in; what to expect; constraints; etc.
- Graduate and Junior developers are not slave labour.
You are not just a resource.
- Ask stop asking basic and simple questions. They’re allowed. In fact, they’re REQUIRED!
Question old assumptions and “proven” conclusions.
- Gate your loops to stop from running for infinity.
Add a counter with a limit over expected max. If that max is reached, end the loop.
Ever loops expects to end.
- Automate everything you expect to do more than once.
If code automation is not feasible (or not enough time) to start, then write it down.
Written step by step instructions is “manual automation”. It gives you the process that can later be converted to code. But the point is you don’t have to figure out/guess the steps every time.
- Thing about namespaces, especially at a global level. Think about naming conflicts (classes, functions and variables).
- Think about session timeouts
- Think about script/processing timeouts.
- There are no edge cases.
There is no such thing as an edge case. Or “it’s not likely to happen”.
A case is a case, regardless of probability.
3 Mile Island was an edge case, but it happened.
So called edge cases are just security problems and system breach points.
Always have logging and telemetry.
Indicate if a log entry is information, warning or error. Split your log data down into discrete, searchable/filterable/groupable components.
Record the source/location.
Date/time stamp everything (I suggest using UTC, so timezones don’t become an issue).
- If you don’t know then say “I don’t know”.
It’s not shameful. It’s the opposite.
And it doesn’t mean you can’t find out.
We can’t be expected to know everything all the time.