Skip to content
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

Add usecase repository #2

Merged
merged 12 commits into from Oct 17, 2017
Merged

Add usecase repository #2

merged 12 commits into from Oct 17, 2017

Conversation

flipper83
Copy link
Member

This pull request contains the first commit with information come from use cases.
I like update the PR step by steps because I have some code that I like your approval :)

This first commit contains usercases, list representation and resultValues.
Next commit will contains a list test and travis configuration.
After that I will start working on repository code.

fun <R> success(value: R) = Result.Right(value)
fun <R> error(error: Error) = Result.Left<R>(error)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

If you implemented this class it's great! I guess we don't need more right now. But I'd rename this class as Either and if it's possible, I'd use this or this implementation so we don't need to re-invent the wheel. It seems the libraries implementations are more complete 😃

Copy link
Contributor

Choose a reason for hiding this comment

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

I've been using funKTionale and it fits perfectly as it is separated in tons of modules that we can load whenever we want (funktionale-either is what we want here)

Copy link
Member Author

Choose a reason for hiding this comment

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

I took the Kotlin blog implementation :), I renamed from Either to Result because a lot of people don't know what Either means. But I will import funktionale-either.

Copy link
Member Author

Choose a reason for hiding this comment

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

What is your opinion about limit the Left type to Error except open to any kind of type?

Copy link
Contributor

Choose a reason for hiding this comment

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

Either represents the disjunction mathematical concept where the left side of the expression can be an error or not. I'd not force the usage of an error in the left side.

Copy link
Member Author

Choose a reason for hiding this comment

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

If we are going to use always for symbolizing an error? is not good limit the inheritance?

Copy link
Contributor

Choose a reason for hiding this comment

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

Most of the times we will use it with errors, but not always. In this project, we don't even need to use errors. If you want to port the original version of this kata you don't even need to use Either or Result.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm asking for learn :) beacuse If the first time that I implement this kind of things. I like understand why we do some things. Original kata is not writting in kotlin, I like adjust the code to kotlin for learn and discover different ways to develop. Remember that the swift Kata is not similar to the Java one ;)

Copy link
Contributor

Choose a reason for hiding this comment

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

Don't read me wrong. I'm just trying to give you my feedback as you requested. If you read the Swift implementation of this kata we don't handle errors. If you have any doubt or any concrete question I did not answer, please let me know.

package com.karumi.ui.domain.model

