You are on page 1of 41

#PROGRAMMING: THE BASICS

# The Extended Version _

Programming fundamentals serve as the foundation for every programmer,


irrespective of their preferred programming language. This tutorial
aims to provide an easy overview of essential programming concepts and
principles that are crucial for beginners and even seasoned programmers
who may not have studied the fundamentals. By understanding these core
concepts, you will develop a strong programming mindset and be equipped
to tackle various programming challenges efficiently.

Section 1: Introduction to Programming

1.1 What is Programming?

Programming is the process of creating instructions for a computer to follow


in order to perform a specific task or solve a problem. Programmers write
code using programming languages, which are sets of rules and syntax that
computers can understand and execute. Programming enables us to build
software applications, websites, games, and much more.

1.2 Why Learn Programming Fundamentals?

Learning programming fundamentals is essential for several reasons:

● Problem Solving: Programming teaches you how to break down complex


problems into smaller, manageable tasks and develop algorithms to
solve them.
● Understanding Software: By learning programming fundamentals, you gain
a deeper understanding of how software works and how to design
efficient and scalable solutions.
● Adaptability: Strong programming fundamentals provide a solid
foundation that allows you to learn new programming languages and
technologies more easily.
● Debugging and Maintenance: Understanding programming fundamentals
helps you write clean, maintainable code and debug errors effectively.
● Collaboration: Having a shared understanding of programming
fundamentals enables effective collaboration with other programmers.

By: Waleed Mousa


Now, let's dive into the core concepts of programming fundamentals!

Section 2: Programming Paradigms


Programming Paradigms are the various styles or "ways" of programming.
These are some of the major ones:

2.1 Introduction to Programming Paradigms

A programming paradigm is a style or "way" of programming. Some


languages are designed to support one paradigm (Smalltalk supports
object-oriented programming, Haskell supports functional programming),
while others support multiple paradigms (such as Python, which is
object-oriented but also supports procedural and functional
programming).

2.2 Procedural Programming

In procedural programming, a program is divided into small parts called


procedures. Each procedure is a set of instructions that accomplishes a
specific task.

Procedural programming emphasizes a step by step set of instructions.


This paradigm is commonly used in languages like C, Go and earlier
versions of BASIC.

Example (in C):

#include <stdio.h>

void greet() {
printf("Hello, World!");
}

int main() {
greet(); // This is a procedure call
return 0;
}

Here, greet() is a procedure that prints "Hello, World!" when it's


called.

By: Waleed Mousa


2.3 Object-Oriented Programming (OOP)

OOP is a design philosophy which uses "objects" and classes for


designing applications and software. An object is a thing that can
perform a set of related activities. The set of activities that the
object performs defines the object's behavior.

OOP is supported in languages like Java, C++, and Python.

Example (in Python):

class Dog: # Define a class 'Dog'


def __init__(self, name):
self.name = name

def bark(self): # Define a method 'bark'


print(self.name + " says woof!")

fido = Dog("Fido") # Create an instance of 'Dog' named 'Fido'


fido.bark() # Call the 'bark' method

Here, Dog is a class, which is like a blueprint for creating objects.


fido is an instance (object) of the class Dog. The bark method
represents a behavior that the Dog class objects can perform.

2.4 Functional Programming

Functional programming is a paradigm where programs are constructed by


applying and composing functions. It is a declarative type of
programming style that focuses on what to solve rather than how to
solve (procedural programming).

Functional programming is supported in languages like Haskell, Erlang,


and in multi-paradigm languages like JavaScript.

Example (in JavaScript):

const add = (x, y) => x + y; // A simple function to add two numbers

const sum = add(5, 7); // Apply the function


console.log(sum); // Prints: 12

By: Waleed Mousa


Here, add is a function that takes two numbers and returns their sum.
The function is applied to the numbers 5 and 7.

2.5 Logic Programming

In logic programming, computation is performed by using a mechanism of


deduction. Instead of calling functions or procedures, you make
assertions about relations and the runtime attempts to prove those
assertions based on existing rules.

Prolog is one of the most commonly used logic programming languages.

Example (in Prolog):

loves(romeo, juliet).

loves(juliet, romeo) :- loves(romeo, juliet).

In this example, the loves(romeo, juliet) is an assertion or fact. The


second line is a rule that states "Juliet loves Romeo if Romeo loves
Juliet".

2.6 Comparison and Use Cases

Each paradigm has its strengths and weaknesses, and the choice of
paradigm can be influenced by other factors such as the specific problem
the program is trying to solve and the programming language in use.
Procedural programming can be useful for simple, straightforward tasks,
while object-oriented programming is widely used in large software
systems. Functional programming is becoming increasingly popular for
tasks that require concurrency or for programs with no side effects.
Logic programming is useful for tasks that involve complex rule systems
or inferences.

By: Waleed Mousa


Section 3: Algorithms and Problem Solving

3.1 Introduction to Algorithms

An algorithm is a step-by-step procedure or a set of rules for solving


a specific problem. It is the backbone of programming and helps us
design efficient solutions. Some common algorithm design techniques
include:

● Brute Force: Exhaustively checking all possible solutions.


● Divide and Conquer: Breaking a problem into smaller subproblems and
solving them individually.
● Greedy: Making locally optimal choices at each step to achieve an
overall optimal solution.
● Dynamic Programming: Breaking a problem into overlapping subproblems
and solving them once, storing the results for future use.
● Backtracking: Exploring all possible solutions by incrementally
building and undoing choices.

3.2 Problem-Solving Strategies

When faced with a programming problem, it's crucial to have effective


problem-solving strategies. Here are some strategies to consider:

