Prueba técnica alvic frontend flutter.
En el siguiente proyecto encontrarás los diferentes retos que debes completar en la prueba técnica.
- Clean Architecture.
- SOLID.
- Null safety (Evitar nulls a toda costa), Programación funcional.
- Manejo correcto de hilos, async, await.
- Evitar a toda costa el "boiler plate" (código repetitivo).
- Implementación de Widgets génericos.
- Unit test (lógica de negocio y widgets).
- flutter test
- mockito
Si conoces los siguientes paquetes y sabes implementarlos es un punto a favor.
- freezed
- injectable
- getit
- bloc_test
La aplicación consiste en una interfaz, una lista de cards que esta poblando con un request a un api/rest, con base en los datos retornados por el api se deben mostrar una lista de personajes "characters" y se deben cumplir las buenas prácticas y minimos requerimientos para desarrollar una app en flutter tanto en la UI como en la lógica de negocio y modelos de datos.
A continuación debes refactorizar una aplicación hecha en flutter, actualmente la app esta hecha con set state, así que, debes refactorizar el código usando el manejador de estados bloc.
Cuando ejecutes el proyecto encontrarás una interfaz como la siguiente:
Encontrarás que en el widget characters_view.dart
se esta haciendo la llamada a backend con http.get
y se estan renderizando los resultados.
![Screenshot 2023-12-22 at 6 23 01 AM](https://private-user-images.githubusercontent.com/13957703/292473678-75f2c447-99f5-42b1-a4b4-60d6c3e26c46.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQ4MDM3NTQsIm5iZiI6MTcyNDgwMzQ1NCwicGF0aCI6Ii8xMzk1NzcwMy8yOTI0NzM2NzgtNzVmMmM0NDctOTlmNS00MmIxLWE0YjQtNjBkNmMzZTI2YzQ2LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODI4VDAwMDQxNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTJiNGJlM2Y0ZmYzMTVjOWQyZTEwYTY5NGUwNTVmZTM2ZWQwNWVlY2M1ZDdiMWZhMzc0NDExNGE5YjQ4ZjQ0YjcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.KdDGGQEhZuiVLg0wCE-5TOYTya-KyjW9550fxEUcDb8)
La UI esperada es la siguiente:
![Screenshot 2023-12-22 at 6 23 01 AM](https://private-user-images.githubusercontent.com/13957703/292473714-e98c681c-b240-4b4f-b128-682b2204125d.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQ4MDM3NTQsIm5iZiI6MTcyNDgwMzQ1NCwicGF0aCI6Ii8xMzk1NzcwMy8yOTI0NzM3MTQtZTk4YzY4MWMtYjI0MC00YjRmLWIxMjgtNjgyYjIyMDQxMjVkLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODI4VDAwMDQxNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWIzYzM3ODM4ZWVhYTI4MGMzYjhiNTA5OTkxODFlNzI2ZTJlMzE0YWY2NGQ5YWJiZGU0MWJhOGJhZmM2NDA0MWEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.F95huz-AguCA6k10zsTWN4dg4i5iFepXiy28TYLuPCM)
- Debes eliminar por completo el uso de
set state
ystatefull widget
e implementar bloc como manejador de estado en un widget tipo stateless. - Debes refactorizar el código de
characters_view.dart
para que luzca como el último screenshot! - Debes simplificar el código eliminando widgets que no estén cumpliendo con ninguna funcionalidad.
- Debes eliminar el código repetitivo.
- Debes implementar null safety.
Pistas!
- Debes crear widgets genericos para que se puedan reutilizar en la vista, ver los widgets pre fabricados en
widgets/custom_button_dialog.dart
ywidgets/generic_grid_content.dart
- Evita no usar el
const
el helper de android studio o vscode ayudar a implementar el correcto uso null safety. - Para el manejo de hilos recuerda solamente usar futures o streams estrictamente cuando necesitas generar un proceso o tarea asíncrona.
Manejo de estado
- En la carpeta
presentation/bloc
encontrarás las clases pre fabricadas para construir el nuevo manejador de estado con bloc y el nuevo widget stateless.
![Screenshot 2023-12-22 at 6 23 01 AM](https://private-user-images.githubusercontent.com/13957703/292475858-9ccba948-cec9-4977-b4a2-caed3ebbcbc8.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQ4MDM3NTQsIm5iZiI6MTcyNDgwMzQ1NCwicGF0aCI6Ii8xMzk1NzcwMy8yOTI0NzU4NTgtOWNjYmE5NDgtY2VjOS00OTc3LWI0YTItY2FlZDNlYmJjYmM4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODI4VDAwMDQxNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWZjZDEyZjUwNjkxOGVmOTY4MGFjMTYxZjkyNzYwZTIzYjg0MDYzOWU0YTEwMmU4ZDkxNWIzM2QyMjU2YzJiNWUmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.ZTWsXicxmfYW8EDaIjQR7ngDJoLvHnP2cdCXCUkyh3k)
En los demas folders encontrarás la siguiente estructura:
![Screenshot 2023-12-22 at 6 26 27 AM](https://private-user-images.githubusercontent.com/13957703/292476441-a09d419f-821b-40fa-86d4-9ec457ab3a5b.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQ4MDM3NTQsIm5iZiI6MTcyNDgwMzQ1NCwicGF0aCI6Ii8xMzk1NzcwMy8yOTI0NzY0NDEtYTA5ZDQxOWYtODIxYi00MGZhLTg2ZDQtOWVjNDU3YWIzYTViLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODI4VDAwMDQxNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTRjMGMyMzgwMDQ0M2FjNGE1NDNjN2I5ZTgwYzQ4ZjQ5YjJjNzBkYzAxNGJhNjhiODdjODZmYjQwNmYwZDg3NTcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.zAhJlLRLHly_dfHZ39Kv3M9akItBkLsEZJyx-IzmHBw)
Es imperativo que sepas donde implementar la extracción de datos y como esos datos llegan al componente de la lógica de negocio, finalmente renderizando los resultados en la vista!
- Cuando implementes la capa de datos y llames el backend debes crear un modelo que hará de transporte entre componentes desde la fuente
el backend
hasta la vista, ese modelo debe tener la siguiente estructura.
![Screenshot 2023-12-22 at 6 35 14 AM](https://private-user-images.githubusercontent.com/13957703/292477825-58cb3320-d11c-4472-900c-4cb43fb1c0a7.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQ4MDM3NTQsIm5iZiI6MTcyNDgwMzQ1NCwicGF0aCI6Ii8xMzk1NzcwMy8yOTI0Nzc4MjUtNThjYjMzMjAtZDExYy00NDcyLTkwMGMtNGNiNDNmYjFjMGE3LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODI4VDAwMDQxNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI4NzM3NWUwYjRjZmI5ODIzMWQxNzNhNTA0ZjNiOTZmMDViZTVmZGIzODJjN2Y5ZmM5ZDhlODQ2OGU5MGI1OWQmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.0HBPAvue1QBmoGHZrVXK6JluYDs_FwFGeGgD24kda18)
PISTA IMPORTANTE!!! Recuerda que lo más importante en clean architecture y S.O.L.I.D es que la comunicación entre componentes y capas debe ser a través de contratos e interfaces!
-
Has el mapeo de datos en el lugar CORRECTO de dominio de negocio con lo que llega del backend a la estructura del modelo de datos requerido en la imagen anterior.
-
Desarrolla el unit test
test/components/...
.
URL: GET
https://mocki.io/v1/5a4770a5-8e75-4a4b-93e8-0fded9315ab2
{
"info":{
"count":826,
"pages":42
"next":"https://rickandmortyapi.com/api/character?page=2",
"prev":null
},
"results":[
{
"id":1,
"name":"Rick Sanchez",
"status":"Alive",
"species":"Human",
"type":"",
"gender":"Male",
"origin":{
"name":"Earth (C-137)",
"url":"https://rickandmortyapi.com/api/location/1"
},
"location":{
"name":"Citadel of Ricks",
"url":"https://rickandmortyapi.com/api/location/3"
},
"image":"https://rickandmortyapi.com/api/character/avatar/1.jpeg",
"episode":[
"https://rickandmortyapi.com/api/episode/1"
],
"url":"https://rickandmortyapi.com/api/character/1",
"created":"2017-11-04T18:48:46.250Z"
},
{
"id":2,
"name":"Morty Smith",
"status":"Alive",
"species":"Human",
"type":"",
"gender":"Male",
"origin":{
"name":"unknown",
"url":""
},
"location":{
"name":"Citadel of Ricks",
"url":"https://rickandmortyapi.com/api/location/3"
},
"image":"https://rickandmortyapi.com/api/character/avatar/2.jpeg",
"episode":[
"https://rickandmortyapi.com/api/episode/1"
],
"url":"https://rickandmortyapi.com/api/character/2",
"created":"2017-11-04T18:50:21.651Z"
},
{
"id":3,
"name":"Summer Smith",
"status":"Alive",
"type":"",
"origin":{
"name":"Earth (Replacement Dimension)",
"url":"https://rickandmortyapi.com/api/location/20"
},
"location":{
"name":"Earth (Replacement Dimension)",
"url":"https://rickandmortyapi.com/api/location/20"
},
"image":"https://rickandmortyapi.com/api/character/avatar/3.jpeg",
"episode":[
"https://rickandmortyapi.com/api/episode/6"
],
"url":"https://rickandmortyapi.com/api/character/3",
"created":"2017-11-04T19:09:56.428Z"
}
]
}
Si lanza un error de url 404 puedes generar de nuevo el endpoint en la pagina https://mocki.io/fake-json-api
copiando y pegando el json anterior.
![Screenshot 2023-12-22 at 7 12 25 AM](https://private-user-images.githubusercontent.com/13957703/292484014-6a8c7bf9-878a-4430-9820-5d6d15536438.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3MjQ4MDM3NTQsIm5iZiI6MTcyNDgwMzQ1NCwicGF0aCI6Ii8xMzk1NzcwMy8yOTI0ODQwMTQtNmE4YzdiZjktODc4YS00NDMwLTk4MjAtNWQ2ZDE1NTM2NDM4LnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNDA4MjglMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjQwODI4VDAwMDQxNFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPTNkNTJlNmUzMWU0ZmRmYmFlMjA5MTg0MzhhMzEwZTU3MWVmYTE3MGU3NjQzYWYxOTQyZGUyMDkxY2I0OTA0MDcmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0JmFjdG9yX2lkPTAma2V5X2lkPTAmcmVwb19pZD0wIn0.8AyaGWsnxygMnD0ryxmC2huok3QyPUzgoUMU7m4yHGU)