A Beginner’s Guide on How to Improve Your Programming Skills

A Beginner’s Guide on How to Improve Your Programming Skills

An in-depth guide on how to learn the skill of Programming

Image for postPhoto by Icons8 team on Unsplash

If you want to become an expert programmer, be ready to spend at least 5 years of programming daily.

However, if you just want to learn the basics that will either get you a job or allow you to work on your projects, you can learn the skill of programming in less than 100 hours of practice.

100 hours of practice is about the equivalent you?d get from an average 4-year degree in Computer Science, but this guide will show you how to practice efficiently so that you can find the time to learn it in up to 7 months (and in most cases, much less).

Sounds exciting?

Let?s get right into it!

Contents

1. What is Programming?2. Why should I learn Programming?3. How should I practice Programming? 3.1 How can I manage my time? 3.2 When should I practice it? 3.3 Where should I practice it?4. What are the basic concepts of Programming? 4.1 Boolean and conditional logic 4.2 Variables 4.3 Loops 4.4 Functions 4.5 Language(s) 4.6 Framework(s)/Language applications 4.7 Scripting 4.8 Frontend 4.9 Backend5. How can I become a good programmer? 5.1 Write clean code like a champ 5.2 Write classes like a champ 5.3 Use Git like a champ 5.4 Become insanely resourceful6. Where can I find great material to learn Programming?

1. What is Programming?

I won?t spend too much time here since if you?re reading this, you likely have a pretty solid idea of what programming is. Here?s my definition:

the act of writing code understood by a computational device to perform various instructions.

So, to get better at programming, you?ll be writing a lot of code!

2. Why should I learn Programming?

I?m not here to motivate you to learn Programming, that?s really up to you. If you came up with the answer simply by reading this section?s headline, that?s a really good sign.

One of the biggest factors why people don?t follow through on learning any skill is because their ?why? is either non-existent or ambiguous. Know your why ? I can?t stress this enough.

Take a moment to jot down ideas on why you want to learn Programming. If you can visualize yourself doing it in the context you want to in the future, that?s perfect. The clearer your picture of why you want to do it, the clearer your path will be to make it happen.

Here are some ideas to get you started:

  • Get a better job;
  • Be happier;
  • Get respect from others;
  • Have more impact;
  • Become wealthy;
  • Become financially secure;
  • Discover new hobbies or passions;
  • and more!

Whatever you come up with, drill down on the details. What specific job do you want to be doing? What does happiness mean to you? Who do you want respect from? What kind of impact do you want to have? On who? What does wealthy mean to you? Why do you want to be wealthy? What does being financially secure mean to you? What kind of new hobbies or passions are you looking to discover?

Again, the clearer your answer, the higher your motivation will be for learning Programming or any other skill.

3. How should I practice Programming?

Some skills can have a higher ratio of knowledge vs application, this is NOT the case with programming. Programming is one of these skills where you will need to practice a lot more than focus on the theory. I then recommend you spend at least 80% of your time writing code and 20% learning the theory. As you learn more and more, I?d even increase the practice ratio.

In section 4 and 5, we?ll go into the basic concepts of programming. For every minute you spend trying to understand the concepts, you should spend about 5x more time on putting it into practice. That?s how the concepts will sink into your brain and start making sense; not by re-reading it multiple times.

If you?re aiming for finding a job as a junior programmer or simply want to build your project, you?ll need about 100 hours of practice to get there. And it?s not an easy ride, especially if you haven?t had much practice with other logical skills in the past. That?s why being good at math is often a requirement to get into a computer programming program. The math you?ll use in programming is rarely that complex, but the logic you learned by applying math greatly accelerates your programming abilities.

3.1 How can I manage my time?

So, if you are aiming for 100 hours of practice, how do you break your learning sessions down?

This greatly depends on your situation. Some of you will be able to do that full-time and be proficient enough with a full month of practice. Some of you have other responsibilities and can?t dedicate much time at all.

For most skills, I recommend practicing for at least 15 minutes per day at a moment of the day where you can easily focus. But for programming, that?s simply not enough. For programming, if you practice for 30 minutes every day, that?s 3.5 hours per week or 14 hours per month.

For 100 hours of practice, that?s a little over 7 months of practice. I?d argue you should aim for at least 15 hours per month, which makes it possible in less than 7 months.

If you?ve got a lot of time on your hands, I would still not cram all this learning in 2 weeks (50 hours per week). Unless you?re a genius (that?s extremely rare by the way), your brain simply doesn?t process information that quickly. Over-cramming information like that will produce the illusion of proficiency. While everything is fresh in your mind, things will seem easy, but if you stop practicing for even just a month, you?ll lose at least 60 percent of what you previously learned. This is based on the forgetting curve.