● Understand the Problem: Clearly define the problem's requirements,


constraints, and expected outputs.
● Divide and Conquer: Break down the problem into smaller, manageable
parts.
● Pattern Recognition: Identify patterns, similarities, or recurring
themes in the problem.
● Algorithm Design: Devise an algorithmic approach to solve the problem
based on the identified patterns.
● Step-by-Step Execution: Implement the algorithm in your chosen
programming language, ensuring each step is correctly executed.
● Test and Debug: Verify your solution's correctness by testing it with
various inputs and debugging any errors or unexpected behaviors.

By: Waleed Mousa


3.3 Pseudocode and Flowcharts

Pseudocode and flowcharts are two essential tools for representing


algorithms visually and improving their readability.

● Pseudocode: Pseudocode is a simplified, high-level description of


an algorithm that uses a combination of natural language and
programming language constructs. It helps programmers plan and
structure their code before writing actual code in a specific
language.

Example of pseudocode for finding the sum of two numbers:

1. Start
2. Read the first number (num1)
3. Read the second number (num2)
4. Add num1 and num2 and store the result in sum
5. Display sum
6. Stop

● Flowcharts: Flowcharts use various shapes and arrows to represent


different steps and decisions in an algorithm. They provide a
visual representation of the flow of control within a program,
making it easier to understand and analyze.

Example of a flowchart for finding the sum of two numbers:

START -> Input num1 -> Input num2 -> Add num1 and num2 -> Store the result in
sum -> Display sum -> END

By: Waleed Mousa


Section 4: Variables and Data Types

4.1 Variables and Constants

In programming, variables are used to store and manipulate data. A


variable is a named location in computer memory that can hold a value.
Constants, on the other hand, are similar to variables but hold fixed
values that cannot be changed during program execution.

Variables and constants have a name and a data type associated with
them. The name allows us to refer to the variable, while the data type
defines the kind of data that the variable can hold.

4.2 Data Types

Different programming languages support various data types. Common data


types include:

● Integer: Represents whole numbers (e.g., 5, -2, 100).

● Floating-Point: Represents decimal numbers with fractional parts (e.g.,


3.14, -0.5, 2.0).

● String: Represents a sequence of characters (e.g., "Hello, World!",


"OpenAI").

● Boolean: Represents either true or false.

● Character: Represents a single character (e.g., 'A', '$', '#').

Programming languages also provide more advanced data types, such as


arrays, lists, structures, and classes, which allow you to store
multiple values or create custom data structures.

By: Waleed Mousa


4.3 Type Conversions and Casting

Sometimes, you may need to convert a value from one data type to
another. This is known as type conversion or casting. The two main
types of casting are implicit casting (also known as coercion) and
explicit casting.

● Implicit Casting: Occurs when the programming language


automatically converts one data type to another without explicit
instructions. For example, converting an integer to a
floating-point number.

● Explicit Casting: Requires the programmer to explicitly specify


the type conversion using type-casting operators or functions
provided by the programming language. This is useful when
converting between incompatible data types.

Example of explicit casting:

int num1 = 5;
float num2 = (float) num1; // Explicitly cast num1 to a float

Section 5: Control Structures

5.1 Conditional Statements

Conditional statements allow you to make decisions in your program


based on certain conditions. The common types of conditional statements
include:

● If Statement: Executes a block of code if a specified condition is


true.

if condition:
# Code to be executed if condition is true

By: Waleed Mousa


● If-else Statement: Executes a block of code if a condition is
true, and another block of code if the condition is false.

if condition:
# Code to be executed if condition is true
else:
# Code to be executed if condition is false

● Nested If-else Statement: Allows you to have multiple levels of


conditions.

if condition1:
# Code to be executed if condition1 is true
if condition2:
# Code to be executed if both condition1 and condition2 are true
else:
# Code to be executed if condition1 is true and condition2 is false
else:
# Code to be executed if condition1 is false

● Switch Statement (or Case Statement): Allows you to select one of


many code blocks to be executed based on the value of a variable
or an expression. This is available in some programming languages
like C++, Java, and JavaScript.

5.2 Looping Structures

Looping structures are used to repeat a block of code multiple times.


There are three common types of loops:

● For Loop: Executes a block of code for a specific number of


iterations, often used when the number of iterations is known in
advance.

for variable in sequence:


# Code to be executed for each value in the sequence

● While Loop: Executes a block of code repeatedly as long as a


specified condition is true, often used when the number of
iterations is not known in advance.

By: Waleed Mousa


while condition:
# Code to be executed while the condition is true

● Do-While Loop: Similar to the while loop, but it always executes


the block of code at least once before checking the condition.

do:
# Code to be executed
while condition

5.3 Control Flow Statements

Control flow statements allow you to control the flow of your program.
They include:

● Break Statement: Terminates the execution of a loop or a switch


statement and transfers control to the next statement outside the
loop or switch.
● Continue Statement: Skips the remaining code in the current
iteration of a loop and moves to the next iteration.
● Return Statement: Terminates the execution of a function and
returns a value (if specified) back to the caller.

Section 6: Functions and Modular Programming

6.1 Introduction to Functions

Functions are blocks of reusable code that perform specific tasks. They
allow you to break down your program into smaller, more manageable
parts, making your code modular and easier to understand. Functions can
take inputs (arguments) and produce outputs (return values).

By: Waleed Mousa


6.2 Function Declarations and Definitions

In most programming languages, functions are declared and defined using


the following syntax:

def function_name(parameters):
# Function code
return value # (optional)

● Function Name: A unique identifier that represents the function.


● Parameters: Variables that receive values when the function is
called. Parameters are optional and can be of any data type.
● Function Code: The block of code that is executed when the
function is called.
● Return Statement: Optional statement used to return a value from
the function. If omitted, the function may perform actions without
returning a value.

6.3 Function Parameters and Return Values

Functions can have zero or more parameters. Parameters allow you to


pass data into the function for processing. When a function is called,
the arguments provided are assigned to the corresponding parameters.

Example of a function with parameters and a return value:

def add_numbers(num1, num2):


sum = num1 + num2
return sum

Functions can also have no parameters or return values, depending on


the task they perform.

By: Waleed Mousa


6.4 Scope and Variable Visibility

Variables in programming have a scope, which determines where they can


be accessed within the program. The two main types of scope are global
scope and local scope.

● Global Scope: Variables declared outside any function are called


global variables and can be accessed from anywhere within the
program.
● Local Scope: Variables declared inside a function are called local
variables and can only be accessed within that specific function.

It's important to understand scope to avoid naming conflicts and ensure


proper variable visibility.

Section 7: Arrays and Lists

7.1 Introduction to Arrays and Lists

Arrays and lists are data structures that allow you to store multiple
values of the same or different data types. They provide a convenient
way to work with collections of data.

● Arrays: Arrays are fixed-size collections of elements, where each


element is identified by an index. The index represents the
position of the element in the array. Arrays are usually supported
in lower-level languages like C, C++, and Java.
● Lists: Lists are dynamic collections of elements, where elements
can be added or removed as needed. Lists are more flexible compared
to arrays and are supported in many programming languages,
including Python, JavaScript, and C#.

By: Waleed Mousa


7.2 Array/List Operations

Arrays and lists support various operations, including:

● Accessing Elements: Elements in an array or list can be accessed


using their index. The index starts at 0 for the first element.

my_list = [10, 20, 30, 40, 50]


print(my_list[0]) # Output: 10

● Modifying Elements: Elements in an array or list can be modified by


assigning a new value to the corresponding index.

my_list = [10, 20, 30, 40, 50]


my_list[2] = 35
print(my_list) # Output: [10, 20, 35, 40, 50]

● Appending Elements: Elements can be added to the end of a list


using the append() method or equivalent functions in other
programming languages.

my_list = [10, 20, 30]


my_list.append(40)
print(my_list) # Output: [10, 20, 30, 40]

● Slicing: Slicing allows you to extract a subset of elements from


an array or list by specifying a range of indices.

my_list = [10, 20, 30, 40, 50]


subset = my_list[1:4]
print(subset) # Output: [20, 30, 40]

7.3 Multidimensional Arrays

Multidimensional arrays are arrays that have multiple dimensions or


indices. They are useful for representing data in a tabular form or
when working with matrices.

matrix = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]


print(matrix[1][2]) # Output: 6

By: Waleed Mousa


7.4 Common Array/List Algorithms

Arrays and lists have a wide range of algorithms and operations that
can be performed on them, such as sorting, searching, and traversing.
Some common algorithms include:

● Sorting: Rearranging the elements in ascending or descending order


(e.g., bubble sort, insertion sort, merge sort, quicksort).
● Searching: Finding the position or existence of an element within
the array or list (e.g., linear search, binary search).
● Traversing: Visiting each element in the array or list (e.g.,
iterating over the elements using loops).

Understanding arrays and lists and their operations is crucial for


working with collections of data efficiently.

Section 8: Input and Output

8.1 User Input

User input allows programs to interact with users by accepting data


from them. Most programming languages provide built-in functions or
libraries to handle user input.

Example of user input in Python:

name = input("Enter your name: ")


age = int(input("Enter your age: ")) # Reading an integer input

8.2 Output to the Console

Outputting information to the console allows programs to display


messages, results, or other data to the user.

Example of console output in Python:

print("Hello, World!")

By: Waleed Mousa


8.3 File Input and Output

In addition to console input and output, programs can read from and
write to files. File input and output operations are essential for data
storage and retrieval.

Example of reading from a file in Python:

with open("filename.txt", "r") as file:


content = file.read()
print(content)

Example of writing to a file in Python:

with open("filename.txt", "w") as file:


file.write("Hello, World!")

Understanding input and output operations is crucial for building


interactive programs and handling data persistence.

Section 9: Error Handling and Exception Handling

9.1 Handling Errors and Exceptions

Errors and exceptions are inevitable in programming. Error handling and


exception handling techniques allow you to gracefully handle unexpected
situations and prevent program crashes.

● Errors: Errors occur when there are syntax or logical mistakes in


the code, preventing the program from running. These errors need
to be identified and fixed during the development process.
● Exceptions: Exceptions occur during program execution when an
unexpected condition or error arises. Exceptions can be
anticipated and handled using exception handling techniques.

By: Waleed Mousa


9.2 Error Types and Exception Classes

Exceptions are categorized into different types based on the nature of


the error. Common exception classes include:

● ArithmeticError: Occurs during arithmetic operations, such as


division by zero.
● TypeError: Occurs when an operation or function is applied to an
object of an inappropriate type.
● ValueError: Occurs when a function receives an argument of the
correct type but an invalid value.
● FileNotFoundError: Occurs when trying to open a file that does not
exist.
● IndexError: Occurs when trying to access an element at an invalid
index in a list or array.

Programming languages provide built-in exception classes, and you can


also create custom exception classes to handle specific situations in
your code.

9.3 Try-Catch Blocks

Try-catch blocks (also known as exception handling blocks) are used to


handle exceptions gracefully. The code within the try block is
executed, and if an exception occurs, it is caught by the corresponding
catch block.

Example of a try-catch block in Python:

try:
# Code that might raise an exception
except ExceptionType:
# Code to handle the exception

