-
Notifications
You must be signed in to change notification settings - Fork 200
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
183 changed files
with
9,015 additions
and
101 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
## Resources for Deploying Applications | ||
|
||
### [Deploying Django to AWS](./Tech_Stacks/Deploying_Django_to_AWS.md) | ||
### [Deploying Django to AWS](./Tech_Stacks/Deploying_Django_to_AWS.md) | ||
|
||
### [Build an Android React Native App Using GitHub Actions](./Tech_Stacks/build-android-app-using-github-actions.md) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,178 @@ | ||
# Code Smells | ||
|
||
## Table of Contents | ||
1. [What is code smell?](#what-is-code-smell) | ||
2. [Duplicate Code](#duplicate-code) | ||
3. [Improper Names](#improper-names) | ||
4. [Dead Code](#dead-code) | ||
5. [Middle Man](#middle-man) | ||
6. [Feature Envy](#feature-envy) | ||
7. [Long Functions](#long-functions) | ||
8. [Data Clumps](#data-clumps) | ||
9. [Additional Resources](#additional-resources) | ||
|
||
### What is a code smell? | ||
|
||
Code smells are indicators of potential issues or weaknesses in software code. They are not bugs or errors, but rather patterns or practices that may lead to problems in the future. | ||
|
||
## Common Types of Code Smells and How They Can Harm your Code | ||
|
||
There are a vast number of code smells and they differ from project to project and developer to developer, and business to business. | ||
|
||
So, it is crucial to thoroughly understand the organization’s design and development standards before handling any code smell. | ||
|
||
Here are the most common code smells that developers usually encounter with: | ||
|
||
### Duplicate Code | ||
|
||
In simple terms, duplicate code happens when two code fragments look almost identical. Consider this piece of code: | ||
|
||
``` | ||
def calculate_rectangle_area(length, width): | ||
return length * width | ||
# Duplicate code | ||
def calculate_square_area(side): | ||
return side * side | ||
``` | ||
|
||
In this example, the `calculate_square_area` function duplicates the functionality of the `calculate_rectangle_area` function but only for squares. This coding habit makes it harder to debug a program because any changes or bug fixes need to be applied to multiple places. Also, duplicated code makes the codebase harder to read and understand. Developers might need to analyze multiple sections of code that are essentially doing the same thing. | ||
|
||
### Improper Names | ||
|
||
If your variables, classes, and functions lack proper names, this can be an indicator that your code isn’t clean. For example, | ||
|
||
``` | ||
def func(a, b): | ||
return a + b | ||
``` | ||
This function is simple enough to understand despite its naming issue. However, imagine that we have a big function to perform some backend tasks for our program, | ||
then it would be more problematic for other developers. Without additional context or comments, it's not immediately clear what the function is supposed to do. | ||
This can lead to confusion for others who encounter this code later or who need to work with it. | ||
|
||
### Dead Code | ||
|
||
Dead code is code that’s in the application but not in use. Here is an example, | ||
|
||
``` | ||
public class Calculator { | ||
public int add(int a, int b) { | ||
return a + b; | ||
} | ||
// This method is never called, making it dead code | ||
public int subtract(int a, int b) { | ||
return a - b; | ||
} | ||
} | ||
``` | ||
|
||
The `subtract` method is never called from any part of the application. It remains in the codebase, occupying space and potentially causing confusion for developers who might assume it serves a purpose. | ||
|
||
### Middle Man | ||
|
||
This code smell refers to a situation where an object or method serves mainly as a pass-through or intermediary, delegating most of its functionality to another object or method without adding significant value or functionality of its own. This can introduce unnecessary complexity and reduce the clarity and efficiency of the codebase. | ||
|
||
``` | ||
class DataManager: | ||
def __init__(self, data): | ||
self.data = data | ||
def process_data(self): | ||
data_processor = DataProcessor() | ||
return data_processor.process(self.data) | ||
class DataProcessor: | ||
def process(self, data): | ||
# Some complex data processing logic here | ||
processed_data = data * 2 | ||
return processed_data | ||
``` | ||
|
||
In this example, the `DataManager` class serves as a middle man that merely delegates the data processing to the `DataProcessor` class. It doesn't add any additional functionality or logic of its own and exists primarily to pass data to another class. | ||
|
||
### Feature Envy | ||
|
||
This happens when a method accesses the data of another object more than its own data. Consider this piece of code: | ||
|
||
``` | ||
class ShoppingCart: | ||
def __init__(self): | ||
self.items = [] | ||
def add_item(self, item): | ||
self.items.append(item) | ||
def total_price(self, tax_rate): | ||
total = 0 | ||
for item in self.items: | ||
total += item.price | ||
total *= (1 + tax_rate) | ||
return total | ||
class Item: | ||
def __init__(self, name, price): | ||
self.name = name | ||
self.price = price | ||
class User: | ||
def __init__(self): | ||
self.shopping_cart = ShoppingCart() | ||
def calculate_total_price(self, tax_rate): | ||
return self.shopping_cart.total_price(tax_rate) | ||
``` | ||
|
||
The `User` class has a method calculate_total_price that calculates the total price of items in the user's shopping cart. However, instead of directly accessing the user's shopping cart and performing the calculation there, it invokes the `total_price` method of the `ShoppingCart` class. This leads to poor encapsulation and violate the principle of encapsulation, where each class should encapsulate its own behavior and data. | ||
|
||
### Long Functions | ||
|
||
Long functions is a code smell that occurs when a function or method is excessively long, containing a large number of lines of code. Long functions can be difficult to understand, maintain, and test. They often violate the Single Responsibility Principle, which states that a function should only have one reason to change. | ||
|
||
``` | ||
def process_order(order): | ||
# Step 1: Validate order data | ||
if not order: | ||
return None | ||
# Step 2: Fetch product information | ||
product_info = fetch_product_info(order.product_id) | ||
# Step 3: Calculate total price | ||
total_price = order.quantity * product_info.price | ||
# Step 4: Apply discounts | ||
if order.discount_code == 'DISCOUNT10': | ||
total_price *= 0.9 | ||
# Step 5: Apply taxes | ||
total_price *= 1.15 # Assuming 15% tax rate | ||
# Step 6: Generate invoice | ||
invoice = generate_invoice(order, product_info, total_price) | ||
# Step 7: Send confirmation email | ||
send_confirmation_email(order.email, invoice) | ||
``` | ||
|
||
In this example, the `process_order` function performs multiple steps, including validation, fetching product information, calculating total price, applying discounts and taxes, generating an invoice, and sending a confirmation email. The function is long and complex, which makes it difficult to understand and maintain. | ||
|
||
### Data Clumps | ||
|
||
Data clumps occur when multiple pieces of data go together. One easy way to spot a data clump is when one component doesn’t make sense in isolation but makes sense as a group. Here's an example to illustrate the data clumps: | ||
|
||
``` | ||
def create_user(name, email, phone): | ||
# Function to create a user using name, email, and phone | ||
pass | ||
def update_user_email(user_id, new_email): | ||
# Function to update user's email | ||
pass | ||
def send_notification(email, message): | ||
# Function to send email notification | ||
pass | ||
``` | ||
|
||
In this example, the `name`, `email`, and `phone` parameters are frequently passed together in various functions. This suggests that these pieces of data are closely related and should be put together in the same class. | ||
|
||
|
||
# Additional Resources | ||
1. [Refactoring Guru](https://refactoring.guru/refactoring/smells) | ||
2. [What is a code smell?](https://linearb.io/blog/what-is-a-code-smell) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# CD for a Dockerized application using Github Actions, Amazon ECR and Amazon ECS | ||
|
||
## Introduction | ||
Containerized applications are becoming more popular due to the consistency they provide accross different machines and portability to different cloud providers. It is becoming increasingly valuable to build applications with dockerization in mind. With that comes the need to streamline deployment of these containerized applications. | ||
|
||
## Pre-Requisites | ||
- [Dockerizing an app](./Docker.md) | ||
- [Github Actions](./Github_Actions.md) | ||
|
||
## Step 1 (Setting up your application & AWS): | ||
- Essentially you want to follow the same steps as this tutorial [Deploy Node.js Docker AWS](./Deploy_Node.js_Docker_AWS.md), adjusting your dockerfile according to language and tools you are using for your application. The main goals are to | ||
- Containerize your application | ||
- Create an amazon ECR repository | ||
- Create an ECS cluster, service as well as task definition | ||
|
||
**NOTE**: It's important that your ECR repository and ECS cluster are defined on the same AWS region otherwise you may have to sign into aws twice throughout the workflow | ||
|
||
|
||
## Step 2 (Setting up the workflow -- triggers): | ||
``` | ||
on: | ||
push: | ||
branches: | ||
- production | ||
``` | ||
- With the above code we ensure that the workflow created in this guide is run only on pushes to the "production" branch | ||
- Generally you only want to deploy your application on pushes to some branch designated as your production branch to avoid wasting github actions minutes and deploying when development is underway | ||
|
||
## Step 2 (Setting up the workflow triggers): | ||
Create a new job | ||
``` | ||
jobs: | ||
deploy: | ||
name: Deploy | ||
runs-on: ubuntu-latest | ||
environment: production | ||
steps: | ||
``` | ||
- We'll be creating a new job called deploy that runs on an ubuntu instance | ||
- All subsequent steps will fall under the "steps:" section in the code block above | ||
|
||
## Step 3 (Checking out the repo) | ||
``` | ||
- name: Checkout | ||
uses: actions/checkout@v4 | ||
``` | ||
- Create a new step for checking out the current repo. This ensures that in subsequent steps you have access to all code within your current repo | ||
|
||
## Step 4 (Signing into AWS) | ||
``` | ||
- name: Configure AWS credentials | ||
uses: aws-actions/configure-aws-credentials@0e613a0980cbf65ed5b322eb7a1e075d28913a83 | ||
with: | ||
aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} | ||
aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} | ||
aws-region: <YOUR_AWS_REGION> | ||
- name: Login to Amazon ECR | ||
id: login-ecr | ||
uses: aws-actions/amazon-ecr-login@62f4f872db3836360b72999f4b87f1ff13310f3a | ||
``` | ||
- For details on how to quickly set up your AWS credentials, view the following video: https://www.youtube.com/watch?v=gswVHTrRX8I | ||
- From the above video, you should have recieved an access key as well as a secret access key which you should then set in your [Github Secrets](https://docs.github.com/en/actions/security-guides/using-secrets-in-github-actions) | ||
- Setting secrets ensures that you have access to your credentials within your workflow without explicitly writing them out in the workflow file | ||
- We are using an action defined by someone else to aid us in signing into aws for subsequent steps | ||
|
||
## Step 5 (Building/tagging your image and pushing it to your ECR repo) | ||
``` | ||
- name: Build, tag, and push image to Amazon ECR | ||
id: build-image | ||
run: | | ||
docker build -t <ECR_REGISTRY>/<ECR_REPOSITORY>:latest <DOCKERFILE_FOLDER_PATH> | ||
docker push <ECR_REGISTRY>/<ECR_REPOSITORY>:latest | ||
``` | ||
- Just like how we build the docker image in order to run a container locally, we should build, tag and push our image to our ECR repository so that ECS can pull from it in a future step | ||
- The `DOCKERFILE_FOLDER_PATH` is the path to the folder containing the dockerfile to build your application | ||
- The `ECR_REGISTRY` and `ECR_REPOSITORY` can be retrieved from the repository URI | ||
<img width="791" alt="Screenshot 2024-03-17 at 9 41 59 PM" src="https://github.com/learning-software-engineering/learning-software-engineering.github.io/assets/58835213/5dd3ce35-6094-48db-980e-a0456becc663"> | ||
|
||
## Step 6 (Deploying the application) | ||
``` | ||
- name: Deploy Amazon ECS task definition | ||
uses: aws-actions/amazon-ecs-deploy-task-definition@df9643053eda01f169e64a0e60233aacca83799a | ||
with: | ||
task-definition: <PATH_TO_TASK_DEFINITION> | ||
service: <ECS_SERVICE> | ||
cluster: <ECS_CLUSTER> | ||
wait-for-service-stability: true | ||
``` | ||
- Once again, using an existing action, we will deploy the app by specifying some additional information | ||
- The task definition, ECS service and ECS cluster are defined as per [Deploy Node.js Docker AWS](./Deploy_Node.js_Docker_AWS.md) | ||
- For `<PATH_TO_TASK_DEFINITION>` you should link to that path of your aws task definition JSON file in your repository. If you don't have one in your repository you can generate one by visiting the task definitions page in Amazon ECS <img width="1022" alt="Screenshot 2024-03-17 at 9 30 22 PM" src="https://github.com/learning-software-engineering/learning-software-engineering.github.io/assets/58835213/8144e7cf-21b7-4c8c-89ad-130e04b5f5a6"> | ||
|
||
|
||
- `wait-for-service-stability` keeps the workflow from passing until the ECS service has become stable given the most recent deployment | ||
|
||
## Conclusion | ||
Congrationations, you have reached the end of this tutorial! After a push to your production branch you should be able to sit back and watch your newest workflow deploy your app for you! | ||
|
||
## Reference | ||
This guide is inspired by this github actions guide [Deploying to amazon elastic container service](https://docs.github.com/en/actions/deployment/deploying-to-your-cloud-provider/deploying-to-amazon-elastic-container-service) |
Binary file added
BIN
+1.33 MB
...s/Development_Process/Ubuntu_server_edition/Assets/IMG_20240315_021624_8542.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added
BIN
+1.32 MB
Topics/Development_Process/Ubuntu_server_edition/Assets/invidious.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.