4developers 2015: przejrzysty i testowalny kod na androidzie? spróbujmy z clean architecture -...
TRANSCRIPT
![Page 1: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/1.jpg)
![Page 2: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/2.jpg)
Testowalna aplikacja na Androida?
Spróbujmy z Clean Architecture.
Michał Charmas
![Page 3: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/3.jpg)
O mnie
• Developer aplikacji mobilnych na Androida
• Trener w firmie Bottega IT Solutions
• Konsultant / Freelancer
![Page 4: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/4.jpg)
Photo by http://commons.wikimedia.org/wiki/User:Mattbuck / CC BY
![Page 5: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/5.jpg)
• Kwestie techniczne / optymalizacyjne - raczej łatwe i dobrze opisane
• Jak żyć?
• jak bezboleśnie wprowadzać zmiany w aplikacji?
• jak nie psuć wcześniej działających ficzerów wprowadzonymi zmianami?
• jak testować?
• jak dzielić odpowiedzialność?
• jak osiągnąć mniejszy coupling?
• jakich patternów / biliotek używac żeby to osiągnąć
![Page 6: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/6.jpg)
Jak żyć?
![Page 7: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/7.jpg)
ioChed 2014
![Page 8: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/8.jpg)
–Android Developers Blog
„…the other primary goal is to serve as a practical example of best practices for Android app design
and development.”
![Page 9: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/9.jpg)
• Gdzie zasada pojedynczej odpowiedzialności?
• Logika domenowa w UI
• Logika UI pomieszana z asynchronicznym pobieraniem danych
• Callbacks everywhere
• Mapowanie kursorów na obiekty biznesowe w UI
• Activity i Fragmenty po 1000+ linii
• Całkowite uzależnienie od frameworka (import android.*)
• Testy?
![Page 10: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/10.jpg)
A 2
B 4
A 2
B 4
A 2
B 4
2 * 4 = 8
2 + 4 = 6
*
* J.B. Rainsberger - Integrated Tests Are A Scam (https://vimeo.com/80533536)
![Page 11: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/11.jpg)
![Page 12: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/12.jpg)
![Page 13: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/13.jpg)
![Page 14: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/14.jpg)
Application
Networking
Persistance
Android SDK Models / Domain
Android Application
Application
Android SDKNetworking
Persistance
Models / Domain
import android.* „szczegół techniczny”
![Page 15: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/15.jpg)
Źródło: http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
![Page 16: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/16.jpg)
• Niezależna od frameworka.
• Niezależna od interfejsu użytkownika.
• Niezależna od bazy danych.
• Testowalna - w oderwaniu od frameworka / bazy danych / serwera.
![Page 17: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/17.jpg)
![Page 18: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/18.jpg)
public class Product { private final long id; private final String name; private boolean isBought; public Product(long id, String name, boolean isBought){ this.id = id; this.name = name; this.isBought = isBought; } public void markBought() { this.isBought = true; } public void markNotBought() { this.isBought = false; }
//getters}
@Test public void testShouldBeBoughtWhenMarkedAsBought() throws Exception { Product product = new Product(0, "sample name", false); product.markBought(); assertEquals(true, product.isBought()); }
![Page 19: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/19.jpg)
public class ProductList implements Iterable<Product> { public Product addProduct(String productName) { } public int removeBoughtProducts() { } public Product getProduct(long id) { } public int size() { } @Override public Iterator<Product> iterator() { } }
![Page 20: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/20.jpg)
–Robert C. Martin
„A good architecture emphasizes the use-cases and decouples them from peripheral concerns.”
![Page 21: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/21.jpg)
• UseCases:
• AddProduct
• ListProducts
• ChangeProductBoughtStatus
• RemoveAllBoughtProducts
public interface UseCase<Result, Argument> { Result execute(Argument arg) throws Exception; }
public interface UseCaseArgumentless<Result> { Result execute() throws Exception; }
![Page 22: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/22.jpg)
public class AddProductUseCaseTest { private AddProductUseCase useCase;
@Before public void setUp() throws Exception { useCase = new AddProductUseCase(); }
@Test public void testShouldAddProduct() throws Exception { useCase.execute("Sample product");
//TODO: verify saved } }
![Page 23: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/23.jpg)
public interface ProductsDataSource { ProductList getProductList(); void saveProductList(ProductList products); }
public class AddProductUseCaseTest { private static final String PRODUCT_NAME = "Sample product"; @Mock ProductsDataSource productsDataSourceMock; @Mock ProductList mockProducts; private AddProductUseCase useCase; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); useCase = new AddProductUseCase(productsDataSourceMock); } @Test public void testShouldAddProduct() throws Exception { when(productsDataSourceMock.getProductList()).thenReturn(mockProducts); useCase.execute(PRODUCT_NAME); verify(mockProducts, times(1)).addProduct(PRODUCT_NAME); verify(productsDataSourceMock).saveProductList(mockProducts); } }
![Page 24: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/24.jpg)
public class AddProductUseCase implements UseCase<Product, String> { private final ProductsDataSource productsDataSource; @Inject public AddProductUseCase(ProductsDataSource productsDataSource) { this.productsDataSource = productsDataSource; } @Override public Product execute(final String productName) { if (productName == null || productName.trim().isEmpty()) { throw new ValidationException("Product name cannot be empty"); } ProductList productList = productsDataSource.getProductList(); Product product = productList.addProduct(productName); productsDataSource.saveProductList(productList); return product; } }
![Page 25: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/25.jpg)
• całkowicie niezależne od frameworka
• pure Java
• może zostać wyciągnięte do oddzielnego modułu - czysto javowego
![Page 26: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/26.jpg)
Persistence / Data
![Page 27: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/27.jpg)
• Domena nie wie o sposobie utrwalania danych.
• Sposób utrwalania danych nie powinien operować na obiektach domeny (wyciekająca abstrakcja od środka).
• Wyznaczenie granicy.
• Trzymanie się „zasady zależności”.
![Page 28: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/28.jpg)
Entities
UseCases
DataSource
DataSourceImpl
StoreRESTStore
InMemoryCacheStoreSharedPreferencesStore
[Product] [ProductList]
[Product -> ProducDBEntity] [ProducDBEntity]
![Page 29: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/29.jpg)
public class ProductEntity { private final long id; private final String name; private final boolean isBought;
public ProductEntity(long id, String name, boolean isBought) { this.id = id; this.name = name; this.isBought = isBought; }
public long getId() { return id; }
public String getName() { return name; }
public boolean isBought() { return isBought; } }
![Page 30: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/30.jpg)
• ProductDataSourceImpl - implementacja oderwana od zewnętrznych bibliotek
• Zależy tylko od ProductEntityStore i Mappera (Product -> ProductEntity)
• Łatwe do zmockowania aby przetestować w izolacji.
public interface ProductEntityStore { List<ProductEntity> getAllProduct(); void storeAllProducts(List<ProductEntity> entities); }
![Page 31: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/31.jpg)
http://upload.wikimedia.org/wikipedia/commons/1/10/20090529_Great_Wall_8185.jpg
![Page 32: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/32.jpg)
public class SharedPreferencesProductEntityStore implements ProductEntityStore { private final SharedPreferences sharedPreferences; private final EntityJsonMapper entityJsonMapper;
//… @Inject public SharedPreferencesProductEntityStore(SharedPreferences sharedPreferences, EntityJsonMapper entityJsonMapper) { this.sharedPreferences = sharedPreferences; this.entityJsonMapper = entityJsonMapper; } @Override public List<ProductEntity> getAllProduct() { try { return entityJsonMapper.fromJson( sharedPreferences.getString(SP_PRODUCT_ENTITIES, „[]” )); } catch (JSONException e) { handleJSONError(e); return Collections.emptyList(); } }
//… }
![Page 33: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/33.jpg)
public class SharedPreferencesProductEntityStoreTest extends AndroidTestCase { private SharedPreferencesProductEntityStore store; @Override public void setUp() throws Exception { super.setUp(); store = new SharedPreferencesProductEntityStore( getAndClearSharedPreferences(), new SharedPreferencesProductEntityStore.EntityJsonMapper() ); } public void testShouldStoreEmptyList() throws Exception { store.storeAllProducts(Collections.<ProductEntity>emptyList()); assertEquals(store.getAllProduct().size(), 0); }}
![Page 34: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/34.jpg)
Entities
UseCases
DataSource
DataSourceImpl
StoreRESTStore
InMemoryCacheStoreSharedPreferencesStore
[Product] [ProductList]
[Product -> ProducDBEntity] [ProducDBEntity]
![Page 35: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/35.jpg)
UI
![Page 36: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/36.jpg)
Źródło: http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
![Page 37: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/37.jpg)
Model View Presenter
Passive View
Presenter
Model
user events
updates model
view updates
state changes
![Page 38: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/38.jpg)
![Page 39: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/39.jpg)
![Page 40: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/40.jpg)
LOLCycle
![Page 41: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/41.jpg)
public interface Presenter<T extends UI> { void attachUI(T ui); }
![Page 42: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/42.jpg)
UI1
P1 P1
UI1 UI2
P2
![Page 43: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/43.jpg)
UI1
P1
UI2UI1
![Page 44: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/44.jpg)
public interface Presenter<T extends UI> { void attachUI(T ui); void detachUI(); }
![Page 45: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/45.jpg)
UI1
P1
UI2
P1
AsyncOperation
P1
![Page 46: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/46.jpg)
public interface UICommand<T> { void execute(T ui); }
private Queue<UICommand<T>> commandQueue = new LinkedList<>();
UI1
P1
UI2
P1
AsyncOperation
P1
![Page 47: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/47.jpg)
@Singletonpublic class ProductListPresenter extends BasePresenter<ProductListPresenter.ProductListUI> { @Override protected void onFirstUIAttachment() { updateProductList(true); } public void productStatusChanged(long productId, boolean isBought) { } public void onAddNewProduct() { } public void onRemoveBoughtProducts() { } private void updateProductList(boolean withProgress) { if (withProgress) { execute(new ShowProgressCommand(), true); } asyncUseCase.wrap(listProductsUseCase).subscribe( new Action1<ProductList>() { @Override public void call(ProductList products) { List<ProductViewModel> viewModels = mapper.toViewModel(products); executeRepeat(new PresentContentCommand(viewModels)); } } ); } }
![Page 48: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/48.jpg)
@Singletonpublic class AddProductPresenter extends BasePresenter<AddProductPresenter.AddProductUI> { private final AddProductUseCase addProductUseCase; private final AsyncUseCase asyncUseCase; @Inject public AddProductPresenter(AddProductUseCase addProductUseCase, AsyncUseCase asyncUseCase) { this.addProductUseCase = addProductUseCase; this.asyncUseCase = asyncUseCase; } public void onProductNameComplete(final String productName) { asyncUseCase.wrap(addProductUseCase, productName) .subscribe( new Action1<Product>() { @Override public void call(Product product) { executeRepeat(new NavigateBackCommand()); } }, new Action1<Throwable>() { @Override public void call(Throwable throwable) { if (throwable instanceof ValidationException) { executeOnce(new ShowValidationErrorCommand()); } // TODO: handle unknown error } }); } }
![Page 49: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/49.jpg)
private static class ShowValidationErrorCommand implements UICommand<AddProductUI> { @Override public void execute(AddProductUI ui) { ui.showValidationError(); } } private static class NavigateBackCommand implements UICommand<AddProductUI> { @Override public void execute(AddProductUI ui) { ui.navigateBack(); } } public interface AddProductUI extends UI { void navigateBack(); void showValidationError(); }
![Page 50: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/50.jpg)
Pink Floyd - The Wall Cover
![Page 51: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/51.jpg)
public class AddProductFragment extends PresenterFragment<AddProductUI> implements AddProductUI { @Inject AddProductPresenter presenter; private EditText productNameView; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setupPresenter(presenter, this); } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { return inflater.inflate(R.layout.fragment_add_product, container, false); } @Override public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); productNameView = (EditText) view.findViewById(R.id.product_name_view); view.findViewById(R.id.product_add_button) .setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { presenter.onProductNameComplete(productNameView.getText().toString()); } }); } @Override public void navigateBack() { ((ProductListFragmentActivity) getActivity()).onProductAdded(); } @Override public void showValidationError() { Toast.makeText(getActivity(), "Product name cannot be empty.", Toast.LENGTH_SHORT).show(); } }
![Page 52: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/52.jpg)
Entities
UseCases
Presenters
UI ProductListUI
AddProductUI
[Product]
[Product -> ProductViewModel] [ProductViewModel]
![Page 53: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/53.jpg)
Zapisywanie stanu• Input użytkownika jest stanem - nie model danych.
• Stan == Parcelable
• UI Zapisuje swój własny stan - EditText, ListView z automatu.
• Powinniśmy trzymać stan w Presenterach?
![Page 54: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/54.jpg)
DI
![Page 55: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/55.jpg)
Kontener DI
• ma konstruktor @Inject - wiem jak go znaleźć - tworzę i zwracam
• nie wiem skąd go wziąć? - sięgam do modułu
Moduły Litania metod dostarczających zależności.
Dagger
daj obiekt
ObjectGraph
@Singleton
![Page 56: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/56.jpg)
AppObjectGraph • AndroidModule • DataModule • DomainModule Application Scope
PresenterActivityOG • PresenterModule • Preseneter - @Singleton onRetainCustomNonConfigurationInstance
ActivityOG • ActivityModule Activity Scope
![Page 57: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/57.jpg)
Wady / Zalety?• Overhead dla małych aplikacji - na pewno wiadomo, że nie urośnie?
• Duża ilość wywołań metod.
• Mniej optymalne rozwiązanie pamięciowo - tworzy i zwalnia się dużo obiektów, fragmentacja pamięci.
• Samo podejście i ,,zasada zależności” słuszne - umożliwiają testowanie.
![Page 58: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/58.jpg)
–Robert C. Martin
„A good architecture allows major decisions to be deffered.”
![Page 59: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/59.jpg)
https://github.com/mcharmas/shoppinglist-clean-architecture-example
![Page 60: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/60.jpg)
http://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html
http://blog.8thlight.com/uncle-bob/2011/09/30/Screaming-Architecture.html
https://vimeo.com/43612849
https://vimeo.com/80533536
http://tpierrain.blogspot.com/2013/08/a-zoom-on-hexagonalcleanonion.html
![Page 61: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/61.jpg)
Na czym polega ,,zasada zależności" w Clean Architecture?
![Page 62: 4Developers 2015: Przejrzysty i testowalny kod na Androidzie? Spróbujmy z Clean Architecture - Michał Charmas](https://reader034.vdocuments.net/reader034/viewer/2022042716/55a65fb81a28ab5b538b457c/html5/thumbnails/62.jpg)
Q&A?