The catch block specifies the type of exception to catch. You can have
multiple except blocks to handle different types of exceptions or
provide a generic except block to handle any exception.

By: Waleed Mousa


9.4 Finally Block

Additionally, many programming languages provide a finally block, which


is executed regardless of whether an exception occurs or not. The
finally block is commonly used for cleanup tasks, such as closing files
or releasing resources.

Example of using a finally block in Python:

try:
# Code that might raise an exception
except ExceptionType:
# Code to handle the exception
finally:
# Code to be executed regardless of an exception

Error handling and exception handling are essential for building robust
and resilient programs that can gracefully handle unexpected
situations.

Section 10: Secure Coding


Secure coding is the practice of writing programs that are resistant to
attack by malicious or mischievous people or programs.

10.1 Importance of Secure Coding

Secure coding is important because today's software underpins systems


that perform critical functions in all sectors of the economy. Software
vulnerabilities can allow attackers to access sensitive data, disrupt
system operations, or gain control of systems.

10.2 Common Security Vulnerabilities

Some of the most common security vulnerabilities include:

● Buffer Overflows: Happen when a program writes more data to a


buffer than the buffer is able to hold.

By: Waleed Mousa


● Injection attacks: Occur when untrusted data is sent to an
interpreter as part of a command or query. The most common example
is SQL injection.
● Cross-Site Scripting (XSS): Occurs when an attacker injects
malicious scripts into websites viewed by other users.
● Insecure Direct Object References: Happens when a developer
exposes a reference to an internal implementation object.
● Misconfiguration: Can happen at any level of an application stack,
including the platform, web server, application server, database,
and framework.

10.3 Input Validation and Sanitization

Input validation is the process of ensuring an application operates on


clean, correct and useful data. It uses routines, rules, and
constraints that check for correctness, meaningfulness, and security of
input data. It can be used to detect unauthorized input before it is
processed by the application.

Example (Python):

def sanitize(input):
return ''.join(e for e in input if e.isalnum())

user_input = sanitize(input("Enter your name: "))


print(user_input)

In this example, we define a function sanitize that only allows


alphanumeric characters in the user input, potentially preventing
injection attacks.

10.4 Principle of Least Privilege

The principle of least privilege (POLP) is a computer security concept


in which a user is given the minimum levels of access necessary to
complete his/her job functions. This is done to enhance the protection
of data and functionality from faults and malicious behavior.

By: Waleed Mousa


10.5 Defense in Depth

Defense in Depth is an approach to cybersecurity in which a series of


defensive mechanisms are layered in order to protect valuable data and
information. If one mechanism fails, another steps up immediately to
thwart an attack.

10.6 Secure Error and Exception Handling

Secure error and exception handling is important to prevent an attacker


from learning too much about the architecture of your site through
detailed error messages.

Example (Python):

try:
risky_operation()
except Exception:
log_error("An error occurred.")
show_user_friendly_error_message()

In this example, if risky_operation() raises an exception, the error


details are logged but not displayed to the user, who only sees a
generic error message.

10.7 Secure Coding Practices and Standards

Some of the most widely accepted and effective secure coding practices
include:

● Input validation: Always validate user input to ensure it conforms


to the expected format, using both client-side and server-side
validation.
● Password protection: Always hash and salt passwords, and consider
adding additional security measures, like two-factor
authentication.
● Regular updates and patches: Always apply updates and patches to
your systems, frameworks, and libraries as soon as they become
available.

By: Waleed Mousa


● Use HTTPS: Always use HTTPS instead of HTTP to protect the
integrity and confidentiality of data in transit.
● Use of security headers: Use HTTP security headers to protect your
site from different types of attacks like XSS, code injection,
clickjacking, etc.

Section 11: Object-Oriented Programming (OOP) Basics

11.1 Introduction to OOP

Object-Oriented Programming (OOP) is a programming paradigm that


organizes code around objects, which are instances of classes. OOP
provides a way to structure programs, create reusable code, and model
real-world entities.

In OOP, objects have attributes (data) and behaviors


(methods/functions) associated with them. These attributes and
behaviors are defined by the class, which acts as a blueprint for
creating objects.

11.2 Classes and Objects

● Classes: A class is a blueprint or a template that defines the


attributes and behaviors of an object. It encapsulates data and
functions into a single entity.

Example of a class in Python:

class Circle:
def __init__(self, radius):
self.radius = radius

def calculate_area(self):
return 3.14 * self.radius * self.radius

● Objects: Objects are instances of a class. They are created using


the class blueprint and can access the attributes and behaviors
defined in the class.

By: Waleed Mousa


Example of creating objects from a class in Python:

circle1 = Circle(5) # Create an object of the Circle class with a radius of


5
circle2 = Circle(3) # Create another object with a radius of 3

print(circle1.calculate_area()) # Output: 78.5


print(circle2.calculate_area()) # Output: 28.26

11.3 Encapsulation, Inheritance, and Polymorphism

● Encapsulation: Encapsulation is the practice of bundling data and


the methods that operate on that data within a single unit (i.e.,
a class). It hides the internal details of how the data is stored
and manipulated, providing better data security and abstraction.
● Inheritance: Inheritance is a mechanism in which a class can
inherit attributes and behaviors from another class. The class
that is being inherited from is called the parent or base class,
and the class that inherits is called the child or derived class.
Inheritance promotes code reuse and allows for hierarchical
relationships between classes.

Example of inheritance in Python:

class Animal:
def __init__(self, name):
self.name = name

def sound(self):
pass # Placeholder method

class Dog(Animal):
def sound(self):
return "Woof!"

class Cat(Animal):
def sound(self):
return "Meow!"

