😵‍💫 5 Programming Concepts Every Newbie Finds Confusing (And Tips for Learning Them)

Cherlock Code 🔎 - Sep 7 '23 - - Dev Community

The things we all find difficult and how to tackle them.


I grew up in an era where my first steps into coding consisted of simple static HTML pages and websites.

If I could successfully change the background colour of a web page, I was happy.

The fanciest thing I did was create moving text using <marquee> - does anyone still use this? 🤔 haha!

But as time went on websites became more dynamic, and mobile apps started to take off, I had no choice but to move on to learn more complex programming skills.

So I started dipping my toes into JavaScript, and at the time if there was one word I could use to describe that transition it would be: baffling.

The learning curve was massive!

With so many concepts, paradigms, methods, and frameworks to go through it’s no wonder I felt overwhelmed.

You might be feeling or have felt the same way too - and that’s okay.

The good news is, that you're not alone in finding the initial stages of learning programming to be head-spinning.

Every experienced developer has been through the growing pains of wrapping their heads around entirely new constructs and patterns of thinking.

In this article, I'll break down five of the most notoriously tricky concepts that baffle new coders.

We'll walk through core ideas and I'll explain where the difficulty lies in each area and share the tips and resources that can help you level up as a developer.

Take comfort in knowing that confusion is part of the journey.

With time and the right strategies, you can master programming's steepest hurdles.

Let’s go through 5 programming concepts that every newbie dev finds confusing:

#1 - Recursion

Coding in Circles 🔃

Recursion is a programming concept that involves functions calling themselves. On the first encounter, this idea can tie your brain in knots! 🤯

Let's take a simple example: calculating factorials.

The factorial of a number N is the product of all the integers from 1 to N. For example, 5! (read as "5 factorial") is 5 x 4 x 3 x 2 x 1 = 120.

To calculate factorials recursively, we can break it down into:

Base case: The factorial of 0 is 1.

Recursive case: The factorial of N is N multiplied by the factorial of N-1.

So a recursive factorial function in JavaScript would look like this:

function factorial(n) {
if (n === 0) {
return 1;
}
return n * factorial(n-1);
}
Enter fullscreen mode Exit fullscreen mode

See how the function calls itself?

The confusion arises from trying to unwrap how all these stacked function calls resolve.

To unravel the magic, we need to understand the call stack. Each recursive call adds a new stack frame until we reach the base case. Then the returns start resolving the calls from the bottom up.

Debugging with print statements at each call also helps visualise this.

Overall, practice makes recursion click eventually.

Start with simple examples and work your way up to more complex recursive problems.

#2 - Asynchronous Programming

Out of Sync 🔄

Asynchronous programming refers to code that doesn't run in a predictable, sequential order. This is common in JavaScript given its event-driven nature.

For example, fetching data from an API is asynchronous because the response won't be ready instantly. We use callbacks, promises, or async/await to deal with this.

Understanding asynchronicity requires shifting your thinking or mental model.

Instead of thinking step-by-step, you have to visualise how things run concurrently.

Callbacks make this especially tricky.

A classic example:

setTimeout(() => {
// runs after 2 seconds
}, 2000);
// more code here runs right away
Enter fullscreen mode Exit fullscreen mode

The callback inside setTimeout() gets deferred while the remaining code executes. This inversion of control flow can make reasoning about program logic quite challenging!

Some tips:

  • Practice with simple examples using timers, promises, etc.
  • Visualise the JavaScript event loop and how the call stack/queue interacts.
  • Use diagrams to map out the flow when callbacks are involved.
  • Try rewriting async code in a synchronous style first, then introduce asynchronicity.

It takes time to adapt to asynchronous programming.

But with the right mental models and techniques, you can get your head around writing asynchronous code.

#3 - Algorithms and Data Structures

Organising the Chaos 🧩

Algorithms and data structures are fundamental to writing efficient and optimised code.

But for beginners, knowing when and how to apply them can be baffling.

Data structures like arrays, linked lists, trees, graphs, and hash tables are ways of organising information in the computer's memory.

Different structures have trade-offs in terms of operations like search, insert, delete, and access.

Algorithms are step-by-step procedures for tasks like sorting, searching, and more complex problems.

The efficiency of algorithms is analysed using Big-O notation in terms of time and space complexity.

Choosing the right data structure and algorithm for a problem requires weighing many factors.

Understanding the mathematical analysis behind their performance takes time to grasp.

Some tips:

  • Learn individual structures and algorithms thoroughly first before combining them.
  • Use visualisations to understand the logical connections and flow of data.
  • Practice implementing structures and algorithms from scratch.
  • Apply your knowledge to problems on CodeWars, LeetCode, HackerRank, etc.
  • Read others' code that employs data structures and algorithms.

Over time, you can develop intuition for how to organise data effectively and efficiently.

#4 - Design Patterns

Breaking down the Blueprints 🗺

In programming, design patterns are reusable solutions to common problems in object-oriented design. Patterns like "singleton", "factory", "observer", and "MVC" come up frequently.

Understanding when and how to implement patterns can be challenging for a few reasons:

  • They are abstract conceptual templates rather than concrete examples.
  • Knowing which pattern fits a situation takes experience.
  • They can feel unnecessarily complex at first.

Here are some tips for debunking patterns:

  • Study sample code that implements various patterns. Seeing them in action makes their purpose clearer.
  • Try refactoring code without patterns into a more robust design using patterns.
  • Work through case studies and examples of applying patterns to UI, databases, networks, etc.
  • Start by thoroughly learning a few key patterns rather than trying to master them all immediately.

The value of design patterns grows as you gain experience.

Learning to identify solutions that can apply across projects saves time and technical debt.

Immerse yourself in pattern examples and over time, they will make more sense.

#5 - Functional Programming

A Change in Mindset 🧠

Functional programming represents a dramatic shift from the imperative style that dominates in languages like JavaScript.

Core principles like immutable data, pure functions, and avoidance of side effects require a new mode of thinking.

Some key difficulties beginners face:

  • Letting go of state changes and embracing immutability.
  • Thinking in terms of transforming data instead of step-by-step flows.
  • Getting your head around higher-order functions like map, filter, and reduce.
  • Knowing when and why to apply functional techniques.

Here are some tips for getting up to speed:

  • Practice using built-in functional methods like map and filter on arrays.
  • Try rewriting some imperative code in a functional style.
  • Learn how concepts like closures, recursion, and currying work.
  • Complete interactive exercises that teach functional concepts and patterns.
  • Understand benefits like testability, concurrency, and modularisation.

Functional programming requires a slight perspective shift but can produce cleaner and more reliable code.

A step-by-step approach focused on core concepts will ease the learning curve.

Conclusion

Learning to code comes with its fair share of brain-bending concepts.

The ideas we've covered - recursion, asynchronous programming, algorithms, design patterns, and functional programming - trip up nearly every new programmer.

These hurdles can seem intimidating, but each one represents an opportunity to level up your skills in meaningful ways.

Building up skills in these core programming topics will allow you to write more efficient, scalable, and maintainable code.

The key is to be patient with yourself.

Break complex ideas down into smaller steps.

Use diagrams, examples, and plenty of practice to train both your logical and coding muscles.

Stick with it through the inevitable confusion, and eventually, you'll reach those satisfying "aha!" moments.

These concepts highlight key milestones on the journey.

When you reflect back from years of experience, you'll appreciate how far you've come from those early days of feeling baffled.

Yet always keep that beginner's mindset - ready to learn, as after all we are ever-growing devs! 🌱

From your fellow ever-growing dev,

Cherlock Code


💙 If you liked this article...

I publish a weekly newsletter to a community of ever-growing developers, seeking to improve programming skills and stay on a journey of continuous self-improvement. Focusing on tips for powering up your programming productivity 🚀.

Get more articles like this straight to your inbox.

Let’s grow together 🌱

And stay in touch on 𝕏 @evergrowingdev


Dev Pages

And if you're looking for the right tools to build awesome things, check out Devpages.io, an ultimate hub I built with 100s of developer tools and resources 🛠

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .