Skip to content

Refactor to support JVM #13

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 17 commits into from
Jun 30, 2021
Merged

Refactor to support JVM #13

merged 17 commits into from
Jun 30, 2021

Conversation

prayansh
Copy link
Contributor

@prayansh prayansh commented Jun 24, 2021

Kind of a big refactor, so will try to capture as much context as possible.
We have refactored our analytics-kotlin module into 2 seperate modules in order to support JVM as a first-class source. The 2 components

  • core: main analytics module
    • Analytics functions
    • Platform / Plugin architecture
    • Plugins
    • Utility Functions
  • android: android analytics module which defines android-specific functionality, built on top of core
    • Analytics constructor
    • JSON functions
    • Storage
    • Plugins

This refactor will allow users to import the analytics-kotlin based on the app type.
If using a JVM kotlin app you would do

dependencies {
    implementation 'com.github.segmentio.kotlin-analytics:core'
}

and for android kotlin app you would do

dependencies {
    implementation 'com.github.segmentio.kotlin-analytics:android'
}

Closes #11

import android.content.SharedPreferences
import com.segment.analytics.kotlin.core.utilities.KVS

class AndroidKVS(val sharedPreferences: SharedPreferences): KVS {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No description provided.

import com.segment.analytics.kotlin.core.utilities.KVS

class AndroidKVS(val sharedPreferences: SharedPreferences): KVS {
override fun getInt(key: String, defaultVal: Int): Int =
Copy link
Contributor

@migs647 migs647 Jun 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider a default parameter value for defaultVal or add an additional method if they don't want to pass a defaultVal?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed the rest of them were defaulted to 0

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is an internal api, only being used in 1 place currently. im not sure if having default values will give us any additional benefits

@@ -22,7 +22,8 @@ import java.util.*
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
class EventsFileTest {
private val epochTimestamp = Date(0).toInstant().toString()
private val sharedPreferences = MemorySharedPreferences()
private val _sharedPreferences = MemorySharedPreferences()
private val kvStore = AndroidKVS(_sharedPreferences)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I noticed you used _sharedPreferences for shadow var. We often do this to signify to "not touch" on the obj-c side. Do we want to apply underscore to kvStore as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think this was a refactoring issue. normally ur suggestion would apply, but this is a test file so im not sure if the concept of shadow var / "do not touch" applies here

import sovran.kotlin.Store
import java.io.File

fun mockAnalytics(): Analytics {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

? It may be beneficial to add here for when we have new eng coming and knowing if / who they should use this for testing.

@@ -19,14 +20,14 @@ import java.util.concurrent.atomic.AtomicInteger
class SegmentDestination(
Copy link
Contributor

@migs647 migs647 Jun 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

may be good to add here since it's such an integral part of our library (not related to PR)

@@ -108,6 +109,7 @@ class SegmentDestination(
}

override fun flush() {
println("flush")
Copy link
Contributor

@migs647 migs647 Jun 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove println or alternate for analytics?.log()?

import kotlinx.serialization.json.JsonObject
import sovran.kotlin.Store

interface Storage {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No description provided.

}
}

interface StorageProvider {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No description provided.


// Platform abstraction for managing plugins' execution (of a specific type)
// All operations are thread safe via the `synchronized` function
internal class Mediator(internal val plugins: MutableList<Plugin>) {
class Mediator(internal val plugins: MutableList<Plugin>) {
Copy link
Contributor

@migs647 migs647 Jun 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Love the mediator pattern ++!

Should we give it a more specific name? and since it's public now?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

im actually going to move it back to being internal and expose the applyClosure function via Analytics

import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put

class ContextPlugin: Plugin {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

import java.io.FileOutputStream
import java.util.*

class PropertiesFile(private val directory: File, writeKey: String): KVS {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

import sovran.kotlin.Subscriber
import java.io.File

class StorageImpl(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

?

val dispatcher = coroutineContext[ContinuationInterceptor] as CoroutineDispatcher
val analytics = Analytics("gNHARErhCjBxvBErXOMrTTuwoIlxKkCg") {
application = "MainApp"
// flushInterval = 0
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove comment?

}
)
analytics.flush()
delay(30 * 1000)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Be good to know why we're delaying

Copy link
Contributor

@migs647 migs647 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Super nit picky review

import com.segment.analytics.kotlin.core.*
import com.segment.analytics.kotlin.core.platform.*

class TestRunPlugin(override val name: String = "TestRunPlugin", var closure: (BaseEvent?) -> Unit): EventPlugin {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this for tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yup, added some docs to outline use-cases

@@ -62,7 +67,7 @@ public fun Analytics(
}

// Logger instance that uses the android `Log` class
object AndroidLogger: Logger("AndroidLogger") {
object AndroidLogger : Logger("AndroidLogger") {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are we adding spaces or was this an accident? I noticed others don't have that space.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i ran a auto-lint on the project after the rebase, so all of the files should conform to the same convention

@prayansh prayansh merged commit 7be234e into main Jun 30, 2021
@prayansh prayansh deleted the pray/jvm branch June 30, 2021 17:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Kotlin jvm (not Android) fails to build
2 participants