<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Shane Nolan</title>
    <description>The latest articles on DEV Community by Shane Nolan (@shanenullain).</description>
    <link>https://dev.to/shanenullain</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F839586%2F6aa9ac19-9577-49cc-affc-d98b1dc0983b.png</url>
      <title>DEV Community: Shane Nolan</title>
      <link>https://dev.to/shanenullain</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/shanenullain"/>
    <language>en</language>
    <item>
      <title>Decoupling Python Code: Implementing the Unit of Work and Repository Pattern</title>
      <dc:creator>Shane Nolan</dc:creator>
      <pubDate>Fri, 24 Feb 2023 15:58:19 +0000</pubDate>
      <link>https://dev.to/shanenullain/decoupling-python-code-implementing-the-unit-of-work-and-repository-pattern-43kf</link>
      <guid>https://dev.to/shanenullain/decoupling-python-code-implementing-the-unit-of-work-and-repository-pattern-43kf</guid>
      <description>&lt;p&gt;The repository and unit of work architectural patterns are utilised to create loosely coupled abstractions between the data access and business logic layers. Implementing these patterns helps insulate your application from changes, facilitates automated unit testing or test-driven development (TDD) and makes it easier to manage and maintain over time.&lt;br&gt;
When introducing an architectural pattern, a cost-benefit analysis should be performed. Repositories are an excellent example of this; they add low-level complexity but reduce high-level complexity, meaning each domain object will need its own repository class. In return, a simple interface over the data access layer is provided. A concrete implementation would look something like this:&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;center&gt;
Concrete Implementation of the Repository and Unit of Work Architectural Patterns.
&lt;/center&gt;




&lt;h2&gt;
  
  
  Repository Pattern
&lt;/h2&gt;

&lt;p&gt;The repository is a layer that sits between the business logic of the application and the data storage and is responsible for retrieving and storing data. Every repository will have two methods: add()to store an object and get_by_id(id: int) to retrieve a stored object by its ID. I prefer to use generics since implementation logic is mostly the same and prevents code duplication.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;center&gt;
Generic Repository Interface.
&lt;/center&gt;

&lt;p&gt;This implementation uses an Account model class with a username and password field. Since Account is a domain model, it requires a repository. Repositories can have a variety of unique methods to query the backend. For example, IAccountRepository has an additional method: get_all() to return all accounts.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;center&gt;
Concrete AccountRepository Implementation.
&lt;/center&gt;

&lt;p&gt;The AccountRepository is loosely coupled to SQLAlchemy's Session class through the use of &lt;a href="https://towardsdev.com/loosely-coupled-python-code-with-dependency-injection-d9adc6725d4a"&gt;Dependency Injection&lt;/a&gt; via its constructor and inherits the IAccountRepository interface. This is important because, let's say, a future feature requires a NoSQL backend database. It can be easily implemented by passing the NoSQL database context into a repository class and implementing the interface without any change to high-level modules.&lt;/p&gt;

&lt;h2&gt;
  
  
  Unit of Work Pattern
&lt;/h2&gt;

&lt;p&gt;The unit of work implementation is responsible for managing the changes made to a set of objects. It tracks the changes made to these objects and, when asked, can commit or roll back the changes as a single transaction. Put simply; it ensures that multiple repositories share a single database context. That way, when a unit of work is committed, all related changes will be coordinated and saved.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;center&gt;
Interface for the UnitOfWork Pattern.
&lt;/center&gt;

&lt;p&gt;The IUnitOfWork interface provides access to the AccountsRepository through its public account attribute. The &lt;strong&gt;enter&lt;/strong&gt; magic method retrieves a session, normally from a session factory. For example, SQLAlchemy has sessionmaker. The &lt;strong&gt;exit&lt;/strong&gt; magic method handles rolling back any changes and closing the session.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;


&lt;center&gt;
Concrete UnitOfWork Implementation.
&lt;/center&gt;

&lt;p&gt;For demonstration purposes, let's assume there's a requirement to get the sum of all account balances. This can be easily implemented by using the UnitOfWork class, calling the AccountRepository.get_all() method and adding each account's balance together.&lt;/p&gt;


&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
 

&lt;center&gt;
Implement to get the Sum Of All Account Balances.
&lt;/center&gt;

&lt;p&gt;In summary, the unit of work and repository design pattern are powerful techniques for decoupling code in Python. These patterns provide a modular, reusable approach to organizing code that promotes maintainability and testability and helps developers build more robust and flexible applications by separating concerns. Thus, these patterns are excellent choices for anyone looking to write clean, decoupled and maintainable code in Python.&lt;/p&gt;

&lt;p&gt;Thanks for reading 🙌. You can find me on &lt;a href="https://www.linkedin.com/in/shanenullain/"&gt;Linkedin&lt;/a&gt; or &lt;a href="https://github.com/ShaneNolan"&gt;Github&lt;/a&gt; if you want to connect with me.&lt;/p&gt;




&lt;p&gt;References:&lt;br&gt;
&lt;a href="https://amzn.to/3I9GL1U"&gt;Architecture Patterns with Python: Enabling Test-Driven Development, Domain-Driven Design, and Event-Driven Microservices&lt;/a&gt;&lt;br&gt;
&lt;a href="https://learn.microsoft.com/en-us/aspnet/mvc/overview/older-versions/getting-started-with-ef-5-using-mvc-4/implementing-the-repository-and-unit-of-work-patterns-in-an-asp-net-mvc-application"&gt;Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>tutorial</category>
      <category>python</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Loosely coupled Python code with Dependency Injection</title>
      <dc:creator>Shane Nolan</dc:creator>
      <pubDate>Wed, 09 Nov 2022 23:55:09 +0000</pubDate>
      <link>https://dev.to/shanenullain/loosely-coupled-python-code-with-dependency-injection-1lep</link>
      <guid>https://dev.to/shanenullain/loosely-coupled-python-code-with-dependency-injection-1lep</guid>
      <description>&lt;h2&gt;
  
  
  Loosely coupled Python code with Dependency Injection
&lt;/h2&gt;

&lt;p&gt;Software has to be flexible in order to respond to change. Dependency injection is a technique for managing the dependencies between software components. It is a design pattern that uses &lt;a href="https://en.wikipedia.org/wiki/Inversion_of_control" rel="noopener noreferrer"&gt;inversion of control&lt;/a&gt; to provide the ability to swap out components for testing or other purposes without changing any other part of the system.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A558ZzT23dBI2a7W9GDR08A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A558ZzT23dBI2a7W9GDR08A.png" alt="Dependency Injection in Python"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The main idea behind dependency injection is to pass the responsibility for providing services from constructor functions or direct instantiation methods onto other objects. In other words, an object is given its dependencies instead of creating them. This way, if we want to add new features, we don’t have to change the existing code but instead, pass new dependencies into it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating Abstractions with Interfaces
&lt;/h2&gt;

&lt;p&gt;There are three steps in writing loosely coupled Python code with dependency injection. The first step is to identify what dependencies the code needs, the second step is to create interfaces for each dependency, and the third step is to pass them into the dependent object through its constructor or method parameters.&lt;/p&gt;

&lt;p&gt;Recently, I implemented functionality that required a byte encoder and decoder to manipulate business data (&lt;em&gt;I’ve simplified its implementation for readability purposes&lt;/em&gt;). I abstracted out their responsibilities to interfaces. Python doesn’t have an interface keyword like Golang, but you can replicate interface functionality with the &lt;a href="https://docs.python.org/3/library/abc.html" rel="noopener noreferrer"&gt;ABC&lt;/a&gt; library.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ApE7ljP47xVPUWQF8ZHQY9A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ApE7ljP47xVPUWQF8ZHQY9A.png" alt="Interfaces for encoder and decoder."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Focusing on the IPacketEncoder interface, a concrete encoder class must implement it. The initial business requirements required all types to be encoded and strings to be padded with their length. Luckily, Python provides the &lt;a href="https://docs.python.org/3/library/struct.html" rel="noopener noreferrer"&gt;struct&lt;/a&gt; library to do most of the hard work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A6npvkUPlfUWH_aQaeK4w4Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A6npvkUPlfUWH_aQaeK4w4Q.png" alt="PaddedPacketEncoder concrete class."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing Dependency Injection
&lt;/h2&gt;

&lt;p&gt;The encode_name function is a simple implementation for creating an encoded payload with the specified name. It takes an IPacketEncoder object and a string as parameters.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AubtImmLLVUTSG7RdU2JXpQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AubtImmLLVUTSG7RdU2JXpQ.png" alt="PaddedPacketEncoder instance passed into encode_name function."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The two key implementation details are using the IPacketEncoder interface instead of the PaddedPacketEncoder concrete class and encoder is an argument rather than being initialized inside the function. &lt;strong&gt;This is dependency injection.&lt;/strong&gt; Because IPacketEncoder is passed in, it can be easily extended, changed or provided with a &lt;a href="https://en.wikipedia.org/wiki/Method_stub" rel="noopener noreferrer"&gt;stub&lt;/a&gt;, thus keeping the system loosely coupled.&lt;/p&gt;

&lt;p&gt;A few weeks later, there was a new requirement for an encoder to handle null terminated encodings. Luckily, due to the existing implementation, it can be easily implemented.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AjN4Y6XkS0YblS4PzPlFWCA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AjN4Y6XkS0YblS4PzPlFWCA.png" alt="NullTerminatedPacketEncoder concrete class."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;NullTerminatedPacketEncoder essentially adds NULL_BYTE after each encoded string. Going back to the encode_name function, an instance of NullTerminatedPacketEncoder is a valid encoder argument since NullTerminatedPacketEncoder implements the IPacketEncoder interface similarly to PaddedPacketEncoder.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A9r1M-qsPxNlV9zdiEA-AVg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A9r1M-qsPxNlV9zdiEA-AVg.png" alt="NullTerminatedPacketEncoder passed into encode_name function."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If dependency injection wasn’t used here, it could result in code that is tightly coupled and difficult to change, for example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AdqHXMd9IQDXIQ6zk9qFJDA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AdqHXMd9IQDXIQ6zk9qFJDA.png" alt="Coupled encoding Python code."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If a new encoder is required, the encode_name function will have to be changed almost entirely along with its tests, extending delivery times. What’s worse, it could result in hidden side effects, especially if the original developer is no longer available.&lt;/p&gt;

&lt;p&gt;To conclude, I’ll provide a less simplistic example using this technique. SocketService is responsible for decoding an operation code, calling its relevant handler and returning its result. All of its argument types are interface abstractions, including its constructor. The CLI is responsible for determining which encoder to use, i.e. NullTerminated or Padded, and passing its instance down to the SocketService class.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AzlPn_b4v3cB-wjlhtbLIVQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AzlPn_b4v3cB-wjlhtbLIVQ.png" alt="SocketService utilising dependency injection."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;As projects continue to grow, its recommended to utilise a dependency injection framework to “inject” these dependencies automatically, such as &lt;a href="https://github.com/ets-labs/python-dependency-injector" rel="noopener noreferrer"&gt;Dependency Injector&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Hopefully, this demonstrates how to write loosely coupled Python code with dependency injection. Many Python developers dislike dependency injection because they feel it's not “pythonic”, but I would argue that its benefits can’t be discredited, especially when it's present in so many other programming languages.&lt;/p&gt;

&lt;p&gt;Thanks for reading 😊. If you would like to connect with me, you can find me on &lt;a href="https://www.linkedin.com/in/shanenullain/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; or &lt;a href="https://github.com/ShaneNolan" rel="noopener noreferrer"&gt;Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>architecture</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Creating an HTTPS Lambda Endpoint without API Gateway</title>
      <dc:creator>Shane Nolan</dc:creator>
      <pubDate>Fri, 15 Apr 2022 19:32:57 +0000</pubDate>
      <link>https://dev.to/shanenullain/creating-an-https-lambda-endpoint-without-api-gateway-4nnh</link>
      <guid>https://dev.to/shanenullain/creating-an-https-lambda-endpoint-without-api-gateway-4nnh</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PFzERDxJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A2ITtm6wPmCIykfN-CHun_g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PFzERDxJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A2ITtm6wPmCIykfN-CHun_g.png" alt="" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Amazon Web Services (AWS) recently announced &lt;a href="https://aws.amazon.com/about-aws/whats-new/2022/04/aws-lambda-function-urls-built-in-https-endpoints/"&gt;Function URLs&lt;/a&gt;, a new in-built feature that allows you to invoke your functions through an HTTPS endpoint. By default, the endpoint is secure using &lt;a href="https://aws.amazon.com/iam/"&gt;AWS Identity Access Management&lt;/a&gt; (IAM) but you can allow public access with optional Cross-Origin Resource Sharing (CORS) configurations and/or custom authorisation logic. Originally, if you wanted to invoke a Lambda function publicly via HTTPS you would need to set up and configure &lt;a href="https://aws.amazon.com/api-gateway/"&gt;AWS API Gateway&lt;/a&gt; or &lt;a href="https://aws.amazon.com/elasticloadbalancing/"&gt;AWS Elastic Load Balancing&lt;/a&gt; and pay additional fees once you exceeded their free tier. Fortunately, Function URLs don't incur an additional cost 🎉. I’d recommend you continue to use these services if you’re building a serverless REST API or require additional features such as request-response &lt;a href="https://docs.aws.amazon.com/apigateway/latest/developerguide/rest-api-data-transformations.html"&gt;transformations&lt;/a&gt;. For small use-cases such as webhooks or determining the price of a cryptocurrency, Function URLs are more suited.&lt;/p&gt;

&lt;p&gt;This blog post will demonstrate how to create an HTTPS Lambda endpoint using Function URLs, &lt;a href="https://python.org/"&gt;Python&lt;/a&gt; and &lt;a href="https://www.terraform.io/"&gt;Terraform&lt;/a&gt;, an open-source infrastructure as code tool. If you’d rather not use Terraform, Function URLs can be created directly via the AWS user interface (UI). You can follow the official AWS guide &lt;a href="https://aws.amazon.com/blogs/aws/announcing-aws-lambda-function-urls-built-in-https-endpoints-for-single-function-microservices/"&gt;here&lt;/a&gt;. You can use any compatible programming language with AWS Lambda for this demonstration since the principles are the same. You can view the project's source code on &lt;a href="https://github.com/ShaneNolan/lambda_function_url_terraform"&gt;Github&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Python Lambda Function
&lt;/h2&gt;

&lt;p&gt;First, create a Python project with main.py being the entry point for Lambda. I recommend using &lt;a href="https://medium.com/@shanenullain/creating-a-modern-python-development-environment-3d383c944877"&gt;this modern Python development environment&lt;/a&gt; for a more straightforward implementation but your own will suffice. This project will use the Python version 3.9.0 . You can view a list of supported versions &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/lambda-runtimes.html"&gt;here&lt;/a&gt;. Your project directory structure should replicate this:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── .editorconfig
├── CHANGELOG.md
├── README.md
├── lambda_function_url_terraform
│   ├── __init__.py
│   └── main.py
├── poetry.lock
├── pyproject.toml
├── setup.cfg
└── tests
    ├── __init__.py
    └── test_main.py

2 directories, 10 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;For this example, the main.py Lambda handler will return a JSON object with a body containing a message and status code of 200.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--7tcnO9bA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2948/1%2ADjbjR52dDmAku0NTuRt9NA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--7tcnO9bA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2948/1%2ADjbjR52dDmAku0NTuRt9NA.png" alt="Python main.py Lambda Handler" width="880" height="346"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To ensure the Lambda handler is working as expected write a unit test in tests/test_main.py to validate its response.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m6EnMcfI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2608/1%2Aao3oJTFk5gyHCUB-xnV-fw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m6EnMcfI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2608/1%2Aao3oJTFk5gyHCUB-xnV-fw.png" alt="Unit test to validate the Lambda handler's response." width="880" height="366"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  Terraform Deployment
&lt;/h2&gt;

&lt;p&gt;If you don’t have Terraform already installed, you can follow the &lt;a href="http://HashiCorp%20distributes%20Terraform%20as%20a%20binary%20package.%20You%20can%20also%20install%20Terraform%20using%20popular%20package%20managers."&gt;official installation documentation.&lt;/a&gt; Once installed, confirm the installation was successful by executing:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YvrqH0La--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AlL0YsyFAvtSDuAnrkzPj8Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YvrqH0La--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AlL0YsyFAvtSDuAnrkzPj8Q.png" alt="Confirmation of Terraforms installation." width="880" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;First, create the required Terraform deployment file main.tf at the top level of your Python project. Declare 1.0.0 as the Terraform version and 4.9.0 as the Hashicorp AWS provider version since that's when Function URLs functionality was implemented. You can review the merge request &lt;a href="https://github.com/hashicorp/terraform-provider-aws/pull/24053"&gt;here&lt;/a&gt;. Next, declare the AWS region, for example eu-west-1 . Once declared main.tf should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--u7qZO1Ay--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AgSyNkAXEbqHR-YL57xesZA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--u7qZO1Ay--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AgSyNkAXEbqHR-YL57xesZA.png" alt="Initial Terraform deployment code." width="614" height="658"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Before the Lambda function can be implemented, an IAM role with a &lt;a href="https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles_terms-and-concepts.html"&gt;trust policy&lt;/a&gt; needs to be created. In this case, the AWS Lambda service will be trusted and allowed to call the AWS Security Token Service (STS) AssumeRole action. Append the IAM role resource to main.tf file. Its implementation should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--49v8saA3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AwAQoksZCoNr3-VEZnHaTKw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--49v8saA3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AwAQoksZCoNr3-VEZnHaTKw.png" alt="Lambda IAM role with required trust policy." width="832" height="766"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Execute the following commands to create a zip file called package.zip containing the projects source code and its requirements for Lambda:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install zip package to zip files/folders:
sudo apt-get install zip

poetry build; 
poetry run pip install --upgrade -t package dist/*.whl;
(cd package; zip -r ../package.zip . -x '*.pyc';)

# Pip installation without Poetry or zip:
pip freeze &amp;gt; requirements.txt
pip install -r requirements.txt -t package
# zip the package folder.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Once packaged the Lambda function is ready to be implemented. Depending on your setup you may need to modify the following attributes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;runtime depending on your Python version.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;function_name the name you want to give your Lambda function.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;handler the path to your &lt;a href="https://docs.aws.amazon.com/lambda/latest/dg/python-handler.html"&gt;Lambda handler&lt;/a&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The Lambda function resource should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uRicpH2D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2608/1%2AeNIPsJGBtjMR6SWe3TO80w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uRicpH2D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2608/1%2AeNIPsJGBtjMR6SWe3TO80w.png" alt="Terraform AWS Lambda function resource code." width="880" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The filename attribute is the filename along with the extension of our packaged project. Similarly, the source_code_hash attribute is used to determine if the packaged project has been updated, i.e. a code change. The role attribute is a reference to the previously implemented IAM role. Append the Lambda function to main.tf .&lt;/p&gt;

&lt;p&gt;Lastly, create the Function URL resource and save the generated URL.The authorization_type is set to NONE , meaning it allows public access. You have the option of restricting access to authenticated IAM users only, as well as CORS configuration capabilities. You can read about them &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function_url"&gt;here&lt;/a&gt;. The Lambda Function URL resource should look like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZNzUU-oM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2508/1%2ATKRTthXAbAvDtv3twMRMSw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZNzUU-oM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2508/1%2ATKRTthXAbAvDtv3twMRMSw.png" alt="Terraform AWS Lambda Function URL resource code." width="880" height="380"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The output resource function_url saves the generated Function URL. Append both the Function URL and output resource to main.tf . With all the Terraform components together, main.tf should replicate this:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Deploying with Terraform requires only a single command after the infrastructure is coded but first, you need to initialise Terraform inside of the project by executing terraform init . Additionally, set your AWS_ACCESS_KEY_ID , AWS_SECRET_ACCESS_KEY and AWS_REGION via the command line. If you’re unfamiliar with configuring your AWS credentials you can read more about it on the official &lt;a href="https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-files.html"&gt;AWS&lt;/a&gt; and &lt;a href="https://registry.terraform.io/providers/hashicorp/aws/latest/docs#environment-variables"&gt;Terraform&lt;/a&gt; documentation. &lt;br&gt;&lt;br&gt;
Once initialised, deploy your Lambda function using terraform apply and accept the confirmation of the required changes. After deployment, it will output the Lambda Function URL 🎉.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IBTUuQ61--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/3398/1%2AydC_2cJbnRo65TM9Mver7Q.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IBTUuQ61--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/3398/1%2AydC_2cJbnRo65TM9Mver7Q.gif" alt="Terraform AWS Lambda Function URL deployment." width="880" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Test the public endpoint by either opening the URL in a browser or using an API testing tool such as &lt;a href="https://httpie.io/"&gt;httpie&lt;/a&gt;. The below example uses Terraform to retrieve the generated Function URL via terraform output and a GET request is submitted to the URL via httpie.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6zuIUcMO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/3398/1%2AGNhtY0Hsrst1BEGugU-ILA.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6zuIUcMO--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://cdn-images-1.medium.com/max/3398/1%2AGNhtY0Hsrst1BEGugU-ILA.gif" alt="httpie GET request to the Lambda Function URL." width="880" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>aws</category>
      <category>terraform</category>
      <category>programming</category>
    </item>
    <item>
      <title>Developing my first financial app using React Native, Redux, Figma and FastAPI</title>
      <dc:creator>Shane Nolan</dc:creator>
      <pubDate>Tue, 12 Apr 2022 15:57:09 +0000</pubDate>
      <link>https://dev.to/shanenullain/developing-my-first-financial-app-using-react-native-redux-figma-and-fastapi-1e56</link>
      <guid>https://dev.to/shanenullain/developing-my-first-financial-app-using-react-native-redux-figma-and-fastapi-1e56</guid>
      <description>&lt;p&gt;Nowadays it's normal to have multiple bank accounts, especially with apps such as Revolut becoming a huge success in Ireland. The problem my friends and I find with having multiple bank accounts is, it’s difficult to easily manage our finances. I decided to resolve this problem by designing and developing my first app called Bank Balance, which will instantly tell me my balance across multiple banks, including my savings.&lt;/p&gt;

&lt;p&gt;The tech stack I decided on using was Expo React-Native for its cross-platform functionalities, Redux for state management and FastAPI for the Orchestration Layer. Figma was used for UI/UX prototyping. I had no previous experience using any of these technologies besides FastAPI but I’m always up for the challenge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wTWtgJnn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AnRzUmQHiUHZ4VHeNcaRiNw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wTWtgJnn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AnRzUmQHiUHZ4VHeNcaRiNw.png" alt="Initial Figma Prototype for Bank Balance" width="750" height="1624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dp6DqRUC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AeXCcZ6K0Ge3MmbcsQ_FzGQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dp6DqRUC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AeXCcZ6K0Ge3MmbcsQ_FzGQ.png" alt="Initial Figma Prototype for Bank Balance" width="750" height="1624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The initial prototype was designed using Figma and has two screens. The login screen has a single button that starts the authorisation process and upon successful authorisation, the home screen is displayed with the user's bank accounts and their corresponding balances.&lt;/p&gt;

&lt;p&gt;Before I began App development I needed to create an Orchestration Layer using FastAPI (a modern, fast, web framework for building APIs with Python) to secure my secret keys provided by TrueLayer since apps can be reverse-engineered. Bank Balance uses TrueLayer to access users' financial data securely since TrueLayer adheres to all the Open Banking regulations. Access tokens provided after authentication are stored securely via Keychain on iOS and Keystore on Android.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5CJ1nlUI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AYh3KaxgW8J2BpnFeU2ECBw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5CJ1nlUI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AYh3KaxgW8J2BpnFeU2ECBw.png" alt="Python Orchestration Layer" width="597" height="1402"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Orchestration Layer has two endpoints, /exchange and /refresh . The exchange endpoint returns an access token to the requested bank account and refresh renews the access token once it has expired. Each bank has a different threshold for how long their access tokens are valid.&lt;/p&gt;

&lt;p&gt;By default, iPhone will block any request that is not using SSL (&lt;a href="https://developer.apple.com/forums/thread/3544"&gt;https://developer.apple.com/forums/thread/3544&lt;/a&gt;), meaning the App was prevented from making requests to the Orchestration Layer. Therefore, I generated an SSL certificate to provide the layer using &lt;a href="https://github.com/FiloSottile/mkcert"&gt;mkcert&lt;/a&gt;, a simple tool for making locally-trusted development certificates.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Zf9MXirg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2APvLsY1D7UQGQ1s9qyFjcZw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Zf9MXirg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2APvLsY1D7UQGQ1s9qyFjcZw.png" alt="" width="732" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It's important to retrieve and create the SSL certificate for your IPv4 Address because that's the IP address the App will use to access the Orchestration Layer. Additionally, the mkcert root certificate needs to be installed and trusted. The cert can be located by running mkcert -CAROOT .&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--j78Yh3mW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AtpYbzOC8Z_EzSKkqvRJJaA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--j78Yh3mW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AtpYbzOC8Z_EzSKkqvRJJaA.png" alt="Orchestration Deployment Command for FastApi with SSL." width="755" height="288"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After the Orchestration Layer was deployed I implemented logic to communicate with True Layers APIs and the Orchestration Layer. Using createSlice a function provided by the @reduxjs/toolkit library, I created two reducers, token and account . createSlice hides some of Redux’s complexity and removes boilerplate code. The token reducer is responsible for handling tokens provided by the orchestration layer and account is responsible for handling account information such as bank balance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ItwyLz-U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Arm5nUHg1Uj76ViXHJOjVpw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ItwyLz-U--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Arm5nUHg1Uj76ViXHJOjVpw.png" alt="Token Reducer Code Snippet" width="873" height="1330"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The fetchAccessToken function uses createAsyncThunk to return a &lt;a href="https://redux.js.org/usage/writing-logic-thunks"&gt;thunk action creator&lt;/a&gt; meaning “a piece of code that does some delayed work” wrapped in a promise, enabling chaining through the use of .then(). The token reducer uses the expo-secure-store library to securely store token information and the account reducer uses the@react-native-async-storage/async-storage library to store account information.&lt;/p&gt;

&lt;p&gt;Implementing the logic screen was rather difficult because Expo’s authentication library expo-auth-session would not trigger its linking callback once redirected by the testing TrueLayer environment (it would trigger in the sandbox TrueLayer environment since the app never opened another app i.e. Revolut). Therefore, I created a customisable authorisation component with callback linking functionality.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--AxvtI3YH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AzMwKsttw51hIyBeP5o2Mlw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--AxvtI3YH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AzMwKsttw51hIyBeP5o2Mlw.png" alt="Customizable Bank Authorization Component Code" width="748" height="1181"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The CSS style is passed into the authorisation component via the prop buttonStyle and its children are also rendered. For example, the login screen utilises the authorisation component like so:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dAHsHLMh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aws35LuIum1B3R-qMtXIc1w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dAHsHLMh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aws35LuIum1B3R-qMtXIc1w.png" alt="Login Screen Authorisation Configuration Code Snippet" width="732" height="343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XitLk-_5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AFhl4GehWkxlHfOF9ciCbmA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XitLk-_5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AFhl4GehWkxlHfOF9ciCbmA.png" alt="Final Figma Prototype" width="750" height="1624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--45-3BChE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AjkgjhBR3xU_D9YpP_ktwiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--45-3BChE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AjkgjhBR3xU_D9YpP_ktwiw.png" alt="Final Figma Prototype" width="750" height="1624"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The home screen was the last to implement. I decided to give the initial prototype a slight revamp to look more like a balance sheet. Displaying the relevant accounts required the chaining of API requests and transforming. The API chaining worked as follows, for each access token (bank account), retrieve the permitted accounts and for each permitted account retrieve its bank balance. Then, merge each bank account with its relevant bank balance and transform the required information i.e. convert balances into local currency.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vFMA1YCt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AXJVgyT8NFw8B_asDxKFwgA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vFMA1YCt--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AXJVgyT8NFw8B_asDxKFwgA.png" alt="Code Snippet for Chaining API Requests and Transformations." width="787" height="1348"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Up until now the user only had the option to link one bank account via the login screen. I added a plus button to the top right corner that implements the authorisation used previously for the login screen, reusing functionality, adhering to the DRY (&lt;em&gt;do not repeat yourself&lt;/em&gt;) software development principle, and saving development time but increasing complexity slightly.&lt;/p&gt;

&lt;p&gt;You can view a video demonstration &lt;a href="https://vimeo.com/681477685"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To conclude, this project was a lot of fun but I decided not to deploy it because of the costs involved (Apple Developer Program Fee and Orchestration Layer API fees). I had additional ideas/features for the next iteration which were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Remove a linked bank account.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Insights such as daily spending across accounts, forecasted spending, etc.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;User profiles.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Link multiple bank accounts upon initial login.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Working with all these new technologies was a lot of fun but I would use Typescript for future apps since code readability and maintainability was a concern as the code base grew. Older code examples of Redux had a lot of repetitive code but the @reduxjs/toolkit library removes a significant amount of it. I found Redux to be overkill for this app and unnecessary complexity but if I were to continue with development it would become extremely beneficial since passing props to children would become a nightmare to maintain. Lastly, I found Expo to be a great solution for rapid development on both mobile platforms IOS/Android.&lt;/p&gt;

&lt;p&gt;Thank you for reading and if you would like to connect with me you can find me on &lt;a href="https://www.linkedin.com/in/shanenullain/"&gt;Linkedin&lt;/a&gt; or &lt;a href="https://github.com/ShaneNolan"&gt;Github&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>reactnative</category>
      <category>showdev</category>
      <category>programming</category>
    </item>
    <item>
      <title>Abstract Factory in Python with Generic Typing</title>
      <dc:creator>Shane Nolan</dc:creator>
      <pubDate>Tue, 12 Apr 2022 15:52:09 +0000</pubDate>
      <link>https://dev.to/shanenullain/abstract-factory-in-python-with-generic-typing-257a</link>
      <guid>https://dev.to/shanenullain/abstract-factory-in-python-with-generic-typing-257a</guid>
      <description>&lt;p&gt;I found it difficult to find cleanly typed Python code that implemented the abstract factory creational design pattern. Therefore, this is my implementation of a typed abstract factory in Python.&lt;/p&gt;

&lt;p&gt;The following code uses &lt;a href="https://docs.python.org/3.8/library/typing.html"&gt;Python&lt;/a&gt; 3.8 and &lt;a href="http://mypy-lang.org/"&gt;Mypy&lt;/a&gt; 0.91.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation
&lt;/h2&gt;

&lt;p&gt;The abstract factory we are going to implement is a game factory that creates players and items. For this example, we are going to implement a Rogue player which requires an attack greater than 5 to successfully hit and a Sword item that has 10 damage.&lt;/p&gt;

&lt;p&gt;The Unified Model Language (UML) diagram at the start of this article might be a bit scary to look at it if you’re not familiar with UML but let's start with the basics. Player is an interface (Python doesn't exactly have interfaces but you can achieve the same result using an abstract class, you’ll see an example below) that contains a single method definition. Any class that implements the Player interface must implement the attack method that matches the signature, i.e.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jXkvgP-1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A79GyJozv1teZG_3v_KQTKQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jXkvgP-1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A79GyJozv1teZG_3v_KQTKQ.png" alt="Player interface attack method" width="812" height="260"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Therefore, as shown in the UML diagram the Rogue class implements attack. If attack wasn’t implemented a TypeError would be thrown. Let’s implement Rogue and Sword:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Gvh9Uu3d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AXtwB4y4eRkhk5Ij-m_eELg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Gvh9Uu3d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AXtwB4y4eRkhk5Ij-m_eELg.png" alt="Rogue and Sword implementation of their corresponding interfaces." width="880" height="908"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next, we need to create two factories for Player and Item. The factory design pattern has many benefits but my personal favourite benefit is &lt;a href="https://realpython.com/factory-method-python/#introducing-factory-method"&gt;it separates the process of creating an object from the code that depends on the interface of the object.&lt;/a&gt; Making the code more extensible and maintainable while improving readability. A lot of articles regarding the factory design pattern use a lot of jargon but in reality it is quite simple, let me show you.&lt;/p&gt;

&lt;p&gt;In our UML diagram both the PlayerFactory and ItemFactory implement the AbstractEntityFactory interface, specifically the *generic *createmethod.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1mdiPKVE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AxNMGg0BJXA9gp-maXwEeww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1mdiPKVE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AxNMGg0BJXA9gp-maXwEeww.png" alt="Generic interface method for AbstractEntityFactory" width="762" height="332"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This method might look confusing to those who are not familiar with &lt;a href="https://docs.python.org/3.8/library/typing.html#generics"&gt;generics &lt;/a&gt;(especially Python developers since duck typing essentially allows everything to be &lt;em&gt;“generic”&lt;/em&gt;). Generic methods allow for a single function declaration to be called with different arguments or different return types. Let me show you with an example:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WlgwIz_v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2232/1%2AuUYzF6m8V_egpXYvXmx6Gg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WlgwIz_v--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2232/1%2AuUYzF6m8V_egpXYvXmx6Gg.png" alt="Typed generic abstract factory in Python" width="880" height="886"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AbstractEntityFactory is generic because it inherits Generic[T] and method create returns T . &lt;br&gt;
ItemFactory and PlayerFactory inherit AbstractEntityFactory but look closely, it declares its generic type to be Item for ItemFactory nd Player for PlayerFactory.&lt;/p&gt;

&lt;p&gt;Lastly, we need to create our “factory of factories”, GameFactory. GameFactory encapsulates PlayerFactory and ItemFactory without specifying their concrete classes (what the abstract factory design pattern is meant to do). It sounds more complicated than it looks:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9bQZRaPb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2504/1%2Az_oqA-eHBlZXHuHTsqjlGw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9bQZRaPb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2504/1%2Az_oqA-eHBlZXHuHTsqjlGw.png" alt="GameFactory — Typed abstract factory in Python" width="880" height="436"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Using Mypy we validated our Python code is typed correctly 🙏.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ev-oF80w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AVoFpzGxkIYvVj-OC8vUucA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ev-oF80w--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AVoFpzGxkIYvVj-OC8vUucA.png" alt="Mypy type checking for GameFactory implementation" width="864" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The code snippet directly below is an example of the GameFactory creating a Sword and a Rogue, getting the sword damage and attacking with the rogue.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ym0q3oV1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2940/1%2AYG1khuhkRZ3hV3_J6GsYiw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ym0q3oV1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2940/1%2AYG1khuhkRZ3hV3_J6GsYiw.png" alt="Usage example of GameFactory" width="880" height="285"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;That’s it! You’ve successfully implemented a typed version of the abstract factory in Python while adhering to the &lt;a href="https://en.wikipedia.org/wiki/SOLID"&gt;SOLID design principles&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>architecture</category>
    </item>
    <item>
      <title>Creating A Modern Python Development Environment</title>
      <dc:creator>Shane Nolan</dc:creator>
      <pubDate>Tue, 12 Apr 2022 12:59:54 +0000</pubDate>
      <link>https://dev.to/shanenullain/creating-a-modern-python-development-environment-4gd4</link>
      <guid>https://dev.to/shanenullain/creating-a-modern-python-development-environment-4gd4</guid>
      <description>&lt;p&gt;Being a Python developer for the past few years I’ve gathered a list of my favourite packages/tools that I use in almost every project. Developing is a team effort and at some point, someone is going to have to read and/or alter the code you have written. If the code is poorly implemented and the developer has a new feature or bug fix to implement it will likely lead to additional technical debt. Therefore, I like to enforce developers (*including myself *😉) to produce code that is tested, maintainable, readable and most importantly consistent, otherwise, it's rejected. This results in the software development process going more smoothly since they will be working on the same dependable code.&lt;/p&gt;

&lt;p&gt;This blog post demonstrates how I set up and configure my Python development environment using pyenv and Poetry, on both Unix and Windows systems to produce the same consistent code, helping prevent technical debt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installing pyenv 🐍
&lt;/h2&gt;

&lt;p&gt;Downloading and installing Python from the official binary limits you to one specific Python version, which isn’t great if you’re working on multiple projects with different Python versions. Therefore, it's better to use &lt;a href="https://github.com/pyenv/pyenv" rel="noopener noreferrer"&gt;pyenv&lt;/a&gt;, a tool that lets you easily switch between multiple versions of Python.&lt;/p&gt;

&lt;h3&gt;
  
  
  Windows Installation
&lt;/h3&gt;

&lt;p&gt;For Windows users, I recommend you install &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/install" rel="noopener noreferrer"&gt;WSL2&lt;/a&gt;, a &lt;a href="https://docs.microsoft.com/en-us/windows/wsl/about#:~:text=The%20Windows%20Subsystem%20for%20Linux%20lets%20developers%20run%20a%20GNU/Linux%20environment%20%2D%2D%20including%20most%20command%2Dline%20tools%2C%20utilities%2C%20and%20applications%20%2D%2D%20directly%20on%20Windows%2C%20unmodified%2C%20without%20the%20overhead%20of%20a%20traditional%20virtual%20machine%20or%20dualboot%20setup." rel="noopener noreferrer"&gt;Windows Subsystem that lets developers run a Linux environment without the overhead of a traditional virtual machine or dual-boot setup&lt;/a&gt;. You can install WSL2 by executing the following command in either PowerShell or Command Prompt:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AYLKypOE2mFwP2NCTaLXdVQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AYLKypOE2mFwP2NCTaLXdVQ.png" alt="WSL2 installation command."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you don’t want to use WSL2 you can install &lt;a href="https://github.com/pyenv-win/pyenv-win" rel="noopener noreferrer"&gt;pyenv-win&lt;/a&gt;, &lt;em&gt;a less modern approach *and skip to the **Set Python Version with pyenv&lt;/em&gt;* section.&lt;/p&gt;

&lt;p&gt;After installation search for Ubuntu on Windows (WSL terminal) and open it. It will present you with a bash shell and request you provide a username and password. Once they have been set your terminal is ready for tinkering 🔨 !&lt;/p&gt;

&lt;p&gt;Before installing pyenv you’re going to need to update your environment and install a few build dependencies *(if you don't already have them). *Open your terminal and execute the following commands:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; sudo apt update &amp;amp;&amp;amp; sudo apt upgrade
&amp;gt; sudo apt install -y build-essential git curl libexpat1-dev libssl-dev zlib1g-dev libncurses5-dev libbz2-dev liblzma-dev libsqlite3-dev libffi-dev tcl-dev linux-headers-generic libgdbm-dev libreadline-dev tk tk-dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;pyenv is now ready to be installed and configured &lt;em&gt;(tell your terminal where pyenv is):&lt;/em&gt;&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; curl https://pyenv.run | bash

&amp;gt; echo '\nexport PATH="$HOME/.pyenv/bin:$PATH"' &amp;gt;&amp;gt; ~/.bashrc
&amp;gt; echo '\neval "$(pyenv init -)"' &amp;gt;&amp;gt; ~/.bashrc
&amp;gt; echo '\neval "$(pyenv init --path)"' &amp;gt;&amp;gt; ~/.bashrc

&amp;gt; source ~/.bashrc

# Confirm successful installation:
&amp;gt; pyenv --version
pyenv 2.2.5 # Your version will likely be newer.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Set Python Version with pyenv
&lt;/h3&gt;

&lt;p&gt;Once pyenv is installed successfully, set your global Python version using the following commands:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Install the required Python version:
&amp;gt; pyenv install 3.9.0

# Refresh pyenv since you installed a new Python version:
&amp;gt; pyenv rehash

# Set your global Python version:
&amp;gt; pyenv global 3.9.0

# You can also set the local Python version, i.e. for a project:
# &amp;gt; pyenv local 3.9.0

# Confirm Python version:
&amp;gt; pyenv version
3.9.0 (set by /home/wsl/.pyenv/version)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;If you require another version of Python you can simply execute the same commands with a different version number 🤗.&lt;/p&gt;
&lt;h2&gt;
  
  
  Installing Poetry 📜
&lt;/h2&gt;

&lt;p&gt;Packaging systems and dependency management in Python are rather convoluted and hard to understand for newcomers. Even for seasoned developers, it might be cumbersome at times to create all files needed in a Python project. &lt;a href="https://github.com/python-poetry/poetry" rel="noopener noreferrer"&gt;Poetry&lt;/a&gt; helps you declare, manage and install dependencies of Python projects, ensuring you have the right stack everywhere. It automatically creates isolated environments for each project, preventing modifications to dependencies in another project.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; pyenv shell 3.9.0

&amp;gt; curl -sSL https://raw.githubusercontent.com/python-poetry/poetry/master/get-poetry.py | python -

&amp;gt; source ~/.bashrc

# Confirm installation was successful:
&amp;gt; poetry --version
Poetry version 1.1.13 # Your version will likely be newer.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  EditorConfig
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://editorconfig.org/" rel="noopener noreferrer"&gt;EditorConfig&lt;/a&gt; helps maintain consistent coding styles for multiple developers working on the same project across various editors and integrated development environments (IDE). It works by reading the .editorconfig configuration file provided at the top level of a project. &lt;a href="https://editorconfig.org/#pre-installed" rel="noopener noreferrer"&gt;Most IDEs have built-in support&lt;/a&gt; but this is a list of &lt;a href="https://editorconfig.org/#download" rel="noopener noreferrer"&gt;IDEs/editors that require a plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;This is the standard .editorconfig file that I use in all my Python projects:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
Your environment is now ready to create a modern Python project 🥳.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating and Configuring a Python Project ⚙️
&lt;/h2&gt;

&lt;p&gt;The following instructs how to *manually *create and configure a Python project using pyenv and Poetry.&lt;/p&gt;

&lt;p&gt;To create a new Python project you need to specify the Python version using pyenv and then use Poetry to create the project.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; pyenv shell 3.9.11
&amp;gt; poetry new PROJECT_NAME # Example testproject
&amp;gt; cd testproject
&amp;gt; git init # Initialise the repository
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Next, create the .editorconfig configuration provided above. Your project tree structure should look like this:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; tree

.
├── .editorconfig
├── .git
│   ├── ...
├── README.rst
├── pyproject.toml
├── testproject
│   └── __init__.py
└── tests
    ├── __init__.py
    └── test_testproject.py

12 directories, 22 files
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;p&gt;Personally, I prefer Markdown instead of reStructuredText so I rename README.rst to README.md . All application logic goes into the folder named after your project and &lt;em&gt;tests go into the tests folder&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3398%2F1%2AaweX40JvPGoFG-CXbL6dhg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3398%2F1%2AaweX40JvPGoFG-CXbL6dhg.gif" alt="Example of creating a Python project using pyenv and Poetry."&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  My Essential Python Packages 📦
&lt;/h2&gt;

&lt;p&gt;This section details the majority of development packages (&lt;em&gt;packages that are only required during the development phase&lt;/em&gt;) I use in Python projects.&lt;/p&gt;
&lt;h3&gt;
  
  
  pytest with pytest-cov
&lt;/h3&gt;

&lt;p&gt;The &lt;a href="https://github.com/pytest-dev/pytest/" rel="noopener noreferrer"&gt;pytest&lt;/a&gt; framework makes it easy to write small tests, yet scales to support complex functional testing for applications and libraries. I prefer pytest over the inbuilt unittest library because it allows for plugins such as &lt;a href="http://pypi.python.org/pypi/pytest-xdist" rel="noopener noreferrer"&gt;pytest-xdist&lt;/a&gt;, which enables the execution of multiple tests at once, expediting test runtimes and requires fewer lines of code to produce the same output as unittest. Additionally, &lt;a href="https://pypi.org/project/pytest-cov/" rel="noopener noreferrer"&gt;pytest-cov&lt;/a&gt; is a plugin that automatically produces a test coverage report.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AkNzAYtq0KQtZ2eRJV1Ja9A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AkNzAYtq0KQtZ2eRJV1Ja9A.png" alt="Install development dependencies pytest and pytest-cov with Poetry."&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  wemake-python-styleguide
&lt;/h3&gt;

&lt;p&gt;The wemake.services team describe &lt;a href="https://wemake-python-stylegui.de/en/latest/" rel="noopener noreferrer"&gt;wemake-python-styleguide&lt;/a&gt; as &lt;a href="https://wemake-python-stylegui.de/en/latest/#:~:text=strictest%20and%20most%20opinionated%20Python%20linter%20ever." rel="noopener noreferrer"&gt;*the strictest and most opinionated Python linter ever&lt;/a&gt;*. It's essentially the &lt;a href="https://github.com/PyCQA/flake8" rel="noopener noreferrer"&gt;flake8&lt;/a&gt; package, a linting tool that analyses code for defects, with &lt;a href="https://wemake-python-stylegui.de/en/latest/pages/usage/violations/index.html#external-plugins" rel="noopener noreferrer"&gt;plugins&lt;/a&gt;. Its primary objectives are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Enforcing Python 3.6+ usage.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Significantly reducing the complexity of code and making it more maintainable.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Enforcing “There should be one — and preferably only one — obvious way to do it” rule to coding and naming styles&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Protect developers from possible errors and enforce best practices.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A9_s4XK2dXtKht1ytGcb5Lw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A9_s4XK2dXtKht1ytGcb5Lw.png" alt="Install development dependency wemake-python-styleguide with Poetry."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I’d also recommend the flake8-pytest-style plugin if you’re using pytest.&lt;/p&gt;

&lt;p&gt;For existing projects, you can use the package &lt;a href="https://github.com/flakehell/flakehell" rel="noopener noreferrer"&gt;flakehell&lt;/a&gt; with the baseline feature to report new violations since integrating a new linter will likely result in hundreds or even thousands of violations. This &lt;a href="https://wemake-python-stylegui.de/en/latest/pages/usage/integrations/flakehell.html" rel="noopener noreferrer"&gt;guide&lt;/a&gt; explains how to integrate flakehell and resolve violations over time.&lt;/p&gt;
&lt;h3&gt;
  
  
  Mypy
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/python/mypy" rel="noopener noreferrer"&gt;Mypy&lt;/a&gt; is an optional static type checker that aims to combine the benefits of dynamic (or “duck”) typing and static typing. The benefits of statically typed code are increased readability and maintainability. For an existing code base here's a &lt;a href="https://mypy.readthedocs.io/en/stable/existing_code.html" rel="noopener noreferrer"&gt;guide&lt;/a&gt; on how to implement Mypy.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AoT-Ai_iPXOA0hVWXbgVa0g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AoT-Ai_iPXOA0hVWXbgVa0g.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AHcJ6c2PvbjKIGDoJ-jEklg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AHcJ6c2PvbjKIGDoJ-jEklg.png" alt="Before and after statically typed Python code."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AkRzO55GWEfs2PrtYQB1Ixw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AkRzO55GWEfs2PrtYQB1Ixw.png" alt="Install development dependency Mypy with Poetry."&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  Safety
&lt;/h3&gt;

&lt;p&gt;A 2021 &lt;a href="https://go.snyk.io/rs/677-THP-415/images/Python%20Insight%20Report.pdf" rel="noopener noreferrer"&gt;security report&lt;/a&gt; by Snyk, states 47% of Python projects contain known vulnerabilities. On the bright hand side, almost 87% of known vulnerabilities can be resolved by upgrading the vulnerable package. &lt;a href="https://github.com/pyupio/safety" rel="noopener noreferrer"&gt;Safety&lt;/a&gt; checks your installed dependencies for known security vulnerabilities.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3398%2F1%2AkyKIpi8f6zU-mj2z_1cVlg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3398%2F1%2AkyKIpi8f6zU-mj2z_1cVlg.gif" alt="Example of Safety detecting a vulnerable package."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A14LQ0nng0mFXuAbj3TgR8A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A14LQ0nng0mFXuAbj3TgR8A.png" alt="Install development dependency Safety with Poetry."&gt;&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;
  
  
  pre-commit
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://github.com/pre-commit/pre-commit" rel="noopener noreferrer"&gt;pre-commit&lt;/a&gt; is a framework for managing and maintaining multi-language pre-commit hooks. For example, a hook that runs pytest must succeed before code can be committed to the repository, preventing code defects. The following pre-commit configuration file is what I use in my Python projects. &lt;strong&gt;It ensures that tests, coverage, stating type checking and vulnerability scanning all pass before code is committed.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3398%2F1%2A1Oj11ROFLa5DgvpJqGMhmQ.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3398%2F1%2A1Oj11ROFLa5DgvpJqGMhmQ.gif" alt="Example of pre-commit preventing defective code from being committed."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This is the .pre-commit-config.yaml file used in the above example:&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;

&lt;p&gt;&lt;br&gt;&lt;br&gt;
&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AVPR5SM_voDsUs-eXweL0ug.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2AVPR5SM_voDsUs-eXweL0ug.png" alt="Install development dependency pre-commit."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Nitpick
&lt;/h3&gt;

&lt;p&gt;It can become tedious maintaining configurations across projects, especially since EditorConfig, pytest-cov, flake8, Mypy and pre-commit all require configuration files. &lt;a href="https://github.com/andreoliwa/nitpick" rel="noopener noreferrer"&gt;Nitpick&lt;/a&gt; is a tool and flake8 plugin that enforces the same configurations across multiple language-independent projects, automating this tedious configuration.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A4uqnkUuzixl0Dpxu5nUMgg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2A4uqnkUuzixl0Dpxu5nUMgg.png" alt="Install development dependency Nitpick with Poetry."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once installed, add the following line to your pyproject.toml file:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;**[tool.nitpick]**
style = "https://raw.githubusercontent.com/wemake-services/wemake-python-styleguide/master/styles/nitpick-style-wemake.toml"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You’ll need to create a .gitignore and CHANGELOG.md file to successfully pass Nitpick validation.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ASTIxcv98BWdHNvHuwvWBWg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F2000%2F1%2ASTIxcv98BWdHNvHuwvWBWg.png" alt="Nitpick configuration setup."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;It will automatically create a setup.cfg file that will contain all the required configurations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3398%2F1%2AUufwyUeqD5_DAxjC5viv0g.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3398%2F1%2AUufwyUeqD5_DAxjC5viv0g.gif" alt="Nitpick wemake-services installation."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Congratulations, you’ve successfully created a modern Python development environment 🎉. If you would like to connect with me you can find me on &lt;a href="https://www.linkedin.com/in/shanenullain/" rel="noopener noreferrer"&gt;Linkedin&lt;/a&gt; or &lt;a href="https://github.com/ShaneNolan" rel="noopener noreferrer"&gt;Github&lt;/a&gt;. Thanks for reading 😊!&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra: VSCode WSL2 Integration
&lt;/h2&gt;

&lt;p&gt;If your editor is &lt;a href="https://code.visualstudio.com/" rel="noopener noreferrer"&gt;VSCode&lt;/a&gt; then you’re in luck because you can integrate the Linux subsystem easily with its &lt;a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl" rel="noopener noreferrer"&gt;remote WSL plugin&lt;/a&gt;. Once installed open your WSL terminal and execute code . . This will automatically open the VSCode editor within the Linux subsystem. You can read more about it &lt;a href="https://code.visualstudio.com/blogs/2019/09/03/wsl2" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Extra: Automated Project Setup and Configuration
&lt;/h2&gt;

&lt;p&gt;If you’re any way like me, then you must automate a task when you find yourself doing it more than once. I’ve automated the creation and configuration of a modern Python project using &lt;a href="https://github.com/cookiecutter/cookiecutter" rel="noopener noreferrer"&gt;cookiecutter&lt;/a&gt;. You will need to set up your environment first. Also, nitpick uses my own take on the wemake-services configuration, you can view the &lt;a href="https://github.com/ShaneNolan/python-project-template" rel="noopener noreferrer"&gt;repository&lt;/a&gt; here.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;gt; pyenv shell 3.9.11

---------------------------------------------
# Unix: Specify the name of the project.
&amp;gt; export PROJECT_NAME="MY_PROJECT_NAME"
=============================================
# Windows: Specifcy the name of the project.
&amp;gt; set PROJECT_NAME="MY_PROJECT_NAME"
---------------------------------------------

&amp;gt; python -m pip install cookiecutter &amp;amp;&amp;amp;
python -m cookiecutter --no-input gh:ShaneNolan/python-project-template \
project_name=$PROJECT_NAME &amp;amp;&amp;amp;
(cd $PROJECT_NAME &amp;amp;&amp;amp; git init &amp;amp;&amp;amp;
poetry init --no-interaction --name $PROJECT_NAME &amp;amp;&amp;amp;
poetry add mypy pytest pytest-cov flake8-pytest-style wemake-python-styleguide safety pre-commit nitpick --dev &amp;amp;&amp;amp;
poetry run nitpick fix &amp;amp;&amp;amp;
poetry run pre-commit install) &amp;amp;&amp;amp; python -m uninstall cookiecutter
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3398%2F1%2AGEJV8vWbVOGo4EjelQo1Eg.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn-images-1.medium.com%2Fmax%2F3398%2F1%2AGEJV8vWbVOGo4EjelQo1Eg.gif" alt="Example of Automated Project Setup and Configuration."&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>python</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