dog = Dog("Buddy")
cat = Cat("Whiskers")

By: Waleed Mousa


print(dog.sound()) # Output: Woof!
print(cat.sound()) # Output: Meow!

● Polymorphism: Polymorphism allows objects of different classes to


be treated as objects of a common base class. This enables the use
of different implementations of methods based on the specific
object type. Polymorphism helps achieve code flexibility and
extensibility.

11.4 Constructors and Destructors

● Constructors: Constructors are special methods in a class that are


called when an object is created. They are used to initialize the
object's attributes and perform any necessary setup.

Example of a constructor in Python:

class Person:
def __init__(self, name, age):
self.name = name
self.age = age

person = Person("John", 25)

● Destructors: Destructors are special methods that are called when


an object is destroyed or goes out of scope. They are used to
perform cleanup tasks or release resources associated with the
object.

Destructor example in Python:

class Person:
def __init__(self, name):
self.name = name

def __del__(self):
print("Destructor called")

person = Person("John")
del person # Destructor called

By: Waleed Mousa


11.5 Abstraction and Interfaces

● Abstraction: Abstraction is the process of hiding unnecessary


details and exposing only essential information to the user. It
allows programmers to focus on high-level concepts without
worrying about the implementation details.
● Interfaces: An interface defines a contract that specifies a set of
methods that a class implementing the interface must provide.
Interfaces allow for loose coupling between components and promote
code modularity and flexibility.

Understanding object-oriented programming concepts empowers you to


build modular and maintainable code, model real-world scenarios
effectively, and promote code reusability.

Section 12: Regular Expressions


Regular expressions (regex) are sequences of characters that form a
search pattern. This pattern can be used to match, locate, and manage
text. Regular expressions can check if a string contains the specified
search pattern. They are extremely powerful and used in many fields,
including programming and computer science.

12.1 Basics of Regular Expressions

Here are some basic elements of regular expressions:

● Literal Characters: The most basic regular expression consists of


a single literal character; e.g. a.
● Metacharacters: Characters that have special meaning: . ^ $ * + ?
{ } [ ] \ | ( )
● Special Sequences: \d, \D, \s, \S, \w, \W, \b, \B etc. They make
some common patterns easier to write.
● Sets: A set is a set of characters inside a pair of square
brackets [] with a special meaning.

By: Waleed Mousa


For example, in Python:

import re

txt = "Hello, my phone number is 123-456-7890."


x = re.findall("\d", txt)
print(x) # prints ['1', '2', '3', '4', '5', '6', '7', '8', '9', '0']

In this example, we use \d to find all digit characters in a text.

12.2 Advanced Regular Expression Patterns

In addition to the basics, regular expressions can be very complex:

● Quantifiers: *, +, ?, {3}, {3,6} for specifying quantities of


characters.
● Grouping: Parentheses () for defining scope and logical groups.
● Pipe: | for OR operation.
● Escape special characters: Use \ before special characters.

For example, in Python:

import re

txt = "Hello, my phone number is 123-456-7890."


x = re.findall("\d{3}-\d{3}-\d{4}", txt)
print(x) # prints ['123-456-7890']

In this example, we use {3} to specify that we want to find exactly


three digits.

12.3 Use Cases of Regular Expressions

Regular expressions are used in search algorithms, search and replace


dialogs of text editors, input validators, parsers, and more. They can
be used in almost all programming languages like Python, JavaScript,
Java, etc.

Some common use cases include:

● Data Validation (e.g. check if a user input is a valid email or


phone number)

By: Waleed Mousa


● Data Scraping (e.g. extract all email addresses from a webpage)
● Text Manipulation (e.g. replace all occurrences of a specific
string)
● Syntax Highlighting in IDEs
● File renaming, searching, and so on.

Section 13: Concurrency and Multithreading


Concurrency and multithreading are fundamental concepts in computer
science that allow multiple sequences of operations to be executed in
overlapping periods of time.

13.1 Basics of Concurrency and Multithreading

Concurrency refers to the ability of different parts or units of a


program, algorithm, or problem to be executed out-of-order or in
partial order, without affecting the final outcome.

Multithreading is a specialized form of multitasking and a multitasking


is the feature that allows your computer to run two or more programs
concurrently. In general, there are two types of multitasking:
process-based and thread-based.

Example (Python):

import threading

def print_numbers():
for i in range(10):
print(i)

def print_letters():
for letter in 'abcdefghij':
print(letter)

thread1 = threading.Thread(target=print_numbers)
thread2 = threading.Thread(target=print_letters)

thread1.start()
thread2.start()

By: Waleed Mousa


thread1.join()
thread2.join()

In this example, two threads are created: one to print numbers from 0
to 9, and the other to print letters from 'a' to 'j'. The threads are
started with start(), and join() is used to make sure the program waits
for both threads to finish before it terminates.

13.2 Thread Synchronization

Thread synchronization is defined as a mechanism which ensures that two


or more concurrent threads do not simultaneously execute some
particular program segment known as critical section.

Example (Python):

import threading

class BankAccount:
def __init__(self):
self.balance = 100 # shared resource
self.lock = threading.Lock()

def update(self, change):


with self.lock:
self.balance += change

account = BankAccount()
thread1 = threading.Thread(target=account.update, args=[50])
thread2 = threading.Thread(target=account.update, args=[-75])

thread1.start()
thread2.start()

thread1.join()
thread2.join()

print(account.balance) # prints 75

In this example, a BankAccount object has a balance that is shared


between two threads. The update method, which modifies the balance, is a
critical section that must not be executed by multiple threads at the

By: Waleed Mousa


