Nessa apresentação demonstro como aplicar alguns dos Architecture Components disponíveis no Jetpack em uma arquitetura que segue o padrão Clean com MVVM.
The magic of jQuery's CSS-based selection makes it easy to think about our code in terms of the DOM, and sometimes that approach is exactly right. Other times, though, what we're trying to accomplish is only tangentially related to our nodes, and opting for an approach where we think in terms of functionality -- not how that functionality is manifested on our page -- can pay big dividends in terms of flexibility. In this talk, we'll look at a small sample application where the DOM takes a back seat to functionality-focused modules, and see how the approach can change the way we write and organize our code.
Backbone.js — Introduction to client-side JavaScript MVCpootsbook
Using Backbone.js to move state to the client-side and the benefits of using a JavaScript MVC framework.
Delivered at SuperMondays, Newcastle upon Tyne, on 26th September 2011.
Kotlin is a statically typed programming language for the JVM, Android and the browser.
More and more in the Android community start using Kotlin, we’ll see why and how you can do it too.
The OpenStack Horizon project provides a web-based User Interface to OpenStack services. It is constructed in two parts: (1) a core set of libraries for implementing a Dashboard; (2) the dashboard implementation that uses the core set of libraries.
Horizon uses python django — server side technology
Django is a wonderful framework, but a little dated. Pre-dates the rise in client-side and single page applications.
Javascript is used for enhancing the user experience
In the time since Horizon was first architected, there have been major advances in the design, and best practices for web applications. In particular, the use of more sophisticated and robust client-side javascript frameworks like BackboneJS, AngularJS, MeteorJS, have come to the fore.
These applications provide a much more responsive user experience, much cleaner separation between the client and server, enable configuration driven interfaces, and facilitate more modular testing.
This in turn, results in shorter development cycles, more testable software, and above all, a better user experience.
In this presentation, we share some of our recent work in re-architecting parts of Horizon to take advantage of these new technologies. We discuss some of the technologies we use, our application architecture, and some of the pitfalls to avoid.
The magic of jQuery's CSS-based selection makes it easy to think about our code in terms of the DOM, and sometimes that approach is exactly right. Other times, though, what we're trying to accomplish is only tangentially related to our nodes, and opting for an approach where we think in terms of functionality -- not how that functionality is manifested on our page -- can pay big dividends in terms of flexibility. In this talk, we'll look at a small sample application where the DOM takes a back seat to functionality-focused modules, and see how the approach can change the way we write and organize our code.
Backbone.js — Introduction to client-side JavaScript MVCpootsbook
Using Backbone.js to move state to the client-side and the benefits of using a JavaScript MVC framework.
Delivered at SuperMondays, Newcastle upon Tyne, on 26th September 2011.
Kotlin is a statically typed programming language for the JVM, Android and the browser.
More and more in the Android community start using Kotlin, we’ll see why and how you can do it too.
The OpenStack Horizon project provides a web-based User Interface to OpenStack services. It is constructed in two parts: (1) a core set of libraries for implementing a Dashboard; (2) the dashboard implementation that uses the core set of libraries.
Horizon uses python django — server side technology
Django is a wonderful framework, but a little dated. Pre-dates the rise in client-side and single page applications.
Javascript is used for enhancing the user experience
In the time since Horizon was first architected, there have been major advances in the design, and best practices for web applications. In particular, the use of more sophisticated and robust client-side javascript frameworks like BackboneJS, AngularJS, MeteorJS, have come to the fore.
These applications provide a much more responsive user experience, much cleaner separation between the client and server, enable configuration driven interfaces, and facilitate more modular testing.
This in turn, results in shorter development cycles, more testable software, and above all, a better user experience.
In this presentation, we share some of our recent work in re-architecting parts of Horizon to take advantage of these new technologies. We discuss some of the technologies we use, our application architecture, and some of the pitfalls to avoid.
Slides da apresentação no Meetup realizado no dia 13/04/2019 no CESAR.school, onde foi apresentada uma introdução ao desenvolvimento Android com Kotlin
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Domenic Denicola
This talk takes a deep dive into asynchronous programming patterns and practices, with an emphasis on the promise pattern.
We go through the basics of the event loop, highlighting the drawbacks of asynchronous programming in a naive callback style. Fortunately, we can use the magic of promises to escape from callback hell with a powerful and unified interface for async APIs. Finally, we take a quick look at the possibilities for using coroutines both in current and future (ECMAScript Harmony) JavaScript.
JavaScript Module Patterns: How to build and use JavaScript modules. We cover the Basic Module Pattern, Revealing Module Pattern, CommonJS, AMD, CommonJS, UMD and ES6 modules.
When you move beyond adding simple enhancements to your website with jQuery and start building full-blown client-side applications, how do you organize your code? At this month's Triangle JS Meetup, we'll take a look at patterns for application development using jQuery that promote the principles of tight encapsulation and loose coupling, including classes, the publish/subscribe paradigm, and dependency management and build systems.
Nessa apresentação demonstro como arquitetar uma aplicação Android utilizando MVVM+Clean Architecture no Android utilizando as bibliotecas do Jetpack (View Model, Room, LiveData, ...)
The Android world is full of great people that built great stuff and published it for saving other a lot of time. In this talk, we’ll
go over a list of must-have libraries, tools, and resources every Android developer should know to make their Android development much
easier and help them build better apps in less time.
Simplified Android Development with Simple-StackGabor Varadi
This talk describes multiple Activities, Jetpack Navigation, and Simple-Stack in a single-activity android application context. How to develop screens and navigation using Simple-Stack.
The jQuery community has provided thousands of useful plugins which can be stitched together to create exceptional websites. However, organizing those plugins, tracking their upstream changes and managing dependencies can become a nightmare with a system to help you manage. JavascriptMVC, and specifically its new version 3 release, provides a framework for organizing outside code, integrating it into your workflow and compressing down to a single output javascript file. This talk will focus on taking external plugins such as jQuery Tools, jQuery UI and other popular plugins and creating a workflow for building larger applications from these components. I will show how to use the JavascriptMVC “getter” and “pluginify” scripts to pull external resources. With JavascriptMVC 3, css and javascript can be packaged together creating truly convenient widgets. I will also demonstrate how often-used pieces of functionality can be abstracted into plugins and shared with the general community via Github.
Nessa apresentação demonstro como arquitetar uma aplicação Android utilizando as bibliotecas do Jetpack. O exemplo apresentado utiliza MVVM+Clean:
- Na camada de dados local, Room com Coroutines e Flow;
- View Model, Live Data e Data Binding na camada de apresentação;
- Fragments com a Navigation API na camada de UI.
O app também conta com uma implementação de banco de dados remoto utilizando Firebase.
Getting Started with Combine And SwiftUIScott Gardner
In this 3 1/2-hour live hands-on workshop, you will learn the basics of SwiftUI Combine, and then create a multipeer chat app using SwiftUI and Combine.
Slides da apresentação no Meetup realizado no dia 13/04/2019 no CESAR.school, onde foi apresentada uma introdução ao desenvolvimento Android com Kotlin
Callbacks, Promises, and Coroutines (oh my!): Asynchronous Programming Patter...Domenic Denicola
This talk takes a deep dive into asynchronous programming patterns and practices, with an emphasis on the promise pattern.
We go through the basics of the event loop, highlighting the drawbacks of asynchronous programming in a naive callback style. Fortunately, we can use the magic of promises to escape from callback hell with a powerful and unified interface for async APIs. Finally, we take a quick look at the possibilities for using coroutines both in current and future (ECMAScript Harmony) JavaScript.
JavaScript Module Patterns: How to build and use JavaScript modules. We cover the Basic Module Pattern, Revealing Module Pattern, CommonJS, AMD, CommonJS, UMD and ES6 modules.
When you move beyond adding simple enhancements to your website with jQuery and start building full-blown client-side applications, how do you organize your code? At this month's Triangle JS Meetup, we'll take a look at patterns for application development using jQuery that promote the principles of tight encapsulation and loose coupling, including classes, the publish/subscribe paradigm, and dependency management and build systems.
Nessa apresentação demonstro como arquitetar uma aplicação Android utilizando MVVM+Clean Architecture no Android utilizando as bibliotecas do Jetpack (View Model, Room, LiveData, ...)
The Android world is full of great people that built great stuff and published it for saving other a lot of time. In this talk, we’ll
go over a list of must-have libraries, tools, and resources every Android developer should know to make their Android development much
easier and help them build better apps in less time.
Simplified Android Development with Simple-StackGabor Varadi
This talk describes multiple Activities, Jetpack Navigation, and Simple-Stack in a single-activity android application context. How to develop screens and navigation using Simple-Stack.
The jQuery community has provided thousands of useful plugins which can be stitched together to create exceptional websites. However, organizing those plugins, tracking their upstream changes and managing dependencies can become a nightmare with a system to help you manage. JavascriptMVC, and specifically its new version 3 release, provides a framework for organizing outside code, integrating it into your workflow and compressing down to a single output javascript file. This talk will focus on taking external plugins such as jQuery Tools, jQuery UI and other popular plugins and creating a workflow for building larger applications from these components. I will show how to use the JavascriptMVC “getter” and “pluginify” scripts to pull external resources. With JavascriptMVC 3, css and javascript can be packaged together creating truly convenient widgets. I will also demonstrate how often-used pieces of functionality can be abstracted into plugins and shared with the general community via Github.
Nessa apresentação demonstro como arquitetar uma aplicação Android utilizando as bibliotecas do Jetpack. O exemplo apresentado utiliza MVVM+Clean:
- Na camada de dados local, Room com Coroutines e Flow;
- View Model, Live Data e Data Binding na camada de apresentação;
- Fragments com a Navigation API na camada de UI.
O app também conta com uma implementação de banco de dados remoto utilizando Firebase.
Getting Started with Combine And SwiftUIScott Gardner
In this 3 1/2-hour live hands-on workshop, you will learn the basics of SwiftUI Combine, and then create a multipeer chat app using SwiftUI and Combine.
Is your web app drowning in a sea of JavaScript? Has your client-side codebase grown from "a snippet here and there" to "more JavaScript than HTML"? Do you find yourself writing one-off snippets instead of generalized components? You're not the only one. Learn about a handful of strategies you can use to keep your JavaScript codebase lean, modular, and flexible. We'll cover all the major pain points — MVC, templates, persisting state, namespacing, graceful error handling, client/server communication, and separation of concerns. And we'll cover how to do all this incrementally so that you don't have to redo everything from scratch.
These are the slides of my talk at iOSCon 2017: https://skillsmatter.com/skillscasts/9549-architecting-alive-apps
Our apps are ever more alive. They interact with the rest of the world talking to backends and receiving notifications from them. They get their input from us and from other sensors. They are even aware of the location of the device they run in, or its position. But, in our IoT world, they may also detect presence in a room, get the temperature of it, or change the color of its lights.
Sadly enough, many of the apps available today with those capabilities have some architectural limitations:
Many of them are written in a way that is really dependent on a specific hardware.
Some restrict their use cases to whatever is provided by the hardware devices.
And almost all of them expect having a connection with the real device as the only way to test if they work properly.
However, we can also use an advanced architecture, like the Clean Architecture, to create a beautiful, scalable, testable, and robust application. Join Jorge and he will share with you how you can do it!
This is a "Code or it didn't happen" (TM) talk.
Javascript and first-class citizenry: require.js & node.js
Javascript on web pages is ubiquitous and its problems are legendary. Javascript, seen as a second-class code citizen, is usually hacked together even by seasoned developers. New libraries (jQuery, prototype, backbone, knockout, underscore) and runtime tools (firebug, jasmine) look like they solve many problems - and they do. But they still leave poorly written code as just that. One key problem is that all javascript code lives globally and this results in poorly managed, tested and delivered code.
In this session, I will illustrate that we can treat javascript as a first-class citizen using with require.js and node.js: it can be modular, encapsulated and easily unit tested and added to continuous integration cycle. The dependencies between javascript modules can also be managed and packaged just like in C# and Java. In the end, we can resolve many javascript difficulties at compile time rather than waiting until runtime.
IndexedDB is an exciting option for offline storage in the HTML5 sites and applications that you build. The API's not ready yet, but it's important to play now, and feed your experience into the standards process.
Would you like to make your Android UI code cleaner and more reactive? Android data binding can help. In this talk you’ll learn everything you need to know about data binding, including why it’s so powerful and how to use it effectively. If you haven’t tried data binding in the past, that’s okay! We’ll start with the basics, assuming no prior knowledge and slowly move into more advanced topics, such as 2-way binding, binding adapters, converters, best practices and common pitfalls to avoid.
Similar to Arquitetando seu aplicativo Android com Jetpack (20)
Palestra apresentada no Google I/O Extended 2023 em Salvador-BA no dia 05/08/2023 onde falei sobre as principais novidades do Android para 2023 que foram mostradas no Google I/O 2023.
Apresentação realizada no Google IO Extended Brasil 2021.
Nessa palestra foram apresentadas as principais novidades nas bibliotecas Jetpack divulgadas no Google IO de 2021
Jetpack Compose is the new Android UI framework that allows you to create rich user interfaces in a declarative way using Kotlin language. In this presentation, it will be demonstrated how to take the first steps with Compose, learn its main concepts and understand how to be prepared for this change of paradigm on the front-end development of native Android applications.
Nessa palestra, inicialmente é feita uma introdução à plataforma Android. Em seguida, são comentados os principais requisitos técnicos e não técnicos para se tornar um desenvolvedor Android. Finalmente, é analisado o mercado para esse tipo de profissional, seus benefícios e desafios.
Palestra apresentada na Faculdade de Juazeiro do Norte - FJN (14/02/2020) por Nelson Glauber de Vasconcelos Leal
Aplicações Assíncronas no Android com Coroutines e JetpackNelson Glauber Leal
Para usufruir dos múltiplos núcleos existentes nos processadores dos smartphones atuais, podemos realizar chamadas assíncronas de modo a paralelizar o fluxo de execução da aplicação. Normalmente isso é feito por meio de threads e callbacks que acabam por adicionar uma complexidade ao código que pode comprometer sua leitura e manutenção. Nessa apresentação, veremos como utilizar a API de Coroutines do Kotlin em conjunto com diversas bibliotecas do Jetpack do Android de modo a implementar programação assíncrona forma simples e eficiente.
In this talk I presented three important topics in Kotlin Standard Library: Scope Functions (let, apply, also, run and with); Annotations (Deprecated, Experimental, Jvm*, DslMarker); and Delegates (lazy, vetoable, observable)
Aplicações assíncronas no Android com Coroutines & JetpackNelson Glauber Leal
Para usufruir dos múltiplos núcleos existentes nos processadores dos smartphones atuais, podemos realizar chamadas assíncronas de modo a paralelizar o fluxo de execução da aplicação. Normalmente isso é feito por meio de threads e callbacks que acabam por adicionar uma complexidade ao código que pode comprometer sua leitura e manutenção. Nessa apresentação, veremos como utilizar a API de Coroutines do Kotlin em conjunto com diversas bibliotecas do Jetpack do Android de modo a implementar programação assíncrona forma simples e eficiente.
Palestra apresentada no The Developers Conference São Paulo 2018 na Trilha Android.
A ideia dessa apresentação é dar uma visão geral sobre os principais tópicos do desenvolvimento Android utilizados atualmente, tais como: Kotlin, MVP, MVVM, Architecture Components, ConstraintLayout, RXJava, Firebase e testes.
Palestra realizada no DevFestXP em Recife (09/12/2017) apresentando as principais técnicas, APIs e ferramentas mais atuais utilizadas no desenvolvimento de aplicações Android
Slides da minha palestra sobre Constraint Layout apresentada no Android Dev Conference 2017.
Código-fonte disponível em:
https://github.com/nglauber/ConstraintLayoutAndroidDevConf2017
São Paulo, 25 de Agosto de 2017.
Palestra sobre persistência de dados no SQLite com Room API apresentada no TDC São Paulo 2017 (19/07/2017). O Room é um dos Architectural Components apresentados pelo Google no Google I/O 2017.
Palestra apresentada no evento de comemoração dos 4 anos do meetup de Android do GDG São Paulo. Oxigênio aceleradora no dia 10/Jun/2017
O código-fonte dos exemplos está disponível em:
https://github.com/nglauber/playground/tree/master/android/AnimationDemo
Palestra sobre ConstraintLayout apresentada no meetup de Android do GDG Rio de Janeiro (25/05/2016).
Assista a apresentação em: https://www.youtube.com/watch?v=GcOpTVdtjRU
2. Porque pensar na
arquitetura?
‣ Frameworks raramente forçam o desenvolvedor a seguir
princípios.
‣ É fácil um desenvolvedor iniciante sem o devido
acompanhamento criar um app ruim.
‣ Tecnologia e frameworks ocultam o propósito do
aplicativo.
‣ “Sua arquitetura deve gritar o propósito do aplicativo”. A
lógica de negócio deve ser claramente separada e
independente de framework.
3. Arquitetura
‣ Regra: Não há regras. Mas existem princípios que devem
ser respeitados. Lembra do S.O.L.I.D.?
‣ Promove a organização e o desacoplamento do código.
‣ Devem facilitar a manutenção e adição de novas
funcionalidades.
‣ Devem ser testáveis.
‣ Deixam o código mais complexo? Sim! Mas vale à pena. 😎
21. Room
‣ ORM para Android sobre o SQLite.
‣ Suporta atualização automática da UI
com LiveData ou RXJava
Local
22.
23. @Entity
@TypeConverters(MediaTypeConverter::class)
data class Book(
@PrimaryKey
var id: String,
var title: String = "",
var author: String = "",
var coverUrl: String = "",
var pages: Int = 0,
var year: Int = 0,
@Embedded(prefix = "publisher_")
var publisher: Publisher,
var available: Boolean = false,
var mediaType: MediaType = MediaType.PAPER,
var rating: Float = 0f
)
24. @Dao
interface BookDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun save(book: Book): Completable
@Delete
fun delete(vararg book: Book): Completable
@Query("SELECT * FROM Book WHERE title LIKE :title ORDER BY title")
fun bookByTitle(title: String = "%"): Flowable<List<Book>>
@Query("SELECT * FROM Book WHERE id = :id")
fun bookById(id: String): Flowable<Book>
}
25. @Database(entities = [Book::class], version = 1, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun bookDao(): BookDao
companion object {
private var instance: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
if (instance == null) {
instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"booksDb")
.build()
}
return instance as AppDatabase
}
}
}
26. class RoomRepository(db: AppDatabase,
private val fileHelper: FileHelper) : BooksRepository {
private val bookDao = db.bookDao()
override fun saveBook(book: Book): Completable {
if (book.id.isBlank()) {
book.id = UUID.randomUUID().toString()
}
return bookDao.save(BookConverter.fromData(book))
}
override fun loadBooks(): Flowable<List<Book>> {
return bookDao.bookByTitle()
.map { books ->
books.map { book ->
BookConverter.toData(book)
}
}
}
...
32. Presentation
Data Binding
• Facilita a ligação entre o
Presenter ou View Model e a
View
• Estende os arquivos de layout
com micro-expressões
• Muito útil em telas de input de
dados
35. class BookFormFragment : BaseFragment() {
private lateinit var binding: FragmentBookFormBinding
override fun onCreateView ... {
binding = DataBindingUtil.inflate(
inflater,
R.layout.fragment_book_form,
container,
false
)
return binding.root
}
override fun onViewCreated ... {
binding.book = viewModel.book
}
...
36. @Parcelize
class Book : BaseObservable(), Parcelable {
@Bindable
var id: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.id)
}
@Bindable
var title: String = ""
set(value) {
field = value
notifyPropertyChanged(BR.title)
}
// demais atributos
}
38. LiveData
• LiveData armazena dados observáveis
(Observable) e notifica os observadores
(Observer) quando esses dados mudam
para que a UI seja atualizada.
• O LiveData é lifecycle-aware. Ele só
notificará a UI se a Activity/Fragment
estiver no estado STARTED ou RESUMED.
Presentation
39. class BookDetailsViewModel(private val useCase: ViewBookDetailsUseCase) : ViewModel() {
private val state: MutableLiveData<ViewState<BookBinding>> = MutableLiveData()
fun getState(): LiveData<ViewState<BookBinding>> = state
fun loadBook(id: String) {
if (id != state.value?.data?.id) {
state.postValue(ViewState(ViewState.Status.LOADING))
useCase.execute(id,
{ book ->
val bookBinding = BookConverter.fromData(book)
state.postValue(ViewState(ViewState.Status.SUCCESS, bookBinding))
},
{ e ->
state.postValue(ViewState(ViewState.Status.ERROR, error = e))
}
)
}
}
override fun onCleared() {
super.onCleared()
useCase.dispose()
}
}
40. class BookDetailsFragment : BaseFragment() {
...
private fun init() {
viewModel.getState().observe(this, Observer { viewState ->
when (viewState.status) {
ViewState.Status.SUCCESS -> binding.book = viewState.data
ViewState.Status.LOADING -> { /* show progress*/ }
ViewState.Status.ERROR -> { /* show error */}
}
})
val book = arguments?.getParcelable<Book>("book")
book?.let {
viewModel.loadBook(book.id)
}
}
}
41. Presentation
open class LiveEvent<out T>(private val content: T) {
var hasBeenConsumed = false
private set
fun consumeEvent(): T? {
return if (hasBeenConsumed) {
null
} else {
hasBeenConsumed = true
content
}
}
fun peekContent(): T = content
}
42. class BookFormViewModel(private val useCase: SaveBookUseCase) : ViewModel() {
private val state: MutableLiveData<LiveEvent<ViewState<Unit>>> = MutableLiveData()
fun getState(): LiveData<LiveEvent<ViewState<Unit>>> = state
fun saveBook(book: BookBinding) {
state.postValue(LiveEvent(ViewState(ViewState.Status.LOADING)))
useCase.execute(BookConverter.toData(book),
{
state.postValue(LiveEvent(ViewState(ViewState.Status.SUCCESS)))
},
{ e ->
state.postValue(LiveEvent(ViewState(ViewState.Status.ERROR, error = e)))
}
)
}
44. Lifecycle
‣ Lifecycle é um objeto que define um ciclo de vida
‣ LifecycleOwner é uma interface para objetos com um
ciclo de vida
‣ Activity e Fragment implementam LifecycleOwner
e têm um Lifecycle.
‣ LifecycleObserver é uma interface para observar um
LifecycleOwner.
45. class BookListViewModel(
private val loadBooksUseCase: ListBooksUseCase,...
) : ViewModel(), LifecycleObserver {
...
@OnLifecycleEvent(Lifecycle.Event.ON_CREATE)
fun loadBooks() {
if (state.value == null) {
state.postValue(ViewState(ViewState.Status.LOADING))
loadBooksUseCase.execute(null,
{ books ->
val booksBinding = books.map { book ->
BookConverter.fromData(book)
}
state.postValue(
ViewState(ViewState.Status.SUCCESS, booksBinding)
)
},
{ e ->
state.postValue(
ViewState(ViewState.Status.ERROR, error = e)
)
}
)
}
}
46. class BookListFragment : BaseFragment() {
private val viewModel: BookListViewModel
private fun init() {
...
lifecycle.addObserver(viewModel)
}
...
48. UI (app)
Navigation API
• Serve para implementar o conceito de
“Single Activity” com múltiplos
Fragments/Views.
• Centraliza a lógica de navegação da
aplicação.
• Configuração direta com componentes de
UI (ActionBar, Menu, BottomNav, …)
• Simplifica a passagem de parâmetros.
56. class MyWork(ctx: Context, params: WorkerParameters):
Worker(ctx, params) {
override fun doWork(): Result {
val firstName = inputData.getString(PARAM_FIRST_NAME)
outputData = Data.Builder()
.putString(PARAM_NAME, "$firstName Glauber")
.putInt(PARAM_AGE, 35)
.putLong(PARAM_TIME, System.currentTimeMillis())
.build()
return Result.SUCCESS
}
companion object {
const val PARAM_FIRST_NAME = "first_name"
const val PARAM_NAME = "name"
const val PARAM_AGE = "age"
const val PARAM_TIME = "time"
}
}
57. val input = Data.Builder()
.putString(MyWork.PARAM_FIRST_NAME, "Nelson")
.build()
// Uma vez
val request = OneTimeWorkRequest.Builder(MyWork::class.java)
.setInputData(input)
.build()
// ou Periódico
val request = PeriodicWorkRequest.Builder(
MyWork::class.java, 5, TimeUnit.MINUTES)
.setInputData(input)
.build()
observeAndEnqueue(request)
72. • Você não precisa usar todos esses
recursos no mesmo app…
• Na verdade, você não precisa usar
nenhum!
• Mais importante do que saber quando
USAR é saber quando NÃO USAR 😉
• Mas é essencial conhecer tópicos,
saber seus prós e contras e utilizá-los
adequadamente 💡