Dependency Injection, The Best Pattern

CodeAesthetic
4 Aug 202313:15

Summary

TLDRLa inyección de dependencias, aunque su nombre suene más sofisticado de lo que es, es un concepto fundamental en la programación que permite a una pieza de código utilizar otra pieza de código pasándola como parámetro en lugar de utilizarla directamente. Este enfoque desbloquea efectos secundarios poderosos, como se demuestra en la construcción de un servicio de adjuntos para una aplicación de chat de negocios. El servicio maneja múltiples ubicaciones de almacenamiento, como S3 de AWS y servidores SFTP, y permite la integración de diferentes métodos de almacenamiento como WebDav. A través de la inyección de dependencias, se pueden crear interfaces y clases que se adapten a las necesidades específicas de cada cliente, facilitando la gestión de configuraciones y la capacidad de pruebas unitarias. La inyección de dependencias permite una arquitectura modular y fácil de modificar, lo que se ve particularmente útil para adaptarse a los cambios en los requisitos del negocio o en los acuerdos con proveedores de servicios de seguridad y almacenamiento. Además, permite la creación de interfaces comunes para componentes como escáneres de virus, generadores de vistas previas y servicios de cifrado, lo que facilita la transición entre diferentes implementaciones y la realización de pruebas de integración y unitarias.

Takeaways

  • 🧩 **Inyección de Dependencias Sencilla**: La inyección de dependencias es el proceso de pasar objetos de una clase a otra en lugar de crearlos internamente, lo que puede hacer que el código sea más flexible y fácil de mantener.
  • 🔍 **Separación de Concerns**: Al utilizar la inyección de dependencias, se separan las responsabilidades del código, lo que permite una mejor comprensión y manejo del mismo.
  • 🚀 **Flexibilidad en la Configuración**: Permite configurar el comportamiento del sistema sin modificar el código base, simplemente cambiando las dependencias que se inyectan.
  • 🛠️ **Facilidad para Cambios**: Es fácil adaptar el servicio para diferentes necesidades al inyectar diferentes implementaciones de una interfaz.
  • 📂 **Manejo de Almacenamiento Diverso**: La inyección de dependencias permite manejar múltiples sistemas de almacenamiento, como S3, SFTP y WebDav, según las preferencias de los clientes.
  • 🔗 **Interfaces y Fábricas**: Se utilizan interfaces y fábricas para crear y proporcionar las implementaciones correctas de los servicios, lo que simplifica el código y lo hace más mantenible.
  • 🛡️ **Prevención de Errores**: Al requerir que se pasen exactamente los valores necesarios a través de la inyección de dependencias, se reduce la probabilidad de errores en la configuración.
  • 🔄 **Procesos de Subida Modulares**: Los procesos de subida de archivos, como la detección de virus, el escalado de imágenes y la generación de vistas previas, se modularizan y se inyectan según sea necesario.
  • 🔐 **Encriptación y Seguridad**: La inyección de dependencias también se utiliza para manejar la encriptación de archivos, inyectando servicios de claves y encriptación para garantizar la seguridad de los datos.
  • 🧪 **Pruebas y Mocks**: La inyección de dependencias facilita la prueba de código al permitir la inyección de implementaciones ficticias o simuladas, lo que aísla componentes para pruebas unitarias.
  • 🔄 **Cambio de Implementaciones**: La capacidad de inyectar diferentes implementaciones de una interfaz hace que sea fácil cambiar o actualizar componentes del sistema sin afectar el resto del código.

