Building a scalable, modularized, testable app from scratch
By Android Developers
Summary
Topics Covered
- Unidirectional Data Flow Creates Reactive UI
- Feature Modules Enable Parallel Development
- Test Doubles Isolate ViewModel Logic
- Stateless Composables Simplify UI Testing
- Material 3 Provides Semantic Color Naming
Full Transcript
[Music] hello, I'm, Don, and, I'm, an, engineer, on, the Android, developer, relations, team, today I'm, going, to, show, you, how, to, build, a
scalable, modularized, testable, app, from scratch, now, this, won't, be, a, Hello, World app, I'll, concentrate, on, building, an, app architecture, which, will, enable, your, app to, grow, we, use, modules, to, separate
responsibility, and, create, a, test infrastructure, to, verify, that, your, app behaves, as expected, lastly, we'll, look, at, how, to build, a, flexible, intuitive, and, greatl looking, user, interface, I'll, be, covering
a, lot, of, different, concepts, so, if, I cover, something, you're, not, familiar, with there's, a, link, on, virtually, every, slide which, will, take, you, to, more, information about, the, current topic, throughout, this, talk, I'll, use, the
now, and, Android, app, as, an, example, the source, code, is, available, on GitHub, in, the, app, we, have, a, screen, which shows, content, which, is, customized, for you, it, displays, a, list, of, news, articles
and, allows, the, user, to, bookmark, each article, we're, going, to, take, a, look, at how, the, foru, feature, was, built, starting with, how, bookmarks, work, the, architecture
for, a, feature, like, this, can, be, broadly divided, into, two, layers, UI, and, data, the data, layer, obtains, and, exposes, app, data to, the, UI, layer, as, well, as, performing
business, Logic, the, UI, layer, displays, app data, on, screen, and, reacts, to, any, changes in, that, data, an, important, word, here, is reacts, by, setting, up, a, stream, of, data
between, the, layers, we, are, creating, a reactive, UI, it, just, needs, to, be, told, how to, update, its, state, when, new, data arrives, it's, important, to, understand
that, the, UI, does, not, request, or, Poll, for data, it, just, collects data, the, only, communication, which happens, in, the, opposite, direction, are events, the, data, layer, handles, these
events, updating, its, underlying, data, and emitting, any, changes, back, to, the, UI in, this, way, we, have, a, single, source, of Truth, for, the, apps, data, and, the, data
only, Flows, In, One, Direction, This, is known, as, unidirectional, data, flow, and, is an, excellent, way, of, keeping, your, app, in a, consistent state, if, we, apply, this, General, guidance
to, this, specific, feature, we, can, clearly Define, the, responsibilities, for, each layer, the, data, layer, should, store, user bookmarks, and, expose, them, to, the, UI layer, by, publishing, a, stream, we, can, do
this, using, cotlin, flows, the, UI, layer then, displays, this, information, and updates, it, whenever, it, changes, the, UI should, also, provide, a, way, for, the, user to, add, and, remove, bookmarks, and, these
user, events, are, passed, back, to, the, data layer, so, the, data, can, be, updated, let's dive, into, the, data, layer, to, see, the individual, classes, which, we, should implement, the, data, layer, architecture
can, be, split, into, two, types, of, component repositories, which, expose, the, app, data and, centralize, changes, to, that, data, and data, sources, which, obtain, data, from, a single, Source, let's, take, this, from, from
Theory, to, Reality, by, implementing, the classes, in, the, data, layer, we'll, start, by implementing, a, local, data, source, class this, will, store, bookmarks, locally, on, the
device, using, jetpack, data, store, let's take, a, look, at, the, code, local, data source, accepts, a, data, store, object, as, a dependency, and, exposes, a, stream, of bookmarks, in, the, bookmark, stream
variable, each, bookmark, is, just, a, string ID, of, the, news, resource, which, is bookmarked, data, store, provides, the underlying, data, stream, it, gives, us, a flow, of, data, which, we, then, convert, to, a
list, of, bookmarks, using, the, map, function the, most, important, concept, to, understand here, is, that, we're, not, pulling, data directly, from, data, store, we're, merely setting, up, the, stream, of, data, and mapping, each, item, in, that, stream, to, a
format, which, clients, of, this, class, can use, in, our, case, a, list, of strings, lastly, it, provides, a, function, to update, bookmarks, by, adding, or, removing them, from, a, map, back, by, data, store, each
time, the, bookmarks, change, a, new, list, of bookmarks, is, emitted, into, the, bookmark Stream, flow we, can, now, add, a, repository, to, expose these, functions, to, the, UI layer, the, code, in, the, bookmarks
repository, is, pretty, simple, it, takes, our local, data, source, as, a, dependency, and exposes, The, Bookmark, stream, and, toggle bookmark, function, from, it, if, we, were doing, something, more, complicated, like
combining, data, from, multiple, data sources, this, would, be, the, place, to, do, it a, common, example, is, an, offline, first feature, which, pulls, data, from, a, network data, source, then, synchronizes, it, with, a
local, data source, we, also, need, some, news, articles to, display, and, obtaining, these, can, be implemented, in, much, the, same, way, the only, difference, being, that, the, data comes, from, the, network, rather, than, being
stored locally, we, can, add, a, network, data, source to, pull, news, articles, from, a, rest, API and, a, news, repository, to, expose, those news, articles, to, the, UI, layer, it's, good
practice, to, have, a, repository, for, each type, of, data, in, your, app, so, that's, our data, layer sorted, now, our, UI, layer, needs, to, display those, bookmarks, next, to, each, news
article, and, let, the, user, add, and, remove bookmarks, let's, take, a, look, at, the, UI layer, in, more detail, here, we, also, have, two, component types, the, state, holder, handles, the
screen, logic, and, constructs, UI, state from, app, data, it, does, this, by, listening for, changes, in, the, data, layer, and, the screen, displays, that, UI, State, using, UI elements, again, applying, this, General
guidance, to, our, feature, we, can, Define the, responsibilities, for, each, layer, and the, classes, we, need, to, create, let's, take a, look, at, the, state, holder, for, this, we can, use, a, jetpack, view, model, pre, fixing
the, name, with, for, you, the, name, of, this feature, this, class, listens, for, data, from the, news, and, bookmarks, repositories, and combines, them, to, create, a, UI, State before, we, dive, into, the, code, let's, look
at, exactly, what's, Happening, Here, we, have lists, of, news, resources, coming, from, our news, repository, and, we, have, lists, of, IDs coming, from, our, bookmarks, repository, our
view, model, combines, these, two, to, create a, list, of, savable, news, resources, each item, in, this, list, contains, the, news resource, itself, and, whether, it's, saved or, not the, code, for, these, models, is, pretty
simple, news, resource, has, some, fields, for the, news, article, like, its, ID, and, title and, savable, news, resource, is, just, a wrapper, around, news, resource, which, also includes, whether, that, news, resource, is
bookmarked, it's, used, by, our, UI, layer, to represent, the, combined, data, from, both the, news, and, bookmarks repositories, and, here's, the, code, for, our view, model, we, accept, the, data
repositories, in, our, Constructor, and create, a, combined, data, variable, to, store a, flow, of, savable, news, resources, this, is is, created, using, the, combine, function which, as, its, name, suggests, combines, the
data, streams, from, our, two repositories, whenever, the, data, changes in, either, stream, our, transformation function, is, called, with, the, latest, news resources, and, bookmarks, inside, it, we, map
each, news, resource, to, a, savable, news resource, checking, to, see, whether, it's bookmarked, let's, go, back, to, our, view model, diagram, for, a, second, once, the, data is, combined, our, view, model, needs, to
convert, this, to, a, UI, state, which, can, be one, of, two, possible, values, loading, or success, loading, is, used, when, data, is being, initially, loaded, usually, when, the news, resources, are, being, loaded, over, the
network, and, success, is, used, when, the data, has, been, loaded, successfully, it contains, the, list, of, savable, news resources, so, the, UI, can, display, them here's, the, code, which, does, that, we, use, a
sealed, interface, to, represent, the, two, UI States, loading, is, just, an, object, whereas success, is, a, class, which, holds, the savable, news resources, in, our, view, model, we, create, a
variable, to, expose, our, UI, State, as, a state, flow, this, this, is, a, flow, which, can have, an, initial, value, and, is, optimized for, sharing, state, to, convert, our combined, data, into, a, UI, State, we, simply
map, the, list, of, savable, news, resources into, the, success, UI state, to, convert, the, combined, data, flow into, a, state, flow, we, use, state, in, we specify, the, co-, routine, scope, which, the
flow, should, be, started, in, and, an, initial value, of loading, collecting, from, flows, can, be expensive, especially, if, they, access, the network, or, sensors, we, can, use, the started, parameter, to, indicate, that, we
only, want, the, flow, to, be, active, when there, is, at, least, one, collector, usually a, screen, this, avoids, wasting resources, when, the, last, collector unsubscribes, we, wait, 5, seconds, before
stopping, the, Upstream, flow, just, in, case the, collector, only, went, away, temporarily as, can, happen, during, a, screen, rotation this, avoids, the, potentially timeconsuming, operation, of, restarting the
flow, the, final, task, our, view, model should, perform, is, to, handle, requests from, the, UI, to, save, and, unsave, bookmarks we, do, this, by, creating, a, bookmark function, inside, it, we, call, the, relevant
method, on, the, bookmarks, repository, and execute, that, call, from, The, View, model scope, now, one, of, the, benefits, of, using, a view, model, is, that, it, survives configuration, changes, this, means, that
operations, initiated, using, the, view model, scope, will, continue, to, run, and, our UI, state, will, be preserved, okay, it's, time, to, display something, on, screen, for, this, we, create
you, guessed, it, a, 4u, screen, this, will read, the, UI, state, from, The, View, model and, render, it, using, UI, elements, we'll use, jetpack, compos, for, this, as, it's, the recommended, UI, framework, for, new
apps, let's, refresh, our, memory, on, what the, design, for, this, feature, looks, like we, can, see, that, the, news, articles, are displayed, in, a, column, and, the, design concept, for, each, article, is, known, as, a
card, so, let's, go, ahead, and, create, a draft, implementation, for, our UI, first, we, create, a, composable, function for, the, news, resource, card, it, takes, the news, resource, its, bookmark, State, and, a
Lambda, which, we, called, when, the, user Taps, on, the, bookmark, button, we, create, a column, which, holds, the, UI, elements, for the, title, content, and, bookmark, button when, the, bookmark, button, is, tapped, we
call, on, toggle bookmark, we, also, create, a, composable, to display, a, list, of, these, news, resource cards, called, news, feed, it, simply, creates a, column, and, iterates, through, the
elements, rendering, a, news, resource, card for, each one, now, you, can, preview, composes, in Android, Studio, using, the, app, preview annotation, here's, how, our, news, feed looks
currently, okay, it, isn't, going, to, win, any Design, Awards, and, we're, certainly, not matching, the, design, spec, yet, but, don't worry, we're, going, to, fix, this shortly, now, let's, create, the, for, you screen, this, accepts, the, current, UI, State
and, a, Lambda, to, call, when, the, user, Taps on, any, of, the, bookmark, buttons, when, the UI, state, is, loading, we, just, display, the text, loading, and, for, the, success, State we, get, the, news, resources, from, the, UI
State, and, pass, them, to, the, news, feed along, with, the, Lambda, to, be, called, when the, user, adds, or, removes, a, bookmark, so how, do, we, get, our, UI, St, State, well, we can, create, a, stateful, version, of, foru
screen, which, obtains, our, view, model, and once, we, have, it, we, can, use, collect, a state, with, life, cycle, to, collect, from the, stream, only, when, the, app, is, in, the foreground, to, avoid, wasting, resources
and, to, convert, the, stream, into, a composed, State, when, the, UI, State, changes it, causes, any, composable, functions, which is, Reddit, like, our, for, you, screen, to, be
recomposed, once, we, have, the, UI, State, we simply, Supply, it, to, our, state, list, for you, screen, along, with, a, reference, to, any events, which, the, screen, needs, to, call, in our, case, just, the, toggle, bookmark
function, so, why, don't, we, just, have, a single, stateful, for, you, screen, well, as we'll, see, later, stateless, functions, are easier, to, test, and, to
preview, in, a, compose, app, we, still, need an, activity, this, is, the, glue, between, the Android, framework, and, your, compose, code and, is, what, shows, your, UI, to, the, user, we try, to, keep, our, activity, as, simple, as
possible, just, calling, set, content, and then, our, UI, code Okay, so, we've, created, classes, for, the uui, and, data, layers, we, could, just, place all, these, classes, inside, the, app, module
but, we, know, that, our, app, is, going, to, do more, than, just, display, news, articles, by creating, modules, for, each, distinct, set of, responsibilities, we, can, make, our codebase, more, scalable, modules, can, also
enable, parallel, working, and, potentially reduce, build times, here's, the, modularization, strategy we, used, in, the, now, and, Android, app, at the, top, level, we, have, app, modules, which are, responsible, for, bringing, features
together, an, app, module, exists, for, every app, which, can, be, built, as, part, of, the project, the, mobile, app, is, the, most obvious, of, these, but, we, also, have, an, app module, for, displaying, the, visual, design system, and, could, have, more, app, modules
for, different, Target, platforms, such, as wear, or TV, app, modules, depend, on, feature, modules these, are, scoped, to, a, single, area, of user-facing, responsibility, such, as providing, the, content, for, the, for, you
screen, feature, modules, do, not, depend, on each, other, but, can, depend, on, core modules, these, are, common, Library, modules used, throughout, the, app, also, scoped, to, a single, area, of, responsibility, for
example, repositories, are, held, in, the data, module, and, networking, code, in, the network, module, let's, figure, out, where our, classes, should, go, our, main, activity goes, into, our, app, module, classes, which
are, specific, to, the, for, you, feature, are moved, into, the, for, you, feature, module data, classes, which, are, used, by, other modules, are, moved, into, the, core, model module, repository, trees, into, core, data
classes, associated, with, local, storage using, data, store, move, into, core, data store and, network, classes, move, into, core Network, now, a, common, problem, with modularization, is, that, you, end, up, with
lots, of, duplicate, dependencies, and configuration, blocks, inside, your, build files, we, solve, this, in, now, on, Android using, a, feature, called, convention plugins, the, idea, is, to, move, common
options, and, dependencies, into, a, plug-in and, then, include, that, plugin, in, all, the modules, which, require, those, options, this way, all, your, configuration, stays, in, one place, and, can, be, easily
updated, the, plugins, and, supporting, code is, contained, within, a, separate, build logic, module, which, is, built, before, any other, module, this, ensures, that, any configuration, changes, are, propagated, to
all, dependent, modules, before, they're built, another, common, problem, in, modular code, bases, is, keeping, track, of, Library versions, especially, when, they're scattered, through, multiple, gradal, files
version, cataloges, is, a, gradal, feature which, solves, this, a, version, catalog, is, a single, file, which, contains, a, list, of every, Library, used, in, the, app, and, its version, each, library, has, a, unique, ID
which, can, be, referenced, in, gradal configuration, files, whenever, we, need, to update, the, library, version, we, just update, it, in, the, version catalog, this, modularization, strategy helped, us, to, build, a, Loosely, coupled
graph, of, modules, for, now, an, Android enabling, us, to, work, in, parallel, and reduce, the, amount, of, time, deciding, where to, put, new, code, you, don't, have, to modularize, from, the, outset, but, if, you know, your, project, needs, to, scale, you, can
save, a, lot, of, time, by, introducing, a modularization, strategy early, so, at, this, point, we, know, what classes, to, create, and, which, modules, to save, them, in, what, we, don't, know, for, sure
is, whether, our, code, functions, as intended, tests, can, do, this, by, verifying the, behavior, of, individual, classes, and our, app, as, a, whole, they, allow, us, to, add new, features, or, refactor, our, code, base with, the, confidence, that, if, we, break
something, we'll, know, about, it, before, our product, is, shipped, to, users, in, fact, if you, have, a, clear, idea, of, the, classes, you need, to, create, it's, even, better, to, write the, tests, first, but, it's, up, to, you, to
decide, when, to, write, tests, just, as, long as, you, actually, write, them there's, a, lot, of, theory, behind, testing which, you, can, check, out, using, the, link below, I'm, just, going, to, show, you, how, we
can, write, a, unit, test, and, a, UI, test, to verify, the, behavior, for, our, feature, we should, add, test, wherever, there, is, logic and, one, of, the, places, there's, a, lot, of logic, is, in, our, view
model, as, we've, seen, already, it, combines data, from, two, streams, and, converts, it into, UI, State, let's, write, a, unit, test, to verify, this Behavior, the, first, thing, we, need, to, do
when, writing, a, test, is, isolate, the, test subject, from, its, dependencies, in, this case, the, repositories, instead, of, using the, real, repositories, which, are, going, to be, performing, long, running, operations like, pulling, data, from, the, Network, and
local, storage, we, should, instead, create test, dependencies, also, known, as, test doubles, this, allows, us, to, control, the inputs, to, our, test, subject, and, verify the, output, plus, our, tests, will, run, a, lot
faster, the, problem, is, our, view, model depends, on, concrete, classes, we, should rename, any, concrete, classes, and, have them, Implement, an, interface, which, the test, subject, can, then, depend, on
this, way, we, can, create, test, classes which, will, be, supplied, when, testing let's, Implement, our, view, model, test class, we, start, by, creating, a, rule, which sets, our, co-routine, dispatcher, to, a, test
dispatcher, this, ensures, that, any co-routines, are, executed, sequentially inside, our, test, and, is, essential, when testing flows, then, we, set, up, the, dependencies and, create, a, variable, to, hold, the
subject, under, test, the, view, model, and, we ensure, that, it's, recreated, with, our, test dependencies, before, each, test, is run, now, we, can, write, a, test, which, will verify, that, after, the, news, resources, and
bookmarks, are, loaded, the, view, model produces, the, correct, UI, State, inside, our test, we, start, collecting, from, The, View model, State, without, this, no, values, would
be, emitted, into, the, flow, we, tell, our test, news, repository, to, send, some, news resources, to, the, view, model, and, our, test bookmarks, repository, to, toggle, a bookmark, for, the, first, news
resource, now, we, get, our, UI, State, we, then check, that, it's, success, and, the, correct news, resource, has, been, booked, marked lastly, we, cancel, the, collection, job otherwise, the, test, will, run
indefinitely, since, this, is, a, locally, run unit, test, we, save, it, in, the, test, folder in, our, feature module, now, let's, create, a, test, for, our screen, in, a, UI
test, here, we, have, a, choice, we, can, either run, the, UI, test, directly, on, our, host using, a, testing, framework, like, Robo electric, this, is, known, as, a, local, test and, is, saved, in, the, same, location, as, our previous, test, or, we, can, run, it, on, a
device, or, emulator, running, Android, known as, is, an, instrumented, tests, local, tests generally, run, faster, but, offer, less Fidelity, than, instrumented, tests, let's create, an, instrumented, test, for, our
screen, first, we, add, a, junit, rule, which allows, us, to, control, composes, now, we create, a, test, which, will, verify, that, the news, articles, are, displayed, the, set content, method, allows, us, to, supply, a
composable, and, have, it, rendered, on screen, exactly, the, same, way, as, it, works in, our, main activity, inside, here, we, create, our, test subject, the, for, you, screen, and, pass, in the, success, state, and, some, sample, news
resources, here, we, can, see, the, benefit, of having, a, stateless, screen, composable, it makes, it, really, easy, to, test, after setting, up, our, screen, we, can, use, the, on node, with, text, matcher, to, find, a, node, in
the, composed, graph, with, the, title, of, our news, resource, and, verify, that, it, exists since, this, is, an, instrumented, test, we save, it, in, the, Android, test folder, now, that, we, know, that, everything
is, working, as, intended, and, we, have, a solid, infrastructure, in, place, let's, make our, app, look better, the, material, design, system provides, a, framework, and, set, of guidelines, for, creating, compelling
consistent, and, intuitive, user, interfaces it, includes, a, set, of, customizable, UI components, for, Jetpack, comp, POS, material 3, is, the, latest, version, of, material design, and, our, design, team, has, given, us
a, beautiful, design, spec, based, on, this including, colors, and, typography, we, can use, these, to, define, a, theme, for, our, app any, material, design, components, we, use will, be, styled, according, to, our, theme
let's, take, a, look, at, this, in action, we, take, the, colors, from, our design, design, spec, and, Define, them, in code, then, we, Define, a, color, scheme, for light, and, dark, modes, material, 3, gives
each, color, a, semantic, name, which describes, the, context, in, which, that color, should, be, used, for, example, the, on primary, color, will, be, used, when, on, top of, the, primary, color, we, can, also, create
a, typography, class, to, specify, our, text styles, again, material, 3, gives, us, a, set of, names, to, clearly, define, the, role, for each, textile, with, our, colors, and, tex Styles, defined, we, can, now, create, a, theme
composable, which, wraps, all, the, content in, our, app, first, we, decide, which, color scheme, to, use, based, on, whether, the device, is, in, dark, mode, then, create, a material, theme, based, on, our, color, scheme and
typography, to, use, the, theme, we, simply wrap, our, content, in, our, theme composable, if, we, preview, our, news resource, card, we, can, see, that, the, button is, now, using, the, colors, we, defined, in our
theme, we, can, specify, our, text, Styles whenever, we, render, text, and, we, can, take advantage, of, other, material, design components, like, the, card, which, adds rounded, Corners, by, default, and, derives colors, from, our
theme, one, of, the, great, things, about material, design, components, is, that they're, designed, to, be, customized, in, now in, Android, we, customized, several, of, the stock, components, and, created, a, design catalog, app, which, ships, as, part, of, the
project, so, everyone, on, the, team, can easily, see, the, UI, components, they, have to, work, with, a, good, example, is, the toggle, button, class, it, wraps, the material, icon, button, to, provide, extra
features, like, the, circular, background you, see, when, the, button, is, toggled, on bookmark, button, then, wraps, toggle, button to, provide, the, book, Mark, icons, for, the on, and, off
States, now, if, we, swap, our, normal, button for, the, bookmark, button, add, some padding, and, an, image, using, an, image loading, Library, like, coil, will, start, to
get, much, closer, to, our, design spec, okay, we, made, it, we, learned, how, to implement, a, scalable, architecture, and modularize, our, code, base, as, well, as, our tests, to, verify, our, apps, Behavior, lastly
we, learned, how, to, use, material, design with, jetpack, compos, to, create, beautiful intuitive, apps, but, wait, this, talk, only covers, the, very, basics, of, these, topics and, there's, some, important, ones, which, I haven't, covered, which, you, should
definitely, check, out, including navigation, dependency, injection, using Hilt, performance, testing, and, designing for, all, screen, sizes, the, now, and, Android app, includes, all, of, these, features, so, be
sure, to, check, it, out, thanks, for, watching [Music]
Loading video analysis...