Professional Documents
Culture Documents
Ingredients For A Healthy Codebase PDF
Ingredients For A Healthy Codebase PDF
healthy codebase
Romain Piel
Romain Piel
at Songkick
@_rpiel
Songkick
Architecture of an
Android app?
Let me tell you a story…
John
No knowledge
in Android dev
Let’s build an
Android app !
John
No knowledge
in Android dev
ApiManager
John
MyActivity
ApiManager
John
MyActivity
MyActivity
ApiManager
John
MyApplication MyActivity
MyActivity
ApiManager DbManager
John
MyApplication MyActivity
MyActivity
Mary
New hire !
This codebase
looks so old! Let’s
add change a few
things…
Mary
New hire !
ApiManager DbManager
Mary
MyApplication MyActivity
MyActivity
John
Retrofit
ApiManager DbManager
Mary
MyApplication MyActivity
MyActivity
John
Retrofit
ApiManager DbManager
Mary
NewFeature
MyApplication MyActivity
MyActivity Activity
NewFeature
John
Fragment
Retrofit DbManager
ApiManager
RxJava
Mary
NewFeature
MyApplication MyActivity
MyActivity Activity
NewFeature
John
Fragment
App
John Mary
App
John Mary
No idea where this
crash is coming
from
App
John Mary
Francis
New hire !
OMG !
Zero test ?!
Francis
New hire !
Unit tests App
Francis
John Mary
Unit tests App
Francis
Hard to catch up
with the coverage &
too many Android dependencies
John Mary
App
UI tests
Francis
John Mary
App
UI tests
Francis
Interactions with outside
world = flaky tests
John Mary
App
App
Systems should be
• Independent of Frameworks
• Testable
• Independent of UI
• Independent of Database
• Independent of any external agency
Let’s consider this problem
Data layer
Data layer
Domain layer
Data layer
Domain layer
Presentation layer
Data layer
Data layer
Domain layer
Data layer
Data layer
Domain layer
Data layer : repository pattern
ArtistRepository
Domain layer
Data layer
Domain layer
Presentation layer
Domain layer
Domain layer
<activity android:name=".SearchActivity"/>
<activity android:name=".SearchActivity"/>
<activity android:name=".SearchActivity"/>
Data
Presentation
View layer
Interaction
Domain layer
Data
Interaction
Domain layer
Data
Presentation layer
[ View
]
Interaction
Presentation layer
Data
Interaction
Presentation layer
interface SearchPresenter {
void searchArtist(String searchTerm);
void clickArtist(Artist artist);
}
interface SearchView {
void showProgress();
void hideProgress();
void showArtists(List<Artist> artists);
}
class Artist {
String displayName;
String uri;
String id;
LocalDate onTourUntil;
}
Model vs. View model
class Artist {
String displayName;
String uri;
String id;
LocalDate onTourUntil;
}
Model vs. View model
class ArtistViewModel {
String name;
boolean isOnTour;
}
public class ArtistViewHolder extends ViewHolder {
@Bind(R.id.artist_name)
TextView artistName;
@Bind(R.id.on_tour)
TextView onTour;
class ArtistViewModel {
public ArtistViewHolder(View itemView) {
String name;
super(itemView);
boolean isOnTour;
ButterKnife.bind(this, itemView);
}
}
@Override
public void bind(ArtistViewModel viewModel) {
artistName.setText(artistViewModel.name);
onTour.setVisibility(artistViewModel.isOnTour ?
View.VISIBLE : View.GONE
);
}
}
Presentation layer
interface SearchPresenter {
void searchArtist(String searchTerm);
void clickArtist(ArtistViewModel artist);
}
interface SearchView {
void showProgress();
void hideProgress();
void showArtists(List<ArtistViewModel> artists);
}
{...}
}
Presentation layer
{...}
void onItemClick(ArtistViewModel artist) {
searchPresenter.clickArtist(artist);
}
void search(String searchTerm) {
searchPresenter.searchArtist(searchTerm);
}
}
Data layer
Domain layer
Presentation layer
Communication
Rx all the things!
Observable<Model> Data layer
interface ArtistRepository {
Data layer Observable<List<Artist>> search(String searchTerm);
}
Communication
Rx all the things!
interface ArtistRepository {
Data layer Observable<List<Artist>> search(String searchTerm);
}
interface ArtistRepository {
Data layer Observable<List<Artist>> search(String searchTerm);
}
interface SearchPresenter {
void searchArtist(String searchTerm);
Presentation layer
void onDestroy();
}
Structure
Dagger
Structure
Dagger
Application
component
Structure Application
modules
Repositories
Dagger
Application
component
Structure Application
modules
Repositories
Dagger
Activity
component
Application
component
Structure Application
modules
Repositories
Dagger
Activity
modules
Activity
Activity
component
Application
component
Structure Application
modules
Repositories
Dagger
Activity
modules
Activity
Fragment
modules
Presenter
Use cases
Activity
component
Application
component
Structure
Structure
SearchPresenter
Presentation layer
SearchFragment
Testing
Unit
Data layer ArtistRepository
SearchPresenter
Presentation layer
Testable without
SearchFragment
Robolectric
Testing
Unit
Data layer ArtistRepository
Testable with
Robolectric
SearchPresenter
Presentation layer
Testable without
SearchFragment
Robolectric
Testing
UI
Data layer
Domain layer
Presentation layer
Testing .json
UI
Data layer
Domain layer
Presentation layer
Testing .json
UI class ArtistRepositoryTestImpl {
JsonLoader jsonLoader;
Data layer Observable<List<Artist>> search(String searchTerm) {
return jsonLoader.load(“search/artist.json”);
}
}
Domain layer
Presentation layer
Conclusion
Conclusion
We’re hiring!
Links