Q & A

  • ¿Qué es la inyección de dependencias y cómo se describe en el script?

    -La inyección de dependencias es un principio de programación que permite a una pieza de código utilizar otra pieza de código sin depender directamente de ella, sino que se le pasa por referencia. En el script, se describe como un proceso simple que permite efectos secundarios poderosos, permitiendo la modularidad y la facilidad de prueba de código.

  • ¿Cómo se utiliza la inyección de dependencias en la aplicación de negocios mencionada en el script?

    -En la aplicación de negocios, la inyección de dependencias se utiliza para manejar el almacenamiento de archivos adjuntos. Se crean interfaces y múltiples implementaciones para diferentes servicios de almacenamiento, como S3, SFTP y WebDav. Esto permite que el código que realiza la solicitud de almacenamiento no sepa ni se preocupe por el destino exacto del archivo, mejorando la claridad y la flexibilidad del código.

  • ¿Por qué es problemático tener un único método de carga con múltiples condiciones 'if' para manejar diferentes destinos de almacenamiento?

    -Tener un único método de carga con múltiples condiciones 'if' hace que la clase tenga muchas responsabilidades, lo que hace que el código sea feo y difícil de entender. Además, el código se mezcla para manejar diferentes protocolos y hay muchas rutas que puede tomar, lo que lo hace más complejo. También aumenta la posibilidad de errores al requerir una gran cantidad de información específica del destino que debe ser proporcionada por el llamador del método.

  • ¿Cómo se simplifica el proceso de carga de archivos adjuntos utilizando la inyección de dependencias?

    -Al utilizar la inyección de dependencias, se crean interfaces y se inyectan las implementaciones correspondientes en el controlador de la solicitud. Esto significa que el controlador no necesita conocer los detalles de la implementación de almacenamiento, simplificando así el proceso y centrando la lógica de negocio en la solicitud en sí.

  • ¿Cuál es el propósito de los escaneres de virus y cómo se implementan en el servicio de carga de archivos?

    -Los escaneres de virus se utilizan para verificar las firmas de virus en los archivos cargados. En el servicio, se implementa un escaner de virus a través de una interfaz compartida, lo que permite inyectar diferentes escaneres de virus sin alterar el código del controlador de solicitudes. Esto facilita la prueba y el cambio de escaner si es necesario.

  • ¿Cómo se aborda el problema de la escalado de imágenes en el servicio de carga de archivos?

    -Para el escalado de imágenes, se utiliza la biblioteca Sharp y se encapsula en una interfaz de escalado de imágenes. Esta interfaz también incluye un método para determinar si un archivo adjunto admite el escalado. Solo se realiza el escalado si el archivo lo admite, lo que se inyecta en la solicitud de carga.

  • ¿Cómo se maneja la generación de vistas previas para diferentes tipos de archivos adjuntos?

    -Se tiene una interfaz que representa diferentes generadores de vistas previas, cada uno de los cuales maneja un tipo específico de archivo adjunto. Se inyecta una fábrica que decide qué generador de vistas previas crear basado en el tipo MIME del archivo cargado. Esto permite que el código de carga no se preocupe por los detalles de la generación de vistas previas.

  • ¿Por qué se utiliza el cifrado de archivos antes de almacenarlos en Amazon S3?

    -El cifrado de archivos antes de su almacenamiento en Amazon S3 se realiza para proteger los datos en caso de una violación de seguridad. De esta manera, incluso si se produce un incidente de seguridad, los archivos almacenados están cifrados y, por lo tanto, más seguros.

  • ¿Cómo se implementa el cifrado de archivos en el servicio de carga de archivos?

    -Se utiliza un servicio de claves que proporciona una clave por usuario para el cifrado AES. Este servicio se inyecta en la implementación de cifrado AES, que a su vez se inyecta en la fábrica de almacenamiento. Cuando se recibe una solicitud para una empresa configurada para usar AWS, la fábrica de almacenamiento inyecta el cifrado AES en una nueva instancia de almacenamiento AWS.

  • ¿Cómo se abordan los cambios en la configuración del servicio de carga de archivos?

    -La configuración del servicio se puede cambiar desde un solo punto, lo que facilita la modificación del servicio. Por ejemplo, una vez que se cierra el acuerdo con Synergy Security, solo se necesita cambiar dos líneas de código para cambiar el servicio de escaneo de virus. También se puede agregar soporte de vista previa para nuevos tipos de archivos de manera sencilla.

  • ¿Por qué es beneficioso utilizar interfaces y la inyección de dependencias incluso si solo hay una implementación?

    -El uso de interfaces y la inyección de dependencias permite controlar los puntos de conexión y elegir qué implementación utilizar. Esto no solo se utiliza para elegir la implementación en el servicio de producción, sino que también permite inyectar implementaciones falsas o simuladas para pruebas. Esto facilita la prueba de aislamiento de secciones de código sin necesidad de modificar la estructura del código.

  • ¿Cómo se facilitan las pruebas con la arquitectura basada en inyección de dependencias?

    -La arquitectura basada en inyección de dependencias facilita las pruebas al permitir inyectar implementaciones simuladas o falsas. Esto permite aislamiento de secciones de código durante las pruebas, lo que hace que el proceso de prueba sea más sencillo y menos invasivo. Además, si se necesita probar un método privado o establecer una variable interna, esto puede ser una señal de que se debe considerar la posibilidad de extraer y aislar partes del código mediante la inyección de dependencias.