The golden rule is spaced learning and spaced repetition. This means you should spread out your learning in short bursts to let your brain time to assimilate the concepts. And you should recall what you learned regularly enough.

How regularly?

The easy answer is after 24 hours, after 7 days, and after one month.

3.2 When should I practice Programming?

Every day.

The more you can make your skill practice a habit, the easier it will be to follow through and get results. Focus and the process more so than tangible results. It?s always more motivating to focus for 30 minutes, for example, than to focus on writing a complex piece of code.

But since programming is an intellectually complex skill, make sure to practice when your mind is sharpest. While most programmers proclaim to be night owls, research shows that most people have their mind sharpest shortly after waking up. If you?re unsure when?s the right time for you, I?d start with early morning, before anyone around you is awake. This minimizes distractions.

If it doesn?t work right away, please don?t give up right away. New habits take time to form. Try consistently for at least two weeks and see if there are any improvements. If not, try a different time. A key is to find time without distractions unless you?re practicing in a group setting (which is great by the way).

3.3 Where should I practice Programming?

Your environment has more impact than you?d expect in your ability to learn something. In school, do you remember thinking you knew something until you were in the exam room and couldn?t recall anything?

The problem is that the brain makes associations with the context in which you learn something. Not many people know that, yet it?s a crucial concept in truly learning anything.

Here are a few factors to consider when it comes to your context:

  • Physical location;
  • Temperature;
  • Distractions;
  • Music & noises;
  • Comfort;
  • People you are with;
  • The material you?re using;
  • Your state of mind (relaxed, agitated, nervous, excited, bored, enthusiastic, etc.);
  • What you?re wearing;
  • What you?re eating or drinking; and
  • a lot more!

When you are in the process of learning something, your brain ?takes a snapshot? of your environment. The more of your senses it stimulates, the stronger the connection.

But that?s not all good news.

Within the same context and environment, you?ll perform great. Outside of it, not so much. I?m sure you don?t need to think too hard about a moment where that happened. Now you know why.

So, to be able to use things you learned in a more adaptable way, it?s strongly recommended you vary your environment while you?re trying to learn any skill. Learning to play tennis? Practice on different courts. Practice at different temperatures. Practice against different opponents. Practice with different racquets. I guarantee you?ll skill up your tennis game if you vary all those things.

When it comes to programming, practice using different languages. Practice with different frameworks. Practice frontend and backend. Practice with different IDEs. Try pair programming. Do functional programming. Do Object-Oriented programming. Do Component-based programming. Try scripting. Try Machine Learning. Code in your room, in the living room, in the kitchen, at cafes, at school, outside, etc. Try with different types of music. There?s an infinite combination of things you can do!

4. What are the basic concepts of Programming?

Truth be told, the skill of programming is too broad. If you want to learn ?programming?, you?ll lose motivation quickly. It?s overwhelming beyond imagination to view it as a single entity! As such, we?ll break it apart in the following sub-skills (don?t be thrown off by the names, I?ll simplify everything for you):

4.1 Boolean and conditional logic

A boolean expression is something that evaluates to a binary value of true or false.

In most languages, these are evaluated by using these equality signs:

  • ==: Equals
  • >=: Greater than or equal to
  • <=: Lesser than or equal to
  • >: Greater than
  • <: Lesser than
  • !=: Not equal

In most languages, = is a value assignment, not a boolean expression. You?ll sometimes also see :=, ->, or =>.

If you print the values of a after var a = 3, it would print 3.

If you print a == 3, the value will either be trueor false depending on the value of a. If you previously assigned a the value of 3, it will print true. If not, it will print false.

Conditional logic is the evaluation of a boolean expression. Basically: if this then that. We see that all that time in our day-to-day life. In section 2, I even encouraged you to do that by identifying your why. if I learn Programming, then I?ll get [a better job, happiness, money, etc]. learn Programming, in this case, is the boolean expression that is true.

A conditional expression can have multiple parts defined by and/or. if I eat protein AND do a hard workout at the gym then I?ll grow muscles.

If most languages, ?and? is defined by && and ?or? is defined by ||.

You can also group boolean expressions with ( and ). if (a || (b && c)) then d. if (I buy flowers || (cook dinner && do the dishes)) then my wife will be happy.

As you can probably imagine, this can get really complex. In section 5.2, I?ll show you how good programmers keep this easy to understand for anyone reading their code.

4.2 Variables

To keep it really simple, variables are something named that holds a value. Example:

int numTrees = 6;string orchardName = “Golden Apple Orchard”;bool isOpen = true;int applesInTrees = {12, 4, 8, 7, 2, 4};float collectionRatePerHour = 23.2;

Good programmers will use variables in a descriptive way instead of ?hard-coding? values. Here?s an example of ?hard-coding? a value:

if (numTreesCollected < 6) { // TODO: do something}

What does 6 mean here to someone not familiar with the orchard or the code? Nothing. Now, if we use variables instead, it?s a lot clearer:

if (numTreesCollected < numTrees) { // Keep collecting}

We could similarly write it this way because of the applesInTrees array:

if (numTreesCollected < applesInTrees.length) { // Keep collecting}

Primitive data types

In the above code, you were introduced to the data types present in every language:

  • int is a numerical value that doesn?t support decimals. Some languages allow ?signed? or ?unsigned? values, meaning it prevents negative numbers of not. By default, negative numbers are allowed.
  • string is a ?chain of characters?. Basically: text. Its length is variable to any size.
  • bool is a boolean value of only two possible values: true or false. Every if statement you see evaluates the value of a boolean expression (one or more boolean values)
  • float is a numerical value that supports decimals. Some languages support double for more precision on the decimals.
  • array is represented here with int. This means a collection of int values. You can create arrays from most data types ? and certainly all primitive ones mentioned above.

Going further

This subsection barely scratched the surface on what variables are. It?s strongly encouraged to research the topic further once you have a greater understanding of programming in general.

4.3 Loops

What is the sum of the following numbers: 2, 6, and 7? Fairly simple, right? How did you do it?

Most people go through each number, keeping a running sum and only add two numbers together at once. Something like this:

  • 2+6 = 8
  • 8 + 7 = 15

In your brain, this required two iterations.

In this very simple example, we know how many numbers we have and what their values are. That is rarely the case in programming.

As briefly mentioned in the the previous section, you have the concept of an array. At its most simple, it?s a list of values. You don?t know how many values there are and what the values are. Let?s say you want to write an algorithm that counts the total number of apples in any orchard. The data would be collected in an array to records how many apples a tree possesses. For one orchard, the array could look something like that:

var apples = [12, 4, 8, 7, 2, 4]

Another orchard may have this array:

var apples = [8, 7, 6, 5, 9]

How do you create an algorithm that will work in any scenario to count the sum of apples? The answer is with a concept called loops. It?s ultimately not different at all from what you did in your head above. Let?s do it again using the first array:

  • 12+4 = 16
  • 16+8 = 24
  • 24+7 = 31
  • 31+2 = 33
  • 33+4 = 37

Here?s what the code would look like:

var apples = [12, 4, 8, 7, 2, 4];var sum = 0;for (var i = 0; i < apples.length; i++) { sum = sum + apples[i];}print sum;

That last line would print 37 on your screen.

A lot is going on in the code above. A for loop goes through each value of an array one by one, from one index to another.

In the example above, we started from the index 0 (see var i = 0;). In most programming languages, an array?s first index is not 1, it?s 0. In the above case, at index 0, the value is 12. At index 1, the value is 4.

Our range of indices in the above case is from 0 to the number of values present in the array, indicated by apples.length. Essentially, var i = 0; i < apples.length; i++ means that the algorithm is going through each index one by one (i++), starting from the first index until the last.

So, there are three components of a for loop:

  • Starting index;
  • Ending index; and
  • Number of steps per iteration.

for (startIndex; endIndex; numSteps)

If the above code, if you changed i++ to i + 2 it would sum up every other value: 12+8+2 = 22.

apples[i] means the value at the index the loop is at currently. If you replace i here by apples[3], the value you?ll obtain is 7. Here?s the array again for reference:

var apples = [12, 4, 8, 7, 2, 4];

  • apples[0] = 12
  • apples[1] = 4
  • apples[2] = 8
  • apples[3] = 7
  • apples[4] = 2
  • apples[5] = 4

The for loop above basically performs this:

var sum = apples[0] + apples[1] + apples[2] + apples[3] + apples[4] + apples[5]

Understood?

I know this seems complex right now, and that?s why you need to practice for 80% of your learning time.

for is the most common loop. You?ll also regularly find the while loop. It means ?do something until I?m done?. Example: Pick apples until there are no more apples to pick.

Let?s say we take the first orchard that has 37 apples:

var numApples = 37;while (numApples > 0) { numApples = numApples – 1; print numApples;}

What do you think will happen here?

You?ll see this printed on your screen:

  • 36
  • 35
  • 34
  • 33
  • ?
  • 0

You?ll see 37 values printed. The code in the while loop will keep executing until the condition is met: numApples > 0, aka ? until we still have apples to pick!

4.4 Functions

Functions make code pieces reusable. Remember the for loop above to calculate the sum of apples for the first orchard? How do you make it work for ANY orchard? Let?s make a few adjustments:

function countApples(apples) { var sum = 0; for (var i = 0; i < apples.length; i++) { sum = sum + apples[i]; } return sum;}

You?ve created your first function/method! This, on its own, actually does nothing. Here?s how you would use the function:

var orchard1 = [12, 4, 8, 7, 2, 4];var orchard2 = [8, 7, 6, 5, 9];print countApples(orchard1);print countApples(orchard2);

This would print 37 and 35 on your screen. How? Let?s dig deeper.

When you write print countApples(orchard1) you are sending the orchard1 array to the algorithm you previously created. It essentially becomes exactly like the examples in 4.2:

var apples = [12, 4, 8, 7, 2, 4];var sum = 0;for (var i = 0; i < apples.length; i++) { sum = sum + apples[i];}print sum;

While outside the function, orchard1 refers to [12, 4, 8, 7, 2, 4], it becomes a more generic variable called apples in the function.

In terms of values, when calling countApples(orchard1), orchard1 equals apples in the countApples function.

Similarly, when calling countApples(orchard2), orchard2 equals apples in the countApples function.

With that function, you can now count the number of apples in any orchard without rewriting the logic/algorithm multiples times. You simply use the countApples function/method and pass it the array of values you?ve collected.

4.5 Language(s)

If we took the above algorithm and converted it into different languages, it would look something like that:

Javascript

function countApples(apples) { var sum = 0; for (var i = 0; i < apples.length; i++) { sum = sum + apples[i]; } return sum;}var orchard1 = [12, 4, 8, 7, 2, 4];var orchard2 = [8, 7, 6, 5, 9];console.log (countApples(orchard1));console.log (countApples(orchard2));

Java

int countApples(apples) { int sum = 0; for (int i = 0; i < apples.length; i++) { sum = sum + apples[i]; } return sum;}int orchard1 = {12, 4, 8, 7, 2, 4};int orchard2 = {8, 7, 6, 5, 9};System.out.println (countApples(orchard1));System.out.println (countApples(orchard2));

Python

def countApples(apples): sum = 0 for x in apples: sum = sum + x return sumorchard1 = [12, 4, 8, 7, 2, 4]orchard2 = [8, 7, 6, 5, 9]print countApples(orchard1)print countApples(orchard2)

Isn?t it fascinating?

It?s like spoken languages that come from the same root.

French: Je parleItalian: Lo parlo

If you understand ?je parle? in French, it?s very easy to understand ?lo parlo? in Italian.

Similarly, if you understand how to create a loop in one programming language, you can easily learn to create a loop in another language. All modern languages have variables, loops, and functions. They just have a different syntax.

So, when people ask me what programming language they should learn first, I typically answer that it depends on what they want to accomplish. Each language has frameworks supporting the language.

4.6 Framework(s)/Language applications

If you want to do machine learning or statistics, you?d likely using Python or R.

If you want to create a fast and robust software, you?d use Java or C++. Maybe C#.

If you want to code web application, you?d use Javascript.

If you want to write backend code, you?d use Python, Ruby, Javascript, or Go.

If you want to write scripts, you?d use Go, Python, or Swift.

These are not golden rules though. It?s just that these languages have frameworks that allow you to use the language more easily for specific contexts.

4.7 Scripting

The main goal of writing scripts is to automate processes. Let?s say you want to resize a collection of 10,000 photos into thumbnails. Doing it all manually sounds dreadful, doesn?t it? By writing a script, you can automate the process without having to resize a single one yourself.

You can use scripting for many different purposes. You can scape web pages to store data in a spreadsheet. You can copy a web page?s content into your clipboard. You can turn any type of data into another type of data.

The possibilities are endless.

Usually, you would use scripting for one specific task that is self-contained, meaning it doesn?t need to be part of a larger framework.

For example, the pieces of code we?ve written so far would be considered scripts.

4.8 Frontend

Frontend development has to do with anything that you can visually see. For example, a website with its layout (HTML) and style (CSS). Frontend code gets executed on the user?s computer.

A static website is entirely frontend code. If you use visual tools WordPress or Squarespace, that?s frontend too. WordPress and Squarespace have code on their backend that makes your frontend work.

When people talk about frameworks like React, Angular, and Vue.js for example, these are all frontend frameworks. There are TONS of them!

Frontend development used to be simple, with only HTML, Javascript, and CSS to work with. Then came jQuery. Then came everything else. New frameworks are coming out almost every week.

Because of the ever-changing set of frontend ?tools?, you might want to start learning to most popular frameworks and learn the other ones on the job, as needed.

4.9 Backend

Backend development has to do with anything that is done outside of what people see. It is executed on servers usually far away from the user?s computer, on a company?s server(s).

We can see the frontend as the body and the backend as the brains. You know the brain is responsible for what your body does, yet you never ?see? it in action.

A lot of web applications rely heavily on backends to execute CPU or Memory intensive work. Have you ever been to a website where they tell you to come back later and that you can close the window? That?s because their backend is working on the task. It?s working on their servers, not your computers. You only get the result sent to your computer once it?s done executing on their servers. The main advantages are that servers are more powerful than your machine and can execute faster code.

The backend is also the one responsible for storing data into a database. Usually, the frontend only has access to a sub-section of the data for retrieval. It can also submit changes to the data to the backend for processing. At its most simple, it can just mean ?inserting into the database?.

5. How can I become a good programmer?

The basics above help you get started, but you won?t be a very good programmer yet with those. Below, I?ll explain some ways to go from noob to good in a short while. This section is the most complex one, so if you can?t follow along currently, don?t forget to bookmark to revisit it later when your mind is sharpest!

5.1 Write clean code like a champ

Let?s say you?re working on a 2D platformer game in Unity. You want to add simple range detection to decide when an enemy should attack the player. A regular programmer may write code that looks like this (if not using colliders):

void Update() { if (Mathf.Abs(transform.position.x * 100.0 – player.transform.position.x * 100.0) <= 10.0) { isAttacking = true; animation.SetAnimation(0, “attack”, false); }}

If that terrifies you, it should. Writing clean code is about making it so easy to understand that you?re simply reading English. The above example is extremely simple, yet we can do much better. Here?s one way a more advanced programmer may write it:

//// Core logicvoid Update() { if (IsCloseToPlayer()) Attack();}//// Implementation detailsbool IsCloseToPlayer() { return (PositionDifference(transform, player.transform) <= ATTACK_DETECTION_RANGE);}float PositionDifference(Transform t1, Transform t2) { return Mathf.Abs(GetHorizontalPosition(t1) – GetHorizontalPosition(t2));}float GetHorizontalPosition(Transform t) { return t.position.x * PIXELS_PER_UNIT;}void Attack() { if (isAttacking) return; // No need to repeat if already attacking isAttacking = true; int animationTrack = 0; bool loop = false; animation.SetAnimation(animationTrack, “attack”, loop); // Will reset isAttacking after AnimationComplete}const float PIXELS_PER_UNIT = 100.0; // Number of pixels in a single Unity world view unitconst float ATTACK_DETECTION_RANGE = 10.0;

What?s one of the first thing you?re noticing?

?There?s a lot more code!!?, right?

Did it take me more time to write? You bet! But here?s why it?s better than the first block of code (more explanation also in section 5.2):

Abstraction and encapsulation

Hide implementation details.

If you look at the Update() function of the second code block again:

void Update() { if (IsCloseToPlayer()) Attack();}

It?s simple to read, right? Especially next to the first version you previously saw:

void Update() { if (Mathf.Abs(transform.position.x * 100.0 – player.transform.position.x * 100.0) <= 10.0) { isAttacking = true; animation.SetAnimation(0, “attack”, false); }}

When someone else (or future-you) reads your code, they want to understand what?s going first before jumping into the details. Sometimes, the details are not that important.

If you read the second code block, it will take you a lot more time to understand that it means: ?if I?m close to the player, I should start attacking?. Creating nicely named bite-size methods makes your code a lot more readable.

Name your boolean conditions.

IsCloseToPlayer() is a lot easier to read than Mathf.Abs(transform.position.x * 100.0 ? player.transform.position.x * 100.0) <= 10.0

As much as possible, name all your boolean expressions to something clear. A nice way to do it is by prepending is or has in front of the action name.

isCloseToPlayer, hasEnoughStorage, isAlive, etc.

Name your actions.

Attack() is a lot easier to read than:

isAttacking = true;animation.SetAnimation(0, “attack”, false);

Can you encapsulate a set of instructions into a single named function? If so, do it!

Most good code doesn?t need comments to explain the logic because variables and functions are all named properly. If you need a comment to explain a block of code, chances are you can create a well-named method instead.

The rule of 7

How many lines of code should a function/method have? Here?s a simple answer: 7 2. The reason for this is that our brain only can work on about that many instructions at the same time. I cringe whenever I see methods that have more than 9 lines of code.

Here?s an example from a game I?m working on:

public void SetUp() { this.SoulReaper.SetUp(GridAllies.Team); LoadPrefabs (); InitLists (); grids.ForEach (grid => InitGrid (grid)); InitTimeline (true); InitAllyRowBonuses (teams [0]); InitOpponentRowBonuses (teams [1]);}

If you read the above code, you know all the steps required to setup this class (this sets up the ?Combat? scene). It?s a little technical, but it?s still readable by normal people. Most beginners would put all the initialization logic in here.

I?ll spare you the long example, but combined, it?s about 250 lines of code. You?d never be able to read the logic in one go. If you dig into some of these methods, you?ll see they?re also less than 7 lines of code:

void InitLists () { monsters = new List<CombatMonster> (); unreaps = new List<CombatUnreap> (); stolenSouls = new List<CombatMonster> ();}void InitTimeline (bool soulReaperAssisting) { this.timeline = new Timeline (this); if (soulReaperAssisting) this.timeline.Add (this.SoulReaper); if (UnreapSupport) TimelineController.gameObject.SetActive (true);}void InitAllyRowBonuses (Team team) { DisplayRowBonus (team, PanelStart.transform.GetChild(2), 0); DisplayRowBonus (team, PanelStart.transform.GetChild(3), 3); DisplayRowBonus (team, PanelStart.transform.GetChild(4), 6);}

We did the same with our methods in this same section at the top:

bool IsCloseToPlayer() { return (PositionDifference(transform, player.transform) <= ATTACK_DETECTION_RANGE);}float PositionDifference(Transform t1, Transform t2) { return Mathf.Abs(GetHorizontalPosition(t1) – GetHorizontalPosition(t2));}float GetHorizontalPosition(Transform t) { return t.position.x * PIXELS_PER_UNIT;}

Maintainability

Abstraction and encapsulation make it easier to maintain the code down the road because you understand what everything means without having to search through 100+ lines of code.

In the example above from my game, if there?s an issue with the timeline not getting initiated properly, I can simply search my code for ?Init Timeline? and it?s very likely the problem lies in that method.

This all makes the code much easier to debug.

5.2 Write classes like a champ

Now that we know why the second code block in section 5.1 is better, let?s add more to it.

Let?s say now you have a different enemy you want to code. The problem is, it attacks vertically this time, and its detection range is further.

A junior programmer may copy + paste the code above and replace position.x with position.y and change the ATTACK_DETECTION_RANGE constant.

We can do better with the use of classes to minimize code duplication. Good programmers don?t rewrite code they don?t need too. That?s why you?ll often hear to good programmers are ?lazy?.

Here?s what the ?parent? class could look like:

public class Enemy : MonoBehaviour { public float AttackDetectionRange = 10.0f; public string AttackAnimationName = “attack”; protected const float PIXELS_PER_UNIT = 100.0; // Number of pixels in a single Unity world view unit // // Core logic void Update() { if (IsCloseToPlayer()) Attack(); } // // Implementation details protected abstract bool IsCloseToPlayer(); protected virtual void Attack() { if (isAttacking) return; // No need to repeat if already attacking isAttacking = true; int animationTrack = 0; bool loop = false; animation.SetAnimation(animationTrack, AttackAnimationName, loop); // Will reset isAttacking after AnimationComplete } protected float PositionDifference(Transform t1, Transform t2) { return GetWorldPosition(t1) – GetWorldPosition(t2); } float GetWorldPosition(Transform t) { return t.position * PIXELS_PER_UNIT; }}

So far, we?ve only made a nice abstracted class out of our previous enemy script. You?ll notice a few differences:

  • public variables at the top
  • protected variables and methods
  • abstract methods
  • virtual methods
  • a more ?generic? PositionDifference()

A variable or method that is public is one that can be called by (using the . notation in most languages) any instance of the class (an Object):

var instance = new Enemy();print instance.AttackAnimationName;

This would print ?attack?. If the variable wasn?t public, it would give you an error, saying the variable is not accessible.

A variable or method that is protected is one that can be called by parent and child classes. We?ll dive deeper into the concept shortly.

A virtual method (in C#) means that it can be overridden by a child class by using the override keyword. abstract methods also need to use the override keyword.

Now, you won?t be able to instantiate Enemy because of the abstract method. Everyabstract method need to be implemented in child classes. If we want to instantiate it, we need to create a child class. Let?s make the horizontal attacker first:

public class EnemyHorizontal : Enemy { protected override bool IsCloseToPlayer() { return (PositionDifference(transform, player.transform).x <= AttackDetectionRange); }}

That?s it!

Inheritance

The above code block touches on a very important concept of classes. Likely the most important, so pay attention! 🙂

Inheritance is a hierarchy of classes deriving their logic from other classes.

In the code above, EnemyHorizontal inherits all the public and protected variables and methods from Enemy. Enemy is the parent class. EnemyHorizontal is the child class.

In the Enemy class, IsCloseToPlayer was abstract. We created a ?definition? for it in the child class called EnemyHorizontal. EnemyHorizontal will do the same things as Enemy except for its detection of the player in range (IsCloseToPlayer()).

This line: public class EnemyHorizontal : Enemy can be read as EnemyHorizontal is a type of Enemy. It?s an Enemy, but with additional logic.

The above code block is 100% equivalent to the following version that doesn?t use inheritance:

public class EnemyHorizontal : MonoBehaviour { public float AttackDetectionRange = 10.0f; public string AttackAnimationName = “attack”; protected const float PIXELS_PER_UNIT = 100.0; // Number of pixels in a single Unity world view unit // // Core logic void Update() { if (IsCloseToPlayer()) Attack(); } // // Implementation details protected bool IsCloseToPlayer() { return (PositionDifference(transform, player.transform).x <= AttackDetectionRange); } protected virtual void Attack() { if (isAttacking) return; // No need to repeat if already attackingisAttacking = true; int animationTrack = 0; bool loop = false; animation.SetAnimation(animationTrack, AttackAnimationName, loop); // Will reset isAttacking after AnimationComplete } protected float PositionDifference(Transform t1, Transform t2) { return GetWorldPosition(t1) – GetWorldPosition(t2); } float GetWorldPosition(Transform t) { return t.position * PIXELS_PER_UNIT; }}

That?s a little longer, right?

Now, let?s create the vertical attacker:

public class EnemyVertical : Enemy { protected override bool IsCloseToPlayer() { return (PositionDifference(transform, player.transform).y <= AttackDetectionRange); }}

That?s it!

In both cases, because AttackDetectionRange and AttackAnimationName are public variables, we can set any value for them. We can therefore create an infinite amount of enemies that can attack either horizontally or vertically. For example:

# Goomba : EnemyHorizontal# AttackDetectionRange = 5.0;# Koopa : EnemyHorizontal# AttackAnimationName = “hide_in_shell”# HammerBro : EnemyVertical# AttackDetectionRange = 15.0;# AttackAnimationName = “throw_hammer”;

That?s all good, but what if the attack pattern is different? What if I want a monster that is constantly attacking when in range?

Can you figure it out on your own?

If not, here?s one way to implement it:

public class EnemyBrawler : HorizontalEnemy { void Update() { this.isAttacking = IsCloseToPlayer(); Attack(); } protected override void Attack() { if (!isAttacking || animation.animationName == AttackAnimationName) return; // Don’t continue if already attacking int animationTrack = 0; bool loop = true; animation.SetAnimation(animationTrack, AttackAnimationName, loop); }

Here?s what the hierarchy of classes would look like at this point:

Image for postEnemy is the parent class of Horizontal and Vertical. Horizontal is the parent class of Brawler. Horizontal and Vertical are child classes of Enemy. And Brawler is a child class of Horizontal.

So, while in the second code block of section 5.1, it may have looked like we added so much code uselessly, we shortened the code in the long run and prevented any duplication of code.

This leads us to the concept of Cohesion:

Cohesion

Cohesion refers to the degree to which the elements inside a module belong together.

In our simple example above, every enemy only has one action to perform: Attack. If we had to add more actions, what would they be?

The simple question to ask yourself where deciding which methods a class should have is: ?does it make sense for this object to do that action?? If not, the action should be added to a different class.

Here?s an example:

public class Animal { void Move() { // TODO: Implement this }}public class Dog : Animal { void Bark() { // TODO: Implement this }}public class Cat : Animal { void Meow() { // TODO: Implement this } void Bark() { // TODO: ??? }}

This example is intentionally ridiculous to prove a point. It is extremely common for programmers to add a method to a class it doesn?t belong to because it also doesn?t belong to other existing classes. The Cat class here is an example of a class with low cohesion.

5.3 Use Git like a champ

Take this very seriously, please! There?s nothing senior programmers hate doing more than resolving merge conflicts and when they can be avoided!

The very basics

At its most basic, Git is a ?framework? for collaborating on a codebase. Git handles versioning and merging of files from one commit into another. Git code is stored in a repository, living on a Git server.

As a user, you?ll checkout a branch of the code, usually develop or master. This means it?s now stored on your computer. Any changes you make remain on your local computer until you push your commit(s) to a remote branch. However, you can?t push until you?ve committed your changes into your local version of the branch.

Phew!

While that sounds complicated, here?s the most basic process when working alone:

git commit -am “something”git push origin develop

The first line creates a snapshot of your code (a commit) with the annotation: ?something?.

The second line sends the committed code to the remote server, to the branch called develop.

That?s simple enough so far since you?re working alone, but let?s say Jane joins the project. To keep things simple, Jane is also working on the develop branch.

The remote branch develop is the ?source of truth?. It?s where the most final version of the code that can be run by everyone on the project is stored. Now, both you and Jane have a local branch of the same name (develop).

Let?s say both of you want to work on the same file at the same time: EnemyHorizontal. You want to define the IsCloseToPlayer() method (specified by the override keyword), and she wants to add a new method called UpdateRange().

Once you?re done implementing your code, you?ll do that:

git commit -am “implemented IsCloseToPlayer”git push origin develop

Shortly after, Jane finishes her part and does similar:

git commit -am “added UpdateRange method to EnemyHorizontal”git push origin develop

Git won?t allow the second line to go through.

Why do you think that is?

At the moment Jane pushes her code, the remote develop has a new commit from you? it is further ahead than her local branch in terms of code.

Before she can push her commit, she?ll have to pull the latest changes on the remote develop. It?s done this way:

git pull origin develop

This merges the latest commits from the remote develop branch into her local develop branch. So now Jane has the implemented IsCloseToPlayer method in her local branch as well, in addition to her code. Now she can safely push (provided no one else pushed before her!).

git push origin develop

To stay on the safe side, you might always want to pull before pushing.

git commit -am “something”git pull origin developgit push origin develop

Conflicts

You?ll dread the word. And it will happen to you. Let?s say you and Jane didn?t communicate properly and you both worked on the IsCloseToPlayer method for the HorizontalEnemy class. Jane commits and pushes her changes first, followed by you:

git commit -am “implemented IsCloseToPlayer on EnemyHorizontal”git pull origin develop

BAM! Big fat warning from Git: ?You have merge conflicts!?

Well, this blows. What happened?

Git can?t decide if your version of the code is ?better? than Jane?s. Both started from the same base commit and changed the same part of the code. There?s no way for it to tell which version of the new code is better. It?s then up to you to decide. Git will show you the differences, and you have to resolve the conflict. You decide if your version is better or hers.

You could do one of two things here: (1) revert your changes and accept hers or (2) resolve the conflict using your version of the code, then push again.

GitFlow workflow

I know all this sounds complicated for now, yet it gets a lot more complicated?

The above process works fine for very small teams working on small projects, but it starts falling short very quickly. You want to minimize conflicts and losses of code as much as you can.

A common ?framework? is the GitFlow workflow. I use it all the time on my projects. Going into the details of the workflow would be beyond the scope of this article, but it would end up looking something like that:

Image for post

You can find more information on it here.

5.4 Become insanely resourceful

This is the number one skill of any programmer. Which is great because this is also one of the most useful life skill you can ever master.

As you keep learning Programming, you?ll frequently come across stackoverflow.com or similar websites. When you Google how to do something in programming, chances are someone else had the same issue as you did and someone else gave a clear answer and how to fix it. That question/answer is likely found on StackOverflow.

So, as a junior developer, spend a good amount of time Googling how to solve things in the language and framework you are using. There?s no shame in not knowing every answer. There?s simply too much to Programming to know everything.

If I?m working in a language I?m not familiar with, I frequently Google the syntax. If I?m working in a framework I?ve never used before, I Google ?How do I do <this> in <that> framework?. Everyone does that.

In the programming world, you?re always expected to be resourceful and figure out answers by yourself first ? which is a great way to learn anything. If you can?t figure it out after trying, then is the time to seek out help from others, either in person or by asking on StackOverflow.

Programming is the kind of skill that never stops evolving. If you can?t adapt, you?ll be left out.

When I hire programmers, I like to give them assignments in languages they?ve never worked with. Stressful? Sure, but it proves how adaptable they are. And that, to me, is more valuable than someone who knows 95% of a language.

6. Where can I find great material to learn Programming?

Nothing is timeless with Programming so it?s hard to recommend things that will remain valuable forever. At the time of writing this, these websites have remained great for learning programming (I?m not affiliated to any of them):

  • https://www.codecademy.com
  • https://www.khanacademy.org/computing/computer-programming
  • https://www.udacity.com
  • https://lambdaschool.com
  • https://www.appacademy.io
  • https://www.freecodecamp.org/
  • https://www.youtube.com/user/learncodeacademy

If you like books, over a decade ago, I read Code Complete, by Steve McConnell, and it has remained the most comprehensive guide on how to become a great programmer.

Other than that, remain resourceful. Always strive to find new great resources!

Conclusion

This article covered a lot of material. You are NOT expected to understand everything in one go. Remember, for Programming, you should be practicing at least 5x more than you are acquiring knowledge.

This article, if read in its entirety without stopping to understand, takes 30 minutes to read. If you stopped to think about the concepts, it can easily take 1 hour.

I?d argue that to understand everything in this article, you?ll need about 5 hours of practice if you?re already a logical person, and likely more than 10?15 hours otherwise.

So, save this article and refer to it again and again as you work on getting better at Programming.

Always remember why you?re doing this. Practice daily and don?t give up when things get complicated. Apply all the good principles from section 3 and you?ll be equipped to learn the skill of Programming faster than you?d ever expected.

When?s a good time to start? How about NOW?

You can do this!

Thanks for reading, sharing, and following! 🙂

Check out my deeply actionable Course on 10 Skills to Improve Your Learning in 10 days.

12

No Responses

Write a response