data class SuperHero(val name: String,
val photo: String,
Copy link
Contributor

Choose a reason for hiding this comment

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

If I remember well. The Marvel API has the picture field as optional.

Copy link
Member Author

Choose a reason for hiding this comment

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

the problem is if this is optional picasso crash, what do you prefer? check in ui or check in the respository layer?

Copy link
Contributor

Choose a reason for hiding this comment

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

If you change the picture to optional you'll have to check if the picture is defined before using it in picasso.


class GetSuperHeroes {

val mockSuperHero = SuperHero(name = "Super Peter",
Copy link
Contributor

Choose a reason for hiding this comment

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

In the original implementation, we have a simple repository and the values it returns are private. I've read the repository will be your next PR but we should keep this as private.

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, this line will be dissappear in the next PR, but yes, this is a bug.


fun get(): Result<List<SuperHero>> {
return Result.success(arrayListOf(mockSuperHero))
}
Copy link
Contributor

Choose a reason for hiding this comment

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

You don't even need { } here. You can use just a = and return your value.

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, thank you!


private fun refreshSuperHeroes() {
async {
Copy link
Contributor

Choose a reason for hiding this comment

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

The usage of async/await is so cool and so fancy that I love it ❤️ But I was wondering if we can easily configure an idling resource. I've been reading the documentation and I don't see any reference to this topic. If this is the case, we will need to create our own idling resource. For this kata this approach is ok, but w/o the idling resource I'd not use this library.

Copy link
Member Author

Choose a reason for hiding this comment

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

For the kata is not mandatory, and I like try wrap the async/await in an object. Let me check one idea that I have :P

Copy link
Contributor

Choose a reason for hiding this comment

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

For the kata is not mandatory. That's why I don't request changes and just added comments 😃 I've created a new entry in our outreach ideas log for implementing this.

val result = await { getSuperHeroes.get() }
view()?.hideLoading()
when (result) {
is Right -> view()?.showSuperHeroes(result.value)
Copy link
Contributor

Choose a reason for hiding this comment

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

You are not implementing one of the two main kata behaviors. The empty case implementation.

Copy link
Member Author

Choose a reason for hiding this comment

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

because is out of the scope of the PR. I will add in a next iteration.

import com.karumi.ui.domain.Result
import com.karumi.ui.domain.model.SuperHero

class GetSuperHeroes {
Copy link
Contributor

Choose a reason for hiding this comment

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

As this language is less verbose you can create a file named usecases.kt and move the two use cases we will have to this file. You can even name it domain and move your abstract data types and use cases there.

Copy link
Member Author

Choose a reason for hiding this comment

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

Not for me, one of the good part of the Use cases takes a look and check all operations that we can do over our domain, if we put all together in one file this file can grow to fast and is not a benefict for read it.

Copy link
Contributor

Choose a reason for hiding this comment

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

ok

instance())
}

bind<GetSuperHeroes>() with provider { GetSuperHeroes() }
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you need to bind a class even when the constructor is empty?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes this is mandatory :( this is one of the things that I don't like from kodein.

Copy link
Contributor

Choose a reason for hiding this comment

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

Then I'd not use this dependency injector. If we have to define a dependency every time we need it it's going to be a pain in the ass. Imagine you need to use this use case in two different places and this use case depends on a repository. Based on this library you'll need to write this code twice:

bind<GetSuperHeroes>() with provider { GetSuperHeroes(new SuperHeroesRepository()) }

When the dependency tree is simple, this is not an issue but in the future, this will be a pain in the ass. We could reduce the boilerplate by moving this declaration to a module configured just one.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yes, I have a general module, commons implementation must to be in general module. I am ok with you that it's not the best solution. I don't know why does not automatic.

}

private fun renderSuperHeroPhoto(photo: String) {
Picasso.with(context).load(photo).fit().centerCrop().into(photoImageView)
Copy link
Contributor

Choose a reason for hiding this comment

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

Remember to check if the photo is defined. The Marvel API declares this attribute as optional but we are not handling it.

Copy link
Member Author

Choose a reason for hiding this comment

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

I repeat the same question, if we manage the nullability here or in the api. And remember that the kata don't use internet the data comes from hardcoded info in the repositories.

Copy link
Contributor

Choose a reason for hiding this comment

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

Choose the one you prefer. By definition the picture is optional. If I were you, I'd declare the photo as an optional and I'd check the definition of the photo value in this method, in the UI layer.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm trying to know if it's a best option resolve the nullabilities as soon as we found, in this case the api layer or manage in the ui layer. :) I trying to learn because you have more experience with this kind of things.

@@ -7,7 +7,7 @@ buildscript {
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-beta4'
classpath 'com.android.tools.build:gradle:3.0.0-beta6'
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need to use the beta version?

Copy link
Member Author

Choose a reason for hiding this comment

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

yes, do yo ask the same in the previous PR.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't remember why it's needed, but don't worry. I'll review the previous PR.

@pedrovgs
Copy link
Contributor

pedrovgs commented Oct 2, 2017

Well done @flipper83 😃 As this project aims to be a reference for testing purposes I'd recommend you to start writing tests ASAP. Part of your design will be directly affected by your tests implementation.

Copy link
Contributor

@Serchinastico Serchinastico left a comment

Choose a reason for hiding this comment

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

This is looking awesome, thank you for your work Jorge

fun <R> success(value: R) = Result.Right(value)
fun <R> error(error: Error) = Result.Left<R>(error)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I've been using funKTionale and it fits perfectly as it is separated in tons of modules that we can load whenever we want (funktionale-either is what we want here)

isAvenger = true,
photo = "https://avatars1.githubusercontent.com/u/4030704")

fun get(): Result<List<SuperHero>> {
Copy link
Contributor

Choose a reason for hiding this comment

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

Have you considered implementing the invoke operator so that they look like functions instead of having to implement a get, execute, run method?

Copy link
Member Author

Choose a reason for hiding this comment

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

@Serchinastico Serchinastico merged commit ec6bd10 into master Oct 17, 2017
@Serchinastico Serchinastico deleted the add-usecase-repository branch October 17, 2017 16:25
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.

None yet

3 participants