same time. This is ensured by acquiring a lock before modifying the
balance, and releasing the lock afterwards.

13.3 Deadlocks and Race Conditions

Deadlocks and race conditions are two of the main issues in concurrent
programming.

● Deadlock is a state in which each member of a group is waiting for


some other member to take action, such as sending a message or
more commonly releasing a lock.
● Race condition occurs when two or more operations must execute in
the correct order, but the program has not been written so that
this order is guaranteed to be maintained.

Section 14: Networking Basics


Networking is the practice of connecting computers and other devices
together to share resources.

14.1 Introduction to Networking

Networking is essential in today's computer world. With networking, you


can share resources like files, printers, and internet connections
between computers.

In a computer network, computers can be connected through cables, via


radio waves, and over telephone lines. Examples of computer networks
are the Internet, which connects millions of people globally, and Local
Area Networks (LANs), which might connect computers in your home,
school, or office.

14.2 Understanding HTTP/HTTPS

HTTP stands for Hypertext Transfer Protocol and is used for


transmitting hypermedia documents (like HTML) on the internet. It
defines commands and services used for transmitting webpage data.

By: Waleed Mousa


HTTPS, or HTTP Secure, is an extension of HTTP. It's used for secure
communication over a computer network and is widely used on the
internet. It encrypts the data being sent between the browser and the
server to prevent eavesdropping or tampering with the data.

14.3 Overview of TCP/IP

TCP/IP stands for Transmission Control Protocol/Internet Protocol,


which is a suite of communication protocols used to interconnect
network devices on the internet. TCP/IP can also be used as a
communications protocol in a private computer network (an intranet or
an extranet).

The entire Internet Protocol suite -- a set of rules and procedures --


is commonly referred to as TCP/IP. TCP and IP are the two main
protocols in the suite.

● TCP takes care of the data delivery, but it doesn't worry about
the packet structure or the control of the network.
● IP takes care of the routing of packets. It is responsible for
getting each packet of data to the right destination.

14.4 Web Sockets

WebSockets is a communication protocol that provides full-duplex


communication channels over a single TCP connection. It's used in web
applications to provide real-time functionality.

WebSocket is designed to be used in web browsers and web servers, but


it can be used by any client or server application. The WebSocket
Protocol is an independent TCP-based protocol.

Section 15: Databases and SQL


Databases are organized collections of data. SQL (Structured Query
Language) is a programming language used to manage and manipulate
databases.

By: Waleed Mousa


15.1 Introduction to Databases

At the core, a database is an organized collection of data. More


formally, it's a collection of related data entries that serves
multiple uses.

Databases are useful for storing information categorically. For


example, a company might have a database with the following tables:
"Employees", "Products", "Customers", and "Orders".

15.2 SQL Basics

SQL is a language designed to interact with data stored in a relational


database management system (RDBMS), or for stream processing in a
relational data stream management system (RDSMS). It is particularly
useful in handling structured data, i.e., data incorporating relations
among entities and variables.

Here's a very basic example of an SQL query:

SELECT * FROM Employees WHERE Salary > 50000;

This SQL query selects all fields from the "Employees" table where the
"Salary" field is greater than 50000.

15.3 Indexing and Normalization

Indexing in databases is a way to improve the performance of database


operations. An index is a data structure that improves the speed of
data retrieval operations on a database table.

Normalization is the process of efficiently organizing data in a


database. There are two goals of the normalization process: eliminating
redundant data (for example, storing the same data in more than one
table) and ensuring data dependencies make sense (only storing related
data in a table).

By: Waleed Mousa


15.4 Introduction to NoSQL

NoSQL databases are a type of database that can handle and sort all
kinds of data, everything from unstructured text documents to
structured data. NoSQL databases became popular as web applications
become more complex and required more diverse ways to store and query
data.

The four main types of NoSQL databases are:

1. Document databases: Store data in documents similar to JSON


(JavaScript Object Notation) objects. Each document can contain
pairs of fields and values.
2. Key-value stores: Every single item in the database is stored as
an attribute name (or 'key'), together with its value.
3. Wide-column stores: Instead of tables, you have column families,
which are containers for rows. Unlike relational databases, you
can have billions of columns, and rows don't have to have the same
columns.
4. Graph databases: Store data in nodes, which is the equivalent of a
record in a relational database, and edges, which represent
connections between nodes.

Section 16: Design Patterns


Design patterns are solutions to common problems in software design.
Each pattern is like a blueprint that you can customize to solve a
particular design problem in your code.

16.1 Introduction to Design Patterns

Design patterns can speed up the development process by providing


tested, proven development paradigms. Effective software design
requires considering issues that may not become visible until later in
the implementation.

Design patterns are categorized into three main groups: Creational,


Structural, and Behavioral patterns.
By: Waleed Mousa
16.2 Structural Design Patterns

Structural Design Patterns deal with object composition and typically


identify simple ways to realize relationships among entities.

1. Adapter Pattern: Allows classes with incompatible interfaces to


work together by wrapping its own interface around that of an
already existing class.
2. Decorator Pattern: Used to add new functionality to an existing
object, without being obtrusive.
3. Proxy Pattern: Used to provide a surrogate or placeholder for
another object to control access to it.

16.3 Behavioral Design Patterns

Behavioral patterns are concerned with algorithms and the assignment of


responsibilities between objects.

1. Observer Pattern: Defines a one-to-many dependency between objects


so that when one object changes state, all its dependents are
notified and updated automatically.
2. Strategy Pattern: Encapsulates an algorithm inside a class
separating the selection from the implementation.
3. State Pattern: Allows an object to alter its behavior when its
internal state changes.

16.4 Creational Design Patterns