Outlines

00:00

🔌 Introducción a la Inyección de Dependencias

La inyección de dependencias se presenta como un concepto fundamental en la programación que permite a una pieza de código utilizar otra sin necesidad de conocer detalles sobre su implementación. Se centra en el ejemplo de una aplicación de negocios donde los usuarios pueden chatear, enviar imágenes y archivos, y cómo se maneja el proceso de envío de archivos a través de un servicio de adjuntos. Este servicio es responsable de almacenar, recuperar y procesar todos los adjuntos. Se discute cómo la inyección de dependencias puede mejorar la estructura y flexibilidad del código, especialmente al manejar múltiples ubicaciones de almacenamiento según las preferencias de los clientes.

05:05

🛠 Procesos de Subida y Seguridad de los Archivos

Se describen los diferentes procesos que un archivo atraviesa una vez que es enviado por un usuario. Incluye la verificación de virus, el escalado de imágenes, la generación de vistas previas y el cifrado de archivos antes de su almacenamiento en S3 de Amazon Web Services. Además, se aborda la importancia de la capacidad de cambiar fácilmente estos procesos según las necesidades del negocio o los cambios en las soluciones de seguridad, como el cambio de escáneres de virus o la adición de soporte para nuevos tipos de archivos.

10:06

🧩 Ventajas de la Inyección de Dependencias para la Pruebas y la Flexibilidad

Se destaca cómo la inyección de dependencias permite la creación de interfaces que facilitan la prueba de componentes individuales y la integración de nuevas funcionalidades sin alterar la estructura principal del código. Se menciona la utilidad de las interfaces para inyectar implementaciones simuladas o ficticias durante las pruebas, lo que permite aislamiento y verificación de la lógica de negocio sin depender de servicios externos. Además, se invita a los suscriptores de Patreon a realizar un pequeño experimento práctico con el servicio de adjuntos proporcionado, cambiando la inyección de dependencias y compartiendo los resultados.

Mindmap

Keywords

💡Inyección de dependencias

La inyección de dependencias es un principio de programación que permite a un componente software recibir las dependencias que necesita para funcionar, en lugar de crear o buscar esas dependencias internamente. En el video, se utiliza la inyección de dependencias para construir un servicio de adjuntos que permite a los usuarios compartir archivos en una aplicación de chat de negocios. Este concepto es fundamental para entender cómo se modulariza y extiende la funcionalidad del servicio.

💡Interfaz

Una interfaz en programación es un contrato que define un conjunto de métodos que una clase debe implementar. En el contexto del video, se crean interfaces para representar el almacenamiento de adjuntos, lo que permite a los desarrolladores definir múltiples implementaciones del mismo contrato. Esto es crucial para la inyección de dependencias y permite una mayor flexibilidad y facilidad de prueba.

💡Almacenamiento de adjuntos

El almacenamiento de adjuntos se refiere a la capacidad de guardar y recuperar archivos adjuntos en una aplicación. En el video, se discute cómo se utiliza la inyección de dependencias para manejar diferentes ubicaciones de almacenamiento, como S3 de AWS, SFTP y WebDav, dependiendo de las preferencias de los clientes.

