Aquesta és la segona part del projecte. Si has parat aqui et convido a consultar la primera entrada, on vam configurar l’entorn i vam establir els requisits previs. Ara passem a la implementació del codi.
Objectiu d’avui/Introducció
Documentar la creació del backend. Tot el desenvolupament del codi i que faré menció el podeu trobar al repositori corresponent al meu perfil de Git, o sigui que pots anar directament allà o obrir-lo a una finestra mentre veus els comentaris que descric. No vull deixar-me a aquesta introducció la importància que ha tingut pel bon i correcte desenvolupament del codi:
La documentació oficial d’Amazon Web Services de Boto3 i les seves guies de millors pràctiques, per exemple.
La Classe S3Client i la seva importància
La finalitat de crear una classe S3Client com a façana/embolcall(més conegut com a Wrapper) és que amaga tota la complexitat de boto3. Faig un parèntesi, diguem que:
Estem creant "un embolcall dins d’un altre embolcall". Si m’explico bé, és important entendre això: aquest S3Client més superficial simplificarà Boto3 que també es un embolcall gegantí que amaga tota la complexitat d’AWS.
- La nostra capa d’abstracció ens dóna una interfície senzilla.
- Boto3 és una altra capa que s’encarrega de tasques com la traducció a Python i peticions HTTP(entre d'altres).
Ho encapsula i deixa tot net per a un següent pas sense estar contaminat amb l’altra lògica del projecte (la de Flask). Un altre objectiu que aconseguim si fem que tot passi per S3Client és que podem reutilitzar el codi si un dia pel que sigui decidim canviar la regió que té per defecte de l’S3. Al estar centralitzat, només hem de canviar un arxiu i no 10 o 20 en el cas que estigués tota la lògica repartida en altres arxius.
A més a més, fa molt més fàcil el testeig(testing). Podem simular el comportament d’AWS(amb moto) dins d’aquesta classe sense haver d’interceptar la resta del codi.
Aquesta organització que pot semblar una complicació al principi, ens estalvia hores de feina a llarg termini.
A cada mètode de la classe hem usat el bloc try/except ClientError de Boto3. Això fa que el codi no col·lapsi en cas d’algún problema de xarxa amb AWS o hi han permisos inadequats. Això fa que et retorni un valor segur com es False o una llista buida. És una recomanació de la documentació oficial.
D’altra banda quan utilitzem os.path.basename ens garanteix que només utilitzem el nom del fitxer final ex. “test_file.txt” i no deixa pujar d’altres amb un nom maliciós. Garantint una lògica d’execució.
Testing de qualitat
Un cop escrit tot el programari ens trobarem amb la pregunta de si tot funciona correctament i no em refereixo en el clàssic de donar-li tot el codi a ChatGPT, Gemini, Deepseek, etc. per si troba alguna errada al codi. En el meu cas vaig crear una carpeta anomenada scripts que em va fer d’una mena de pont entre el codi i els tests unitaris que faria com a final de desenvolupament del backend.
Els scripts que vaig anar escrivint tenien l’objectiu de fer proves manuals o demostracions ràpides i són útils per verificar si la configuració d’AWS es correcta. Els scripts verifiquen la connexió real amb AWS i els tests verifiquen que el codi funciona correctament.
Aquests scripts només criden mètodes de classe S3Client i no tenen lògica de boto3.
Deixant de banda els scripts o petits tests. Anem a la problemàtica que seria “Com provem aquesta classe S3Client?" sense que:
- Ens generi despeses a la factura d’AWS.
- Depenguem de la velocitat d’Internet i latència.
- Modifiquem o esborrem dades reals sense voler.
Per resoldre aquests punts tenim dues eines anomenades: Pytest i Moto, aquestes fan simulacions o com diuen professionalment en anglès “Mocking”.
-Pytest és el marc de proves que utilitzem per a estructurar i executar els tests de manera fiable. Què és un marc de proves(framework)? És un conjunt d’eines que faciliten les proves automàtiques per veure si funciona de manera corresponent, en aquest cas aquesta eina funciona per a Python. Amb aquesta executes els teus tests.
-Moto és una llibreria que simula els serveis d’AWS. Amb aquesta pots crear versions “falses”(que realment no es creen) interceptant les crides que Boto3 fa a AWS i simulant l’entorn a la memòria del teu ordinador.
En el meu cas quan he fet després d’haver importat mock_s3 i pytest:
@pytest.fixture
def s3_client():
with mock_s3():
client = S3Client(region_name="eu-west-1")
client.create_bucket("bucket-prueba")
yield client
He creat una fixture de pytest amb el decorador mock_s3(). La fixture prepara quelcom que necessitem abans per executar el test. En aquest cas un client s3 fals. I el decorador afegeix un comportament extra a una funció. Li estem dient que la informació que posem a continuació la interpreti d’una manera determinada com si fos “mock_s3”.
Quan escrivim yield assegurem que cada test unitari s’executa en un entorn AWS fals, es crea i s’esborra de la memòria de l’ordinador.
Un altre detall és l’ús de la funció de Pytest tmp_path que ens permet crear fitxers temporals falsos i ens serveix per exemple per simular la pujada d’aquests i esborrar-los un cop acabat el test, no deixant residus al sistema.
Per que tot funcioni hem de seguir un patró anomenat AAA(Arrange-Act-Assert). Vol dir:
-Preparar(Arrange):
Ho deixem tot enllestit per realitzar la prova. Crear objectes, preparació de l’entorn…
-Actuar(Act):
Executem l’acció a provar. Cridar una funció, fer una petició a un servei…
-Assert(Comprobar):
Verificar i contrastar els resultats. Si coincideixen funciona, sinó falla.
D’aquesta manera em dono per satisfet, havent assolit l’objectiu de tancar el cicle del backend amb èxit.
Comentaris
Publica un comentari a l'entrada