Part 1: A Metaprogramming Feast
Part 2: A Farewell To Stubs
Part 3: The Old Man and the IDE
Metaprogramming is a programming technique in which computer programs have the ability to treat other programs as their data
@Inject
DI
Factory
etc.
@Before
fun setUp() {
// based on https://github.com/android/compose-samples/tree/main/Jetcaster
viewModel = HomeViewModel(
podcastsRepository = PodcastsRepository(
podcastsFetcher = PodcastsFetcher(
okHttpClient = mockClient,
syndFeedInput = SyndFeedInput(true, Locale.ROOT),
testCoroutineDispatcher,
),
podcastStore = PodcastStore(
podcastDao = fakeDatabase.podcastDao,
podcastFollowedEntryDao = fakeDatabase.podcastFollowedEntryDao,
transactionRunner = fakeDatabase.transactionRunner,
),
episodeStore = EpisodeStore(episodesDao = fakeDatabase.episodesDao),
categoryStore = CategoryStore(
categoriesDao = fakeDatabase.categoriesDao,
categoryEntryDao = fakeDatabase.podcastCategoryEntryDao,
episodesDao = fakeDatabase.episodesDao,
podcastsDao = fakeDatabase.podcastsDao,
),
transactionRunner = fakeDatabase.transactionRunner,
mainDispatcher = testCoroutineDispatcher
)
)
}
Feel the heavy lifting every time you manually instantiate a class in a test 🏋️♂️
🥵
class PodcastsRepository @Inject constructor(
private val podcastsFetcher: PodcastsFetcher,
private val podcastStore: PodcastStore,
private val episodeStore: EpisodeStore,
private val categoryStore: CategoryStore,
private val transactionRunner: TransactionRunner,
mainDispatcher: CoroutineDispatcher
)
Handle dependency injection as a cross-cutting concern using annotations
@HiltViewModel
class HomeViewModel @Inject constructor(
private val podcastsRepository: PodcastsRepository,
private val podcastStore: PodcastStore,
) : ViewModel()
JSON parsing
ORM
reflection
code gen
⚠️ Need to fail fast
🕵️ Inspection is easier for code
⚡ Build fast like reflection
⚡ Fail fast code gen
🤔
🤔
Old sample using kapt version of Room
@androidx.room.Entity(tableName = "garden_plantings",
indices = {@androidx.room.Index(value = {"plant_id"})})
public final class GardenPlanting {
public final long getGardenPlantingId() {
return 0L;
}
public final void setGardenPlantingId(long p0) {
}
@org.jetbrains.annotations.NotNull()
@androidx.room.ColumnInfo(name = "plant_id")
private final java.lang.String plantId = null;
}
@Entity(
tableName = "garden_plantings",
indices = [Index("plant_id")]
)
data class GardenPlanting(
@ColumnInfo(name = "plant_id") val plantId: String,
) {
@PrimaryKey(autoGenerate = true)
@ColumnInfo(name = "id")
var gardenPlantingId: Long = 0
}
stubbed out
/* There are 4 steps to the compilation process: 1. Generate stubs (using kotlinc with kapt plugin which does no further compilation) 2. Run apt (using kotlinc with kapt plugin which does no further compilation) 3. Run kotlinc with the normal Kotlin sources and Kotlin sources generated in step 2 4. Run javac with Java sources and the compiled Kotlin classes
generate stubs
Run apt
kotlinc
javac
stubs
kotlin sources
compiled classes
kotlinc with kapt
generate stubs
Run apt
kotlinc
javac
stubs
kotlin sources
compiled classes
kaptGenerateStubsDebugKotlin
kaptDebugKotlin
compileDebugKotlin
compileDebugJavaWithJavac
🐢 extensive symbol resolution 🐢
KSP
kotlinc
javac
kotlin sources
compiled classes
kspDebugKotlin
compileDebugKotlin
compileDebugJavaWithJavac
Gradle tasks for KSP
judicious symbol resolution 🧠
kotlin sources
Symbol resolution? 🤔
@d_rawers
Photo | Link | Author link | Author name |
---|---|---|---|
A Moveable Feast (cover) | https://en.wikipedia.org/wiki/File:MoveableFeast.jpg | ||
Two Roads | https://unsplash.com/photos/u0vgcIOQG08 | https://unsplash.com/@madebyjens | Jens Lelie |
Bullet | https://unsplash.com/photos/5HBpbWsdpck | https://unsplash.com/@jhphotos04 | Joseph Hersh |
A Farewell To Arms (cover) | https://www.flickr.com/photos/digitalcollectionsum/15124278710 | ||
The Old Man And The Sea (cover) | https://www.abebooks.com/servlet/BookDetailsPL?bi=30174085940 |