💡S3 de AWS

S3 (Simple Storage Service) es un servicio de almacenamiento en la nube ofrecido por Amazon Web Services. En el video, se menciona que S3 es el destino de almacenamiento predeterminado para los archivos adjuntos, destacando su uso para la gestión de archivos en la aplicación de chat de negocios.

💡Factory

Una factory es una función o método que encapsula la lógica de creación de objetos y los devuelve. En el video, se utiliza una factory para crear instancias de almacenamiento de adjuntos basadas en la configuración de la empresa del usuario, lo que simplifica el proceso de construcción de objetos y permite una mayor modularidad.

💡Escaner de virus

Un escaner de virus es un software que analiza archivos en busca de código malicioso. En el video, se menciona el uso de un escaner de virus llamado Threat Protect y la posibilidad de cambiar a otro escaner, Synergy Security Scanner, mediante la inyección de dependencias, lo que permite a los desarrolladores probar y cambiar fácilmente la implementación del escaner de virus.

💡Escalado de imágenes

El escalado de imágenes hace referencia al proceso de cambiar el tamaño de una imagen. En el video, se utiliza una biblioteca llamada Sharp para reducir el tamaño de las imágenes a un ancho máximo de 2500 píxeles, lo que mejora la experiencia del usuario al reducir el uso de ancho de banda y la velocidad de carga.

💡Generación de vistas previas

La generación de vistas previas implica crear una representación visual de un archivo antes de que se descargue completamente. En el video, se discute cómo se utiliza una interfaz para diferentes generadores de vistas previas, lo que permite manejar diferentes tipos de archivos y simplificar el proceso de generación de vistas previas.

💡Cifrado AES

El cifrado AES (Advanced Encryption Standard) es un algoritmo de cifrado simétrico ampliamente utilizado para proteger datos. En el video, se menciona el uso de cifrado AES para proteger los archivos antes de almacenarlos en S3, lo que asegura la seguridad de los datos en caso de una violación de seguridad.

💡Pruebas unitarias

Las pruebas unitarias son un tipo de prueba de software que evalúa cada unidad o componente del software individualmente. En el video, se destaca cómo la inyección de dependencias facilita la realización de pruebas unitarias al permitir a los desarrolladores isolar secciones de código y utilizar implementaciones ficticias o simuladas de las dependencias.

💡Desarrollo y producción

El desarrollo y la producción son dos entornos distintos en el ciclo de vida del software. El desarrollo es donde se escribe y se prueba el código, mientras que la producción es donde el software se ejecuta para su uso final. En el video, se discute cómo la inyección de dependencias permite a los desarrolladores cambiar fácilmente entre diferentes entornos, como utilizar un escaner de virus de prueba en desarrollo y otro en producción.

Highlights

Dependency injection is a simple concept but unlocks powerful side effects

Example business app allows users to chat, send pictures and files

File attachments are uploaded to an attachment service for storage and processing

Default storage location is Amazon S3, a simple storage service

Some clients require multiple storage locations like SFTP or WebDav

Using if statements and optional variables makes code complex and error-prone

Dependency injection allows configuring and switching implementations easily

Create an interface for attachment storage with an upload method

Implement different storage options like S3, SFTP, WebDav by implementing the interface

Pass the storage implementation into the request handler instead of configuration

Use a factory to simplify creating storage instances from company configuration

Upload process includes virus scanning, image scaling, preview generation, encryption

Use shared interfaces to easily switch between different virus scanners

Image scaling can be injected through an ImageScaler interface

Preview generation uses an interface with different implementations for file types

Inject a factory to choose the right preview generator based on file type

Encryption uses AES with a per-user key from a KeyService

Injecting dependencies makes it easy to swap in fake implementations for testing

Interfaces allow isolating components for testing in isolation

Dependency injection promotes clean, maintainable, testable code

Transcripts

play00:00

Dependency injection is a term

play00:01

I don't love because it sounds a lot more fancy than it is.

play00:05

Dependency injection is simply when you have a piece of code

play00:08