Creational patterns deal with object creation mechanisms, trying to


create objects in a manner suitable to the situation.

1. Singleton Pattern: Ensures that a class only has one instance, and
provide a global point of access to it.
2. Factory Method Pattern: Defines an interface for creating an
object, but lets subclasses decide which class to instantiate.
3. Abstract Factory Pattern: Provides an interface for creating
families of related or dependent objects without specifying their
concrete classes.

By: Waleed Mousa


Design patterns can provide significant benefits, but they also have
their disadvantages. It's important to know them well enough to know
when to apply them and when to avoid them.

Section 17: Web Development Basics


Web development is the practice of creating or developing websites or
web pages hosted on the Internet or intranets.

17.1 Overview of Web Development

Web development is a broad term that involves the work of creating a


website for the Internet or an intranet (private network). It can range
from developing a simple single static page of plain text to complex
web applications, electronic businesses, and social network services.

Web development typically involves server-side scripting (backend),


client-side scripting (frontend), and database technology.

17.2 HTML Basics

HTML stands for Hyper Text Markup Language. It is used to describe the
structure of web pages using markup. HTML elements are the building
blocks of HTML pages and are represented by tags.

A very simple HTML document might look like this:

<!DOCTYPE html>
<html>
<head>
<title>Page Title</title>
</head>
<body>
<h1>My First Heading</h1>
<p>My first paragraph.</p>
</body>
</html>

By: Waleed Mousa


17.3 CSS Basics

CSS stands for Cascading Style Sheets. It is used to control the style
and layout of multiple web pages all at once.

A simple example of CSS could look like this:

body {
background-color: lightblue;
}

h1 {
color: navy;
margin-left: 20px;
}

17.4 Introduction to JavaScript

JavaScript is a programming language that adds interactivity to your


website. This could be anything from a simple alert that pops up on
your screen to complex animations and 3D graphics.

Here's a basic example of JavaScript:

document.getElementById("demo").innerHTML = "Hello, World!";

17.5 Understanding Frontend and Backend Development

Frontend and backend development are two sides of the same coin. The
frontend of a web application is the part that users interact with.
It's built with languages like HTML, CSS, and JavaScript.

The backend of a web application is responsible for things like


calculations, business logic, database interactions, and performance.
Most of the code that is required to make an application work will be
done on the backend. Languages used for the backend include PHP, Ruby,
Python, Node.js, and more.

By: Waleed Mousa


Section 18: Scripting and Automation
Scripting and automation are powerful tools in the programmer's
toolkit. They can save time and effort by automating repetitive tasks,
and can also perform complex tasks with precision and consistency.

18.1 Introduction to Scripting and Automation

Scripting is a type of programming that is used to automate the


execution of tasks which could alternatively be executed one-by-one by
a human operator. Scripting languages are often interpreted (rather
than compiled), and tend to focus on automating common tasks.

Automation, as the name suggests, is the creation and application of


technologies to produce and deliver goods or services with minimal
human intervention. When applied to programming, it's about making your
software do as much work as possible, to save you having to do it!

18.2 Scripting Languages Overview

There are many scripting languages, each with its own strengths and
purposes. Here are a few examples:

● Bash: A Unix shell and command language, good for file manipulation
and program execution.
● Python: A high-level, interpreted language, Python is often used
for web and Internet development, scientific applications, data
analysis, and more.
● JavaScript: Primarily used in web development to add interactivity
to web pages.
● Ruby: A dynamic, open-source programming language with a focus on
simplicity and productivity. It has an elegant syntax that is easy
to read and write.
● Perl: A highly capable, feature-rich programming language with
over 30 years of development.

By: Waleed Mousa


18.3 Examples of Automation Scripts

Here's an example of a simple automation script in Python that renames


all files in a directory to lowercase:

import os

def rename_files():
file_list = os.listdir(r"<path to directory>")
os.chdir(r"<path to directory>")
for file_name in file_list:
os.rename(file_name, file_name.lower())

rename_files()

This script does the following:

1. Import the os module which provides a way of using operating


system dependent functionality.
2. Define a function called rename_files.
3. Get a list of all the files in a directory.
4. Change the current working directory to the specified path.
5. Iterate over every file in the directory and rename the file.

Section 19: Debugging and Testing

19.1 Debugging Techniques and Tools

Debugging is the process of identifying and fixing errors or bugs in


your code. Here are some techniques and tools to assist you in
debugging:

● Print Statements: Inserting print statements in your code to


display the values of variables at specific points can help track
the flow of execution and identify issues.

print(variable_name)

By: Waleed Mousa


● Debuggers: Debuggers are tools provided by programming
environments that allow you to step through your code, set
breakpoints, and inspect variables at runtime. They provide a more
interactive and detailed debugging experience.

import pdb
pdb.set_trace() # Set a breakpoint

● Logging: Logging libraries allow you to record information,


warnings, and errors during program execution. They provide a
systematic way to gather information and identify issues.

import logging
logging.basicConfig(level=logging.DEBUG)
logging.debug("Debug message")
logging.error("Error message")

19.2 Writing Test Cases

Testing is a crucial part of the software development process. Writing


test cases helps ensure the correctness and reliability of your code.
Test cases typically fall into three categories:

● Unit Tests: Test individual units of code, such as functions or


methods, in isolation. They ensure that each unit performs as
expected.

import unittest

def add_numbers(a, b):


return a + b

class TestAddNumbers(unittest.TestCase):
def test_add_numbers(self):
result = add_numbers(2, 3)
self.assertEqual(result, 5)

if __name__ == '__main__':
unittest.main()

By: Waleed Mousa


