The Best Way to Learn to Code is to Code: Learn App Architecture by Building Apps
Learning to code can be tough. One of the biggest challenges I faced when I was learning was how to make the jump from learning resources and little practice challenges that teach you coding basics to full blown apps.
There’s no other way around it. The best way to learn is to jump in and start building, but that can be very daunting. Where do you start?
Users & Authentication?
You might think that user management and authentication is a good first step to learn. You’d be wrong. First of all, passwords are obsolete, so all your new apps should use passwordless authentication.
Second, user authentication is a huge security risk, and should not be left to newbies under any circumstances. Hundreds of millions of login credentials have been stolen from major companies with dedicated security experts who do nothing but work around the clock on how to improve security. Chances are very good that some of your login credentials have been stolen.
It isn’t just dangerous to your app if you screw up user authentication, it’s dangerous to your users, because they may be using the same login credentials for other apps, like their email provider, or their bank account. In other words, if somebody steals passwords from your app, they may be able to use them to do real damage in areas that have nothing to do with your app.
Remember, user authentication is a huge security risk, and should not be left to newbies under any circumstances.
I recommend that most apps delegate authentication tasks to outside authentication providers such as Facebook, Twitter, or similar. Even large apps backed by big businesses who have legitimate reasons and the resources to manage their own user authentication strategies should be using popular, battle tested libraries rather than rolling their own authentication from scratch.
But there are many tiny single user apps that you could build that don’t need user authentication at all, and some apps that could benefit from user authentication could add that feature later.
One good way to start your transition into real apps is to build browser-based apps using `localStorage`, supporting only a single user, and then scale up from that foundation. You can add multiple users and database connectivity later, after you’ve mastered the basics of modern client-side app architecture.
Introduction to Client Side App Architecture
So what does modern client-side application architecture look like? Just a few short years ago, it was dominated by MV* architectures such as MVC, MVP, MVVM, etc…
Most of them deal with how to coordinate between models (data) and the view (UI/Presentation). An important concept in application architecture is separation of concerns.
Here are some of the concerns we like to keep separate:
- Presentation/view (layout, style, DOM manipulation)
- Event handling/actions (capture and transform input from users and external messages into actions in the app)
- Routing/URLs (translating URLs to actions)
- Business logic (rules for how data is manipulated)
- Client state management/model/store (in-memory client-side data structures)
- Data persistence & server I/O (long-term data storage, AJAX, SSE)
MVC architecture looks something like this:
In MVC, the model emits change events, and the view responds by querying the current state and updating. The controller listens to view events and responds by updating the state, and potentially manipulating the view as well, or selecting a new view in response to routing changes.
With 2-way data binding changes to the view are directly reflected in the model without going through the controller. Imagine that instead of simply querying the state, the view could also update the state directly. That’s 2-way binding in a nutshell.
A user input might trigger a state update, which might trigger a DOM change, which might trigger another state update, which might trigger more DOM changes, and so on. It quickly becomes difficult to understand how changes can cascade and impact the state of your app, and it becomes easy to accidentally introduce infinite loops.
An example of this is Angular 1. Angular 1 attempted to manage this complexity by taking control of the UI state update loop (called the digest loop). In order to avoid infinite messaging recursion, the digest loop had a hard-wired limit of 10 cycles, but that still left a lot of room for a single event to send off a cascade that would cause lots of DOM changes, which could trigger more cycles. In addition to being complex and difficult to understand, it was also a common cause of performance problems in Angular, because a single change can trigger a large cascade of updates.
In 2013, Facebook announced React: a new open-source framework for building user interface components. React doesn’t care how you handle data updates, but it does not support 2-way data binding. Instead, you’re encouraged to use unidirectional data flow, pairing React to something like the Flux architecture.
React & Flux have radically changed how we build web platform apps, and the idea of unidirectional data flow has spread into the Angular and Ember apps as well.
The Flux architecture looks something like this:
Instead of propagating changes through a large number of event listeners, callback functions are passed into the view, which get hooked up to the DOM event listener callbacks. The callback produces an action object which gets dispatched to the store where the state changes are managed.
When you add server I/O to the mix, it can look like this:
In addition to view callbacks, many apps will also have event listeners wired up to communicate with the server. UI actions may also dispatch server queries and relay updates to the server. So, an action callback from the view may trigger a server query or update, and a listener for server sent events may trigger further actions, which could be dispatched to the store, and so on.
You may have heard of Redux, which is currently the most popular Flux alternative. It adds the concept of pure functions for store manipulation, called reducers. The reducers simplify how to reason about the store by ensuring that each kind of state update can be independently managed and tested, and that reducers have no side-effects, which means it’s simple to understand the impact of any particular action. For a great overview of Redux architecture, check out this slide deck.
For your first apps, you probably don’t need to deal with all this architecture. We arrived at these architecture updates by building large applications, where unrestricted shared access to application state can get confusing and messy. These abstractions give us a clear circuit for all state changes in the application, but they’re probably overkill for trivial applications.
Initially, you may wire up event listeners and directly manipulate your application state in response, and that’s OK. Learn to walk before you run. When you’re ready to move on to more complicated apps, check out Dan Abramov’s excellent courses, “Getting Started with Redux” and “Building React Applications with Idiomatic Redux”.
Every developer needs a code portfolio. Practice apps are a great way to build one.
As you explore the above mentioned courses, you’ll be exposed to the very commonly used To Do list example app. I recommend you follow along with the tutorials and put one together yourself.
But what other interesting apps could you build? One of the hardest things about learning to code is coming up with good ideas for apps to build.
There are sites that aggregate and rank app ideas by votes. Definitely take a look at those if you’re looking for ideas.
Example Project: Rejection
Want to work as a team? Find a coding buddy in the student chat.
You gotta lose to win.
Train yourself to:
- Get a raise
- Sell more
- Develop more business
- Negotiate better deals
The game has one rule:
You must be rejected by a human being at least once per day.
Ask for things outside your comfort zone, and you’ll find yourself winning a lot more.
Win = 1 point. Rejection = 10 points.
How long can you make your rejection streak last?
Build a UI that lets you keep track of your score. Include a text input for the ask, who you asked, and two buttons: “Accepted” or “Rejected”. For asynchronous requests such as emails or messages, record the score at the time you get the answer, not at the time you ask.
Use HTML+CSS and store a record of the data in local storage.
Keep a running tally of the user’s current score. Remember that the day’s subtotal needs to be recalculated each time an ask is accepted or rejected, so it will be useful to keep the list in an array that you can reduce with each new answer.
- Add an API to store data using a web service and database.
- Add authentication and track multiple users. Hint: Redis, Mongo, or RethinkDB would be good database candidates.
- Social login such as Facebook or Twitter would be good authentication options (easier and more secure than username/password logins).
- Share your score and compete with your friends on Facebook.
- For each user, keep a leaderboard from their circle of friends.
- Add mobile apps
- Fork the repo
- Implement your solution.
- Open an issue with a link to your fork.
To get credit, you must open an issue with a link to your fork.
He spends most of his time in the San Francisco Bay Area with the most beautiful woman in the world.