which uses another piece of code, and instead of using that code

play00:11

directly, it's passed in instead.

play00:14

When you pass something in to be used, we call it injection.

play00:17

We inject the dependent code into the code that uses it.

play00:21

While this part is quite simple, it unlocks

play00:23

some very powerful side effects that we're going to cover.

play00:27

We have a business app where users can chat with their coworkers.

play00:30

They can also send pictures and files to each other.

play00:33

When a user sends something, the file gets uploaded to our attachment service.

play00:37

The attachment service is responsible for storing, retrieving and processing

play00:41

all attachments.

play00:43

We're

play00:43

going to build up this whole service using dependency injection

play00:46

and we'll see what it enables us to do.

play00:58

When a user sends a message

play00:59

with an attachment, the message text gets sent to our standard chat service.

play01:03

We want people to receive their messages almost real time.

play01:07

So this service is all about speed.

play01:09

The attachment, on the other hand, gets uploaded to our attachment service.

play01:13

There's an end point in our note service

play01:14

/attachment/upload that the app connects to and uploads a file.

play01:18

The attachment gets stored on the disk temporarily, processed in a few ways

play01:22

we'll talk about and then uploaded to its final destination.

play01:26

The default storage location is an S3, a part of Amazon's Web services.

play01:31

It's a simple storage service that lets you put up files and pull them down.

play01:35

We have some code here that takes the uploaded file

play01:38

and then uploads it to S3.

play01:40

Unfortunately, simple and elegant doesn't always like to co-exist with business.

play01:44

While S3 is nice and straightforward and most of our clients are okay with it,

play01:48

we have a few firms that don't want us to permanently store their data.

play01:52

This means we actually need our service to handle multiple storage locations.

play01:56

Then, depending on which company a user is from,

play01:59

we need to put their attachments in the right place.

play02:02

Most of these picky clients just give us an SFTP server to connect to,

play02:05

but one really wanted us to use WebDav.

play02:09

Our first thought might be to simply extend our upload code with some

play02:12

if statements

play02:20

and then have the caller of the upload method pass in where to upload the file.

play02:24

This is awkward for a few reasons.

play02:26

First, this one class has a ton of responsibility, making the code pretty ugly.

play02:31

The code for SFTP is intermingled with the code

play02:33

from AWS and WebDav, even though they're pretty different.

play02:37

There's a lot of paths the code can take, and that makes the code

play02:40

harder to understand.

play02:43

Second, using the class isn't very simple.

play02:47

We have this one upload function

play02:49

which needs a bunch of info for where we're going to upload the attachment.

play02:53

But what info it needs is very different depending on where it's going.

play02:57

If it's AWS, we need the AWS keys.

play03:00

If it's SFTP

play03:01

we need the address and private key and WebDav needs a URL and auth key.

play03:05

So we're kind of forced

play03:06

to have a bunch of these

play03:06

optional variables that need to be filled out in certain cases,

play03:10

and then comments to tell you which ones to fill out.

play03:12

This makes it pretty easy for the caller to make a mistake.

play03:15

And finally, the part of the code that actually calls upload over here

play03:19

needs to have all of this destination specific context to perform the upload.

play03:24

But really, at this phase, it just wants to upload.

play03:27

The part of the code that knows best which company a user is from

play03:30

and can deduce where the file should go is up here at the beginning of the request.

play03:34

But right now, we're forced to pass all of this information around.

play03:38

Let's see what happens if we use dependency injection instead.

play03:41

Let's create an interface that represents our attachment storage,

play03:44

which contains a key upload method

play03:46

that does what the request handler wants to do: Upload an attachment.

play03:50

Then we create three different implementations of the storage interface.

play03:54

The configuration for each is passed into their constructor.

play03:59

There's no

play03:59

more optional variables that sometimes need to be set.

play04:03

We require exactly these values and you get an error if you forget one.

play04:07

So now, once the user is authenticated and we know which company they're from,

play04:11

we create the storage that the request handler should use.

play04:15

Instead of the configuration needing to be passed all the way to the request

