All posts Career

Teaching Yourself Software: What Actually Worked Over Seven Years

I have been teaching myself since 2018. Here are the three habits that worked, the two methods that did nothing for me, and the order I follow when I learn a new language.

DT
Demir Taşdemir Mobile App & Web Developer
— min read

I started with Python in 2018. I was not enrolled in a program and nobody was guiding me. Today I work with Swift, Kotlin, Java, Dart and JavaScript, and I have apps published in the stores. Along the way I got a lot of things wrong.

This post is about which of those mistakes were genuinely a waste of time and which habits actually paid off. Not general advice — just the things I could measure in myself.

The first thing that did not work: watching courses end to end

For a long time my routine looked like this: find a course series, watch it from start to finish, then move on to the next one. Editor open beside me, typing along exactly as narrated, it runs, on to the next chapter.

The problem with this method is that you think you are learning. Everything makes sense in the video because the decisions have already been made; you are only typing. When I finished a course and opened an empty file, I had no idea what to do. The knowledge was there, the practice of making decisions was not.

The method I use now is the reverse: I first decide on the small thing I want to build, then go to a source at the point where I get stuck on that thing. The source is consumed at the moment of need, not as a whole. It feels like learning slows down, but how much of it sticks is on another level entirely.

Where you get stuck is where you learn

When you do something comfortably you are not learning, you are repeating. Learning happens exactly at the moment when you do not know what to do and you sit there with it for a while. That is why I now read being stuck as a signal: if a problem is frustrating me, there is probably something to learn there.

The second thing that did not work: collecting languages

For a while I aimed to give each new language a week and learn its basics. What I ended up with was someone who knew the syntax of five languages but had never finished anything with any of them.

I realized this late: the difference between languages is much smaller than people assume. What you actually learn is not the language itself — it is concepts like state management, asynchronous work, memory, data modeling and error handling. Once you learn those deeply in one language, moving to a second one takes days rather than weeks.

In concrete terms, this is how it went for me: after the concepts settled with Java on the Android side, moving to Kotlin was not difficult, because what I had to learn was new syntax, not new concepts. In the same way, the asynchronous flow model I learned in Swift felt familiar once I found its counterpart on the Dart side.

The first thing that worked: projects small enough to finish

The biggest risk when you are self-taught is running out of motivation. The only thing that prevents it is being able to look at something finished at regular intervals.

My criterion for picking a project became this: small enough to be working by the end of a weekend, but meaningful enough to solve a real problem. Artificial projects built "in order to learn" never carried me; small tools I actually needed did.

Finishing has another benefit: while completing a project you inevitably run into the boring parts — error states, edge cases, setup. Most of the real work is there, and you only learn it by finishing.

The second thing that worked: taking debugging seriously

For a long time I treated fixing bugs as "searching": copy the error message, paste it, try the first answer that comes up. Sometimes it worked, but I did not know why it worked, so nothing accumulated for next time.

What I changed was forming a hypothesis before fixing anything. I write out a sentence like "I think this variable is not holding the value I expect here," then I run the smallest check that would confirm it. If it is right, I have found the cause; if it is wrong, I have still moved forward because I ruled out one possibility.

This habit is the single thing that changed my learning speed the most. Because now every bug leaves behind a piece of knowledge about how the system works.

The third thing that worked: getting used to official documentation

In the beginning I avoided documentation — it felt dry, detailed and not written for a beginner. Videos and blog posts were easier.

But past a certain point second-hand sources stop being enough: once what you are looking for is specific enough, there is no post written about it. Getting used to reading official documentation is a precondition for being able to work independently.

The method I used to get comfortable was this: open and read the documentation for a function I was already using in working code. Not while trying to solve a problem, but when calm. That way you learn how the docs are organized and you do not get lost when you really need them.

Do not leave pasted code alone until you understand it

You found a solution, pasted it in, and it worked. If you stop there you have taken on debt — and you repay that debt by getting stuck again on a similar problem. These days I read every block I paste line by line and explain to myself what it does; if there is a line I cannot explain, I go look it up. It takes five minutes and it keeps me from hitting the same problem a second time.

The order I follow when learning a language

When I move to a new language I now have a standard order:

  1. Basic syntax — variables, conditionals, loops, functions. Less than a day.
  2. Type system and null behavior — this is where the language produces the most bugs, so it needs to be learned early.
  3. Collections and transformations — filtering, mapping and grouping a list. Most of the daily work is this.
  4. The asynchronous model — how a network request is made, how the result is awaited, how errors are caught.
  5. The ecosystem — package manager, project structure, common libraries.
  6. A small app — something finished that uses all five of the above together.

When I follow this order, becoming productive in a language takes far less time than long courses do. The first three items are similar everywhere; the real time goes into the fourth and fifth.

What happens without a degree

This is the question self-taught developers ask most. My observation is this: the other side wants proof from you. A degree is one form of proof; but a published app, an open source contribution, or a project whose depth is obvious when you talk about it is proof too.

That is why I keep the things I build while learning and make them explainable. When you can describe a project not as "I built this" but as "I solved this problem this way for this reason, the alternative was that, and I did not pick it because of this," the conversation goes somewhere completely different.

The disadvantage of teaching yourself is the lack of feedback. The advantage is this: you know what you learned and why, because you came to every topic out of a need. Looking back after seven years, I think the second one outweighs the first.

  • Career
  • Learning
  • Software
  • Experience
Share: LinkedIn X WhatsApp
DT

Demir Taşdemir

Mobile App & Web Developer

I have been building software since 2018. I have published 11 apps on the App Store and Google Play; right now I am working on 6 mobile apps, 1 e-commerce platform and 1 desktop game.

Not sure where to start?

Having walked the same road, I am happy to answer your questions. If you want to talk about which language to start with or which project to pick, you can write to me from the contact page.