by smckk on 6/11/20, 11:59 AM with 44 comments
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?
by kadabra9 on 6/11/20, 2:16 PM
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.
by semicolonandson on 6/11/20, 1:29 PM
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
by insin on 6/11/20, 3:21 PM
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.
by holografix on 6/11/20, 2:49 PM
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.
by melenaos on 6/11/20, 2:11 PM
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.
by stonemetal12 on 6/11/20, 2:56 PM
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.
by AlchemistCamp on 6/11/20, 3:03 PM
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.
by tommyage on 6/11/20, 5:31 PM
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
by dec0dedab0de on 6/11/20, 2:23 PM
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.
by peterkos on 6/13/20, 7:05 AM
Like, for Instagram. First, just the scrolling list of images. Then, images with text under them. Then, a tab bar with images and a profile. After enough of this, a basic skeleton will form and you'll start hitting the fun edge cases: how do you edit a user's comment? How do you make sure user data is always in sync? How do you handle every possible API error that you might get, and communicate that simply to the user?
Open source projects are also a great reference. As an iOS dev, I'm biased, but I've heard Android code tends to err on the side of "meh, it works", even in large projects, so be on the lookout for that. Software architecture tends to be fairly consistent across platforms in my experience anyways.
by wiseleo on 6/11/20, 11:03 PM
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.
by saluki on 6/11/20, 3:26 PM
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.
by easytiger on 6/11/20, 12:59 PM
Perhaps I'm missing something?
by projektfu on 6/11/20, 2:45 PM
by brianolson on 6/11/20, 4:42 PM
by janee on 6/11/20, 9:46 PM
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
by villgax on 6/11/20, 2:11 PM
by nickthemagicman on 6/11/20, 3:11 PM
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.
by lovelearning on 6/11/20, 4:29 PM
by soulchild37 on 6/11/20, 6:48 PM
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?
by bluedino on 6/11/20, 5:47 PM
by rtcoms on 6/12/20, 1:31 PM
by ykevinator on 6/11/20, 10:59 PM
by plantain on 6/11/20, 6:58 PM
by Ologn on 6/12/20, 10:41 AM
Two activity files? That's a lot. With Jetpack Navigation, you can have substantial real world apps using one Activity.
I have programmed Android apps professionally for a number of years, from substantial, as you describe it, apps for Fortune 100 companies, to smaller apps for much smaller companies.
There are two things to consider looking for examples - one, is you want an app using modern Android architecture. That it is using coroutines would be one of the main markers of this. Also it would probably be using Navigation, View Models, and Live Data. It would be written in Kotlin, of course. The architecture being MVVM, or possibly Clean Architecture with use cases. Possibly using Dagger for dependency injection.
You might find some older substantial, real world apps using architecture and design patterns, but they might be ones not used much any more - maybe an app written in Java that made direct non-Room access to SQLite to get and retrieve local state (or, forbid, Shared Preferences), maybe Volley to access a web API, Asynctasks to do background work, Loaders to load data - none of this is current best practice, and much of it is deprecated.
If I had the choice of a model to be a small, modern example app, or a several years old out-of-date substantial, real world app, I would choose the basis to be the smaller, more modern app.
Google has some example apps. I think this is a decent one - https://github.com/android/architecture-samples
Both the main branch, and the slightly more out of date dagger branch.
This has all the architecture you need for a bit. The main thing it is lacking is network access, but you can learn that from other Google example apps.
What is architecture in an Android app? It can be thought of as a few things. One is just a clear line from the ultimate authority of state (say a web API) to the I/O of a screen. You tap a view, it goes to a fragment, under the management of an activity and navigation - and the fragment sends data to a ViewModel, which sends data to a repository, which sends that data to a remote data source. There might be a response which filters the other way. So a clear separation of UI and state model, and a clear line of transmission between them.
Another way to look at Android architecture is in the clean sense. You have a model for state which does not change much - organization-wide (like enterprise-wide business) data models and rules which are the same across the organization. These do not change much, and have no dependencies on classes apt to change. Dependent on these organization-wide, system-wide shared data models are data models that are specific to your particular app - application specific data models and rules. Dependent on these application specific rules/models are interface adapters like presenters (or view models, or repositories). Then dependent on these interface adapters would be the UI, web API and DB layer - the framework layer.
In both of these, architecture is the protection of the platonic ideal of the critical data structures used from the flittering volatility of the input and output of UI. In the case of clean architecture, it is protection from the specific framework dependencies needed to store and retrieve data model state as well.
In terms of design patterns, you make use of them in Android when needed - from singletons ("objects" in Kotlin), to adapters (particularly for RecyclerViews and such), to observers (used for Live data).
In terms of large and substantial apps, once you break out into different teams working on different parts of the app, you will usually (although not always) have the app broken into different modules for different features of the app. As your main concern seems to be apps which have more than ten files in a project, I take it you are not talking about apps so large they cross this threshold into one with multiple modules used by different teams in an organization within one app.