play04:18

handler, only the storage is passed to, or injected into, the request handler.

play04:24

It's not aware of which storage is passed in

play04:26

or where the file is going, it just knows that it can call upload.

play04:30

That said, this construction code is still a little

play04:33

too complex to put here, so let's see if we can clean this up.

play04:37

If we look at the input here, it's really just this company configuration

play04:41

and the output is the storage which conforms to the storage interface.

play04:46

So we can just move this out to a factory.

play04:51

Great.

play04:52

But saving to the final storage destination

play04:55

is the last step of the process.

play04:57

We have all these other stages that the upload goes through.

play05:04

We run each upload through a virus scanner.

play05:07

This checks the files for signatures of obvious viruses.

play05:11

Then if the file’s an image, we scale it down

play05:13

to a max width of 2500 pixels.

play05:17

This is what we display to the user when they click on an image

play05:19

because it uses less bandwidth and loads faster.

play05:24

Then the file goes through preview generation.

play05:26

This is basically the thumbnail that pops up underneath an attachment in the chat

play05:30

so the user can see what the attachment is without fully downloading it.

play05:35

Then the last step is encryption.

play05:38

If we're storing the files on Amazon's S3, we pre encrypt the files

play05:41

before sending them up.

play05:42

That way, if there's a security breach at Amazon,

play05:45

we can say they're encrypted

play05:46

when we have to send out one of those: ‘We were hacked, btw’, emails.

play05:50

So let's see how we

play05:51

can make each of these requirements fit cleanly into our service.

play05:55

For the virus scanner, we currently use a scanner called Threat Protect.

play05:59

However, Synergy Security Scanner has much better

play06:02

detection KPIs and our plan is to switch to it.

play06:05

But sadly, we haven't finalized the deal with Synergy We're only allowed to test

play06:09

with it in our development environment, not in production.

play06:12

No worries.

play06:13

We can create a shared interface for our two scanners

play06:20

and on initialization we pick one

play06:26

and inject

play06:27

that one into the request handler.

play06:32

When we launch in development mode, synergy security is initialized

play06:36

and in production the old Threat Protect scanner is created.

play06:40

Our request handler just scans the files but doesn't know which

play06:43

scanner is doing it.

play06:45

For image scaling,

play06:46

we use the sharp library in order to inject that,

play06:50

we simply wrap it up in an image scaler interface.

play06:54

The interface also contains a method

play06:56

which tells us if an attachment supports scaling.

play07:00

We injected into our upload, request and only scale

play07:04

if the attachment supports it.

play07:08

Preview generation is the most complex given how many types of attachments

play07:11

there could be.

play07:13

We have an interface that represents the different preview generators.

play07:16

It takes the input file and then returns the preview image.

play07:19

We have one implementation that handles document files like word docs, slides,

play07:23

etc. one for videos which extracts a thumbnail from the video

play07:27

and one for images.

play07:29

But the image one can thankfully just reuse our image scaler.

play07:33

We just inject the same image scaler from before into the image preview generator.

play07:38

So we have all these preview generator classes,

play07:41

but we only need one at a time depending on which file type is being uploaded.

play07:45

The upload request shouldn't need to worry about these details.

play07:49

We’ll inject a factory which takes on the burden of deciding

play07:52

which preview generator to create.

play08:08

The factory takes in the mime type of the upload and then returns

play08:11

the right preview generator to use.

play08:15

So now the upload can simply just ask the factory for the preview generator

play08:18

and then use it.

play08:22

And lastly, we have encryption.

play08:25

We only have one implementation of encryption.

play08:27

We use AES but the key is per user and comes from our key service.

play08:33

So we inject our KeyService into the AesEncryption

play08:37

and then the AesEncryption into the storage factory.

play08:44

Then whenever we get a request for a company

play08:47

that's configured to use AWS, the storage factory

play08:50

injects the AesEncryption into the new instance of AWSstorage.

play08:55

Then the upload request gets this final

play08:57

constructed AWSstorage and simply calls upload without knowing

play09:02

