Ask HN: How do you learn to build substantial, real world apps?
I am learning to build apps in android. Most of the tutorials and even books I come across have quite small examples to follow, usually 2 activity files and 2 layout files. Honestly, the progress to build a substantial app is a bit slow because the projects are so small. It feels like being stuck as a beginner.
Looking at examples of most apps, they are usually made up of 10+ class files serving the app. I want to know what resources are out there that help you make the move from learning to build an app by showing you the basics to something substantial with architecture and design patterns - not necessarily spelt out but present nonetheless.
I want to know how you made the jump to 10+ files in a project, what resources are out there that lead you to get to that level?
47 comments
[ 4.6 ms ] story [ 126 ms ] threadPerhaps I'm missing something?
@smckk the closet thing I can think of that may help you is to visit large company's engineering blogs that sometimes do small to large writeups on big changes in their architecture, code organization style, etc. It's not as detailed as seeing the actual changes line for line but it can help guide your thinking of taking a piece of non-trivial code to another level of non-trivial code if that makes any sense.
Basically I've run a profitable production web app for 10 years (~14k LOC, 200k monthlies, revenue higher than any day-job I could get) as well as a few Android/IOS apps.
Now I'm creating videos where I show various real-world aspects of writing software in the context of my own production code - e.g.
- architecture
- rapid response systems to production errors
- dependency choices
- data integrity guarantees
- integration testing systems
- softer stuff, like optimizing for SEO and on-page conversion.
There's not enough non-beginner material out there and I hope to help fill that gap in resources.
They're all available here: https://www.semicolonandsons.com/series/Inside-The-Muse
Just want to say there is a huge vacuum for this sort of content, and I'd definitely pay for it!
I'm particularly excited for the "rapid response systems to production errors" and "integration testing systems" parts!
Do that Asian for a number of projects and you will see that every project looks different, maybe better maybe more complicated than it should.
My group of friends used to run a pool where we would handicap NFL football games and pay out prizes to the top 10-15% of finishers each season. The pool grew big enough to the point where it was a pain to manage manually, so I ended up building a small app where we could create new pools, users could sign in and make / edit picks, it would track the standings, etc. It would scrape the final scores/results of NFL games to grade everyone's picks, and each Tuesday it would scrape the consensus lines to set the spreads for each weeks slate of games.
Im not really sure "how" I made the jump per se, it just became one of those things I couldn't wait to work on. Anytime I ran into difficulty it was like getting stuck in a video game, I would try new things until I fixed it. Gradually over time things started to fit into place and a functional (but clunky) web app emerged.
It wasn't pretty (this was a long time ago), but it worked, and we used it for our pool for a few seasons without a hiccup. I still remember the afternoon I made the "final" commit as one of the happier moments in my career.
Perfect is the enemy of good. Your tech doesn't need to play buzzword bingo out the door, it just needs to solve the problem.
Couldn’t agree more. What better way to learn development than actually experiencing the direct results of your actions. Not only do you practice app development, your UX design skills will Improve dramatically.
About 10 years ago, while at school, I achieved the second highest non-degree qualification in piano, an LRSM diploma. But, gone are the days of being able to or even wanting to spend 4 hours a day practicing. I needed to get more efficient. The problem is that I’m objectively terrible at practice - I learn the first page, then enjoy playing it so much I never get on to the second.
I made an app that helps me with this. I upload an svg score (lilypond, I use Mutopia scores then correct any discrepancies with whatever urtext I have), then use the app to break it into a tree of segments. The app then shows me, for 5 minutes at a time, the first 5 segments I haven’t marked as completed. Right now, it does nothing more, but it’s fantastic.
It’s also objectively terrible proof of concept code, but crucially I’ve learned more about the UX requirements with the POC than I would ever have learned by planning ahead.
In my general development experience the amount of files/classes/functions/modules/whatever you use is really just about organizing your code in a way that makes it easier for you to work on one part of the code at a time. The idea being that once you know you have part of your code working the way you want it to, then you can forget about that part and focus on the next bit.
As far as when and where to do those splits, it's not always obvious, but it comes with experience in the language, and a greater understanding of what you want your application to be. When in doubt, just get it to work as best you can. Then when you find yourself digging through a giant method to debug 4 lines that could stand on their own, or copy/pasting a blob of code that could be a function, or just wishing to yourself that there was a library that did exactly what you needed, then take a step back and think about how to make it better.
Sometimes the solution won't present itself until you have to go back and make changes years later. In that case, fight the urge to throw it all away and start over, but remember the pain for your next project.
What you’ll find is that it doesn’t typically exist.
Unless your app is following a particular category of app (is it a todo app, mostly crud, is it just a skin over a bunch of read only APIs, is it a game?) your app will grow organically and as the complexity grows you’ll naturally start breaking things up, realising certain parts can be generalised where it’ll be useful not to one, two or even three other bits of code but dozens (don’t be afraid of a little repetition, MUCH better to repeat 5 lines of code thrice than to create another function).
Also with more complexity and simple volume of code, testing becomes indispensable. At some point it becomes difficult to foresee how interdependencies in the code might be affected if you change something.
Running a suite of tests will save you lots of time. And you need test files for that.
If you’re looking for the way to get you more organised I’d recommend building a test for every function you write. It’s very interesting how that changed my code suddenly every bit of code I wrote felt independent but connected, it was also nice to feel like at any time I could feed a function some dummy/simulated data and it’d spit out the same output. There was no hidden state being mutated somewhere else. No global vars.
It is Software Engineering. SE, will be a bit generic and won't directly talk about making an Android app. So you will have to take generic principles and apply them to a specific domain.
The code was ugly, but each project got more sophisticated than the one before and showed me the value of certain techniques (after having done things in a more difficult way without them).
Tutorials are fine, but you really need to work on your own projects afterwords and use what you've learned. You'll get stuck and have to struggle through parts, and in the process learn quite a bit. Start with smaller projects and work up to bigger ones.
There needs to be more books on concrete software development principle that fill the gap between basic software dev 101 and software design patterns.
Like practical books on building an app.
You'll very quickly bump into real-world problems you've never solved before, both in implementing the requirements of the app and in organising your code as the implementation grows.
Plus the design is already done for you (which honestly feels like cheating, as it removes an entire aspect of the app you normally have to worry about in parallel with the rest of the implementation), so you'll also get experience working to a design spec.
I've been scratching some of my own itches while learning Flutter, which has resulted in a bunch of apps with a small number of screens, without user auth or any complex API usage. A workout timer (2 screens), a simple trivia game (3 screens), a remote control (~5 screens), a sound/video/image board for SEN kids (7 screens in a single ~3000 line .dart file)…
Then I tried cloning the app my gym was using to post workouts and log results before it closed down due to COVID-19 - boom! [1] Just from this one app I've gained experience with Firebase Auth, Cloud Firestore, Cloud Storage, co-ordinating and navigating between 24 screens and counting, CRUD screens, screens with multiple user permissions in play, sharing editable data between multiple screens, some fairly complex dynamic display logic in the workout editor, creating bar charts with user statistics, implementing specific little interactions the original app has (like smoothly sliding a comment input into view as you scroll down and sliding it out as you scroll up) and umpteen other things I can't think of right now.
[1] https://www.youtube.com/watch?v=DvWJgZKj7cw
It's so easy to ignore the real-world concerns of a product by just cloning the visuals, sticking a ribbon on it, and calling it a day.
I find this to be a valuable exercise in moderation, but at some point you'll need to build some products from scratch (and I'm not even really talking about the code itself) to gain the requisite experience.
Build a more complex app that you would use.
So pick out a hobby or something that interests you that an app would improve your experience with.
Plan out the requirements/scope and start building it.
Building any app you're going to run in to things that you won't find a tutorial for, or you might have to combine a few tutorials to create it.
That's the best way to learn, is just taking on something and building it.
If you don't have any ideas, ask a friend or family member if they could use an app. You'll learn even more if someone else is telling you what they need/wish it could do.
Good luck expanding your skills.
https://github.com/igorwojda/android-showcase
Do not worry about the size of your app. Managing decoupled apps is way more annoying then conciseley written ones. And by the phrasing of your question I assume you are projecting the complexity of the codebase to the capabilities of the app.
My piece of advice is the following: When developing for mobile modularize the functionalities by screens and aim for a strong coupling within them. Even when the functionalities are growing (proportional to the success of the app, that is), you will not often see too many similiarities between them and the redundancy is factored out easily.
Only when starting to develop a larger app which shares multiple screens across it could make sense to bundle differently. In this case, you want to structure the codebase by your tests. Most of the time, reusing a screen creates plenty pitfalls, which can simply be avoided by not reusing.
Due to grouping the functionalities by screens, issues will mostlikely not be related to eachother. Also, in my experience, libraries introduce more issues then solving, so trying to keep the app barebone will often result in a smaller download size and a more robust app.
When applying these thoughts properly a larger app could look like the telegram client! https://telegram.org/apps#sourcecode
Hell, my own Android app has just 1 Activity and it is making me money (just a cup of coffee haha) everyday, does this counts as real world app?
Like you mention there aren't tuts on complex systems as a single thing. I'd say because complex systems solve quite specific things and usually delve deep into domain specific problems that aren't of interest to people outside that domain
What it meant in practice is writing functions as a collection of calls to other smaller functions. Each function does only one thing. I spend most time on naming objects, functions, and variables. It is hard in the beginning to not use non-descriptive names, but then you have to re-read that code and mentally rename it each time in your head while struggling to understand what it does.
Writing test code to validate shorter functions becomes fluid. When you can easily understand your code and can depend on it not breaking, you will find it’s easier to add features and expand existing features.
You will find many good talks on YouTube, but they really summarize what they wrote in books.
One good exercise is to reimplement built-in language algorithms like sorting and string manipulation from scratch.