● Integration Tests: Test the interaction and compatibility between
different units or components of your code. They ensure that the
units work correctly together.

import unittest

def multiply(a, b):


return a * b

class TestMultiply(unittest.TestCase):
def test_multiply(self):
result = multiply(2, 3)
self.assertEqual(result, 6)

if __name__ == '__main__':
unittest.main()

● System Tests: Test the entire system or application to validate


its behavior and functionality from end to end. They mimic
real-world scenarios and user interactions.

19.3 Unit Testing Basics

Unit testing is the process of testing individual units of code to


ensure they function correctly. Here are some basic principles of unit
testing:

● Test Coverage: Aim to test as many possible code paths and


scenarios as you can to achieve high test coverage. This helps
uncover potential issues and ensure the reliability of your code.
● Test Automation: Automate your tests whenever possible to enable
efficient and consistent testing. Automation frameworks, such as
unittest in Python, provide tools and assertions to simplify the
test-writing process.
● Test Isolation: Test each unit of code in isolation, without
dependencies on external factors or other units. This ensures that
any failures can be easily identified and isolated to the specific
unit being tested.

By: Waleed Mousa


Testing your code thoroughly helps identify and address issues early,
leading to more robust and stable software.

Section 20: Version Control and Collaboration

20.1 Introduction to Version Control Systems (VCS)

Version Control Systems (VCS) are tools that help manage changes to
source code and facilitate collaboration among developers. VCS allows
you to track modifications, revert to previous versions, and merge
changes made by multiple developers.

● Centralized VCS: In centralized VCS, there is a central repository


that stores the code, and developers check out and check in code
changes from that repository. Examples include CVS and Subversion
(SVN).
● Distributed VCS: Distributed VCS allows each developer to have a
complete copy of the code repository, including its history.
Developers can commit changes to their local repositories and
later synchronize with the main repository. Examples include Git
and Mercurial.

20.2 Repository Management

Version control systems manage code repositories, which store the code
and its history. Repository management involves tasks such as creating,
cloning, and managing branches.

● Creating a Repository: Initialize a new repository or create a new


one using the VCS command-line or graphical interface.

git init # Initialize a new Git repository

● Cloning a Repository: Clone an existing repository to create a


local copy of the codebase.

git clone <repository_url> # Clone a Git repository

By: Waleed Mousa


● Branching: Create branches to isolate changes and work on separate
features or fixes without affecting the main codebase.

git branch <branch_name> # Create a new branch


git checkout <branch_name> # Switch to a branch

20.3 Collaborative Development

Version control systems enable collaborative development, allowing


multiple developers to work together on the same codebase.
Collaboration involves tasks such as committing changes, merging code,
and resolving conflicts.

● Committing Changes: Save changes made to the code locally, with an


associated commit message explaining the changes.

git add <file_name> # Stage changes for commit


git commit -m "Commit message" # Commit changes

● Merging Code: Integrate changes from one branch into another,


combining the code modifications.

git merge <branch_name> # Merge changes from branch_name into the current
branch

● Resolving Conflicts: Conflicts may occur when merging if two or more


developers have made conflicting changes to the same code. Resolve
conflicts by manually editing the conflicting files and choosing the
correct changes.

# Git will mark conflicts in the file. Edit the file to resolve conflicts and
choose the desired changes.
git add <file_name> # Stage the resolved file
git commit -m "Merge conflict resolution" # Commit the merged changes

Collaborative development using version control systems allows for


efficient teamwork, easy code sharing, and effective code management.

By: Waleed Mousa


Section 21: Software Development Life Cycle (SDLC)

21.1 Overview of SDLC Phases

The Software Development Life Cycle (SDLC) is a framework that outlines


the process of developing software applications. SDLC consists of
several phases, each with its own objectives and activities. The common
phases include:

1. Requirements Gathering: Gathering and documenting the functional


and non-functional requirements of the software.
2. System Design: Creating a high-level design that outlines the
system architecture, modules, and their interactions.
3. Coding and Implementation: Writing the code for the software
application based on the design specifications.
4. Testing: Performing various testing activities to validate the
software and ensure it meets the requirements.
5. Deployment: Releasing the software to the production environment
for end-users to access and use.
6. Maintenance: Monitoring, maintaining, and enhancing the software
based on user feedback and changing requirements.

21.2 Agile vs. Waterfall Methodologies

There are different methodologies that can be followed within the SDLC.
Two popular approaches are Agile and Waterfall:

● Waterfall Methodology: The Waterfall methodology follows a


sequential, linear approach, where each phase is completed before
moving to the next one. It is suitable for projects with
well-defined and stable requirements.
● Agile Methodology: The Agile methodology emphasizes flexibility,
collaboration, and iterative development. It involves dividing the
project into sprints or iterations, allowing for continuous
feedback and adaptation to changing requirements.

By: Waleed Mousa


21.3 Project Management Tools

Project management tools help manage and track the progress of software
development projects. They provide features for task tracking, team
collaboration, and overall project management. Some popular project
management tools include:

● JIRA: JIRA is a versatile project management tool that supports


Agile methodologies. It allows for creating and tracking tasks,
managing backlogs, and visualizing project progress.
● Trello: Trello is a simple and user-friendly project management
tool that uses boards, lists, and cards to manage tasks and
collaborate with team members.
● Asana: Asana is a comprehensive project management tool that
offers features for task management, team collaboration, and
project tracking.

These tools provide a centralized platform for managing and organizing


project tasks, communication, and collaboration among team members.

Understanding the Software Development Life Cycle (SDLC) and utilizing


project management tools help streamline the development process,
ensure efficient project execution, and deliver high-quality software
applications.

By: Waleed Mousa

You might also like