that there's this whole chain of connected functionality.

play09:08

And now we have our complete architecture.

play09:12

You can see that our service is configurable from this one spot,

play09:16

which makes it super easy to change.

play09:19

Once our deal with synergy security

play09:21

goes through, it's just these two lines to change our service.

play09:25

Want to add preview support for a new file type?

play09:28

It just slots in like this.

play09:29

No access to the key server when running the attachment service

play09:33

on your local development box?

play09:35

No worries.

play09:36

We can just use a fixed key when running locally.

play09:39

Injection basically just lets us pick and choose

play09:42

from our compatible puzzle pieces and then slot them in when we need them.

play09:46

You'll notice that the time

play09:47

in which dependencies are injected varies a bit.

play09:50

A few dependencies are resolved and injected right at startup,.

play09:54

This is often the most common scenario in dependency injection.

play09:59

But some dependencies that are chosen and injected when a request comes in.

play10:03

In either case, the process is mostly the same.

play10:06

We have some code that accomplishes something.

play10:08

It lists the dependencies it needs, and so we fulfill those needs.

play10:14

You might wonder why go through the hassle of creating interfaces

play10:17

and injecting things when we only have one implementation?

play10:20

Like we only have one implementation of encryption.

play10:24

Well, there's one big thing we haven't talked about.

play10:33

If you look at our architecture here, most of our components talk to each other

play10:36

through these interfaces, which are injected in.

play10:39

This means that each of these connection points we can control what is being used.

play10:43

We've been using this to choose which implementation to use

play10:46

in our production service, but we can also make them use no implementation.

play10:50

We can use injection to inject fake or mock implementations instead,

play10:54

which basically means we can slice and dice up our architecture

play10:57

to isolate sections of code during testing.

play11:00

Let's say we want to write a test for our AWS storage class.

play11:04

We can use a fake S3

play11:06

which we run locally that pretends to be the cloud service.

play11:10

Then our test can call upload, and we can verify that a file got uploaded to S3.

play11:15

But because of the encryption, we can't actually check the content

play11:18

of the file and verify that it's correct and didn't get corrupted.

play11:22

Not to worry.

play11:23

Let's inject a mock encryption that basically just disables encryption.

play11:27

When the AWS storage class asks us to encrypt a file

play11:31

we'll just hand back a file that isn't actually encrypted.

play11:34

Now our test is able to verify fully that uploading and only uploading works

play11:39

because we've isolated it away from our dependencies.

play11:43

What if we wanted to test encryption?

play11:45

Well, we could mock out the key store to return a key that we control

play11:49

instead of going all the way to the key service.

play11:52

Or if we wanted to

play11:53

integration test both our AWS code and encryption code together.

play11:57

We could do that by injecting our fake key store into the real encryption

play12:02

and then inject the real encryption into the AWS storage.

play12:06

A key thing here is that this is easy to do.

play12:09

A natural side effect of having nice code

play12:12

is that it's easy to test without needing to hack around the code structure.

play12:16

If you find yourself asking, how can I test a private method?

play12:19

Or I need to set some internal variable in order to test.

play12:22

That's a signal that you maybe need to pull some stuff out,

play12:25

that you need to isolate some part of it by separating it and injecting

play12:29

it instead.

play12:37

I'm going to try something new with this video.

play12:40

I truly think you only learn stuff by trying stuff.

play12:43

So for those subscribed to my Patreon I'm going to start

play12:46

including some light experiments with videos.

play12:49

For this one, you can download the attachment service I wrote,

play12:52

and I want you to reconfigure the service by changing the dependency injection.

play12:57

And then you get to win some *Aesthetic* points

play12:58

if you enter the results on the site.

Rate This

5.0 / 5 (0 votes)

الوسوم ذات الصلة
Inyección de DependenciasDesarrollo de SoftwareEstructura de CódigoInterfacesS3 de AWSSFTPWebDavEscalabilidadPruebas UnitariasDiseño de SistemasSeguridad de Datos
هل تحتاج إلى تلخيص باللغة الإنجليزية؟