read 62 min
74 / 79
Apr 14

:rocket:Day 60 | Boost Performance Without Breaking the Bank: Server Optimization Tips for SWE

When your application starts slowing down, the knee-jerk reaction is to pay for more server space. But why not first squeeze every bit of performance out of your existing setup? Here’s a technical deep dive into some crucial optimizations that can make a world of difference before you open your wallet.

  1. :mag_right: Indexing Matters
    Poor indexing is one of the primary culprits behind sluggish database queries. Before investing in bigger servers, take a close look at your database schema:
    Create Indexes on Frequently Queried Fields: Identify columns that are frequently involved in WHERE, JOIN, and ORDER BY clauses.
    Composite Indexes: Combine multiple columns when they are commonly used together.
    Clustered vs. Non-Clustered: Choose wisely based on your data retrieval patterns.
    Regularly Update Statistics: Keep the query optimizer informed about data distribution.

  2. :vertical_traffic_light: Optimize Your Queries
    Even well-indexed databases can struggle if your queries are inefficient.
    Use Query Profiling Tools: PostgreSQL’s EXPLAIN, MySQL’s EXPLAIN ANALYZE, or SQL Server’s Query Analyzer are invaluable.
    Minimize Select Statements: Instead of SELECT *, specify only the columns you need.
    Avoid Subqueries When Possible: Use joins or common table expressions (CTEs) instead.
    Batch Your Updates: Instead of executing multiple small updates, combine them into one.
    Prepared Statements: Leverage them to improve performance and security.

  3. :bar_chart: Caching Is Your Best Friend
    If your application constantly retrieves the same data, you’re wasting server resources. Implement caching at multiple levels:
    In-Memory Caching: Use Redis or Memcached for rapid data retrieval.
    HTTP Caching: Leverage response caching and cache headers for static resources.
    Application-Level Caching: Cache expensive computations and frequently accessed data.
    Database Query Caching: Store the results of common queries.

  4. :gear: Efficient Data Storage
    Bloated databases can drastically slow performance. Keep your data lean and mean:
    Archive Old Data: Move less frequently accessed data to cheaper storage solutions.
    Partitioning: Split large tables to reduce the scanning effort.
    Data Compression: Compress old logs and rarely accessed datasets.
    Garbage Collection: Periodically clean up temporary tables and expired data.

  5. :computer: Load Balancing and Traffic Distribution
    If your application is highly trafficked, distributing the load can significantly improve performance:
    Reverse Proxying: Use NGINX or HAProxy to balance incoming requests.
    Horizontal Scaling: Add more instances rather than increasing individual server specs.
    Content Delivery Networks (CDN): Serve static assets from edge locations for quicker delivery.

Stay tuned for a part 2!

100daysofcode lebanon-mug

Day 61 | The Common Mistake of Newbies

When building web applications, many developers implement role-based access control (RBAC) to ensure that only authorized users can access certain pages or features. However, a common mistake among newbies is hiding protected routes only on the frontend without properly securing them on the backend. This creates a serious security vulnerability, allowing unauthorized users to bypass client-side restrictions and access sensitive data or functionality. Let’s explore why this happens, the risks involved, and how to fix it properly. :closed_lock_with_key:

The Mistake: Frontend-Only Protection :construction:
Many developers rely on frontend frameworks to handle routing and conditionally display content based on user roles. While this may seem like an effective way to restrict access, it only prevents unauthorized users from seeing certain UI elements. It does not actually prevent them from accessing restricted resources or performing actions directly on the backend.
The frontend is fully accessible to users, meaning they can inspect and modify it using developer tools. If the backend does not have proper role-based authorization, attackers can bypass frontend restrictions and make direct requests to restricted endpoints.

The Risks: Why This Is Dangerous :warning:
Direct API Access: Without backend authorization, an attacker can send requests to restricted endpoints using external tools, even if they cannot access them through the UI.

Client-Side Tampering: Since frontend logic runs in the browser, users can modify it to remove restrictions and gain unauthorized access.
Security Through Obscurity Is Not Security: Just because something is hidden on the frontend doesn’t mean it is protected. Sensitive operations remain exposed if the backend does not enforce security.
Unauthorized Data Exposure: If the backend does not validate user roles, attackers may access confidential data intended only for specific roles.

The Fix: Proper Backend Authorization :white_check_mark:
The correct way to secure protected routes is to enforce RBAC on the backend as well. This means ensuring that every request to sensitive resources is verified against user roles before granting access.

  1. Enforce Role-Based Authorization on Every Request :shield:
    The backend should check the user’s role before processing any request to protected resources. Simply preventing access through the UI is not enough.

  2. Use Centralized Role-Based Access Control :arrows_counterclockwise:
    Instead of implementing role validation separately for each action, a centralized mechanism should handle access control across the application. This reduces redundancy and ensures consistency in security policies.

  3. Secure API Calls with Authentication and Permissions :key:
    Authentication mechanisms such as token-based authentication should be used to verify user identity and role. This ensures that only authorized users can access certain functionalities, even if they attempt to bypass frontend restrictions.

100daysofcode lebanon-mug

Day 62 | :rocket: Kickstarting My SQL Series: The Foundation of Data Modeling with the ER Model!

Hey #LinkedInCommunity! :wave: Excited to launch my SQL series with a deep dive into one of the most fundamental concepts in database design—the Entity-Relationship (ER) Model! :bulb:

Where It All Began

The ER model was introduced in 1976 by the brilliant Professor Peter Chen (Chen Pin-Shan) :mortar_board:. His groundbreaking paper laid the foundation for how we visualize and structure data relationships today. Before ER, database design was more abstract—Chen gave us a clear, graphical way to map entities, attributes, and relationships.

Why Does the ER Model Matter? :thinking:

Visual Clarity :pencil2:: It turns complex data structures into easy-to-understand diagrams.

Blueprint for Databases :building_construction:: Serves as the first step before writing SQL schemas.

Improves Efficiency :zap:: Helps spot design flaws early, saving time and headaches later.

Key Components

:heavy_check_mark: Entities → Real-world objects (e.g., Customer, Product)

:heavy_check_mark: Attributes → Properties of entities (e.g., CustomerID, ProductName)

:heavy_check_mark: Relationships → How entities interact (e.g., Customer buys Product)

Stay tuned for Part 2, where we’ll translate ER diagrams into SQL tables! :card_index_dividers:

:speech_balloon: Discussion Time!

How has the ER model helped you in your projects?

Any database design challenges you’ve faced?

#sql 100daysofcode lebanon-mug

Day 63 |:mag: Mastering Weak Entity Sets, Cardinalities, Specialization & Generalization in Databases! :bulb:

Data modeling is the backbone of efficient databases, and understanding key Entity-Relationship (ER) model concepts is crucial. Let’s break down four essential concepts:

:small_blue_diamond: Weak Entity Sets
Not all entities are independent! Some lack a primary key and must rely on a strong entity through a relationship set. These are called weak entity sets and must have:
:white_check_mark: A discriminator (partial key) to differentiate among instances.
:white_check_mark: A total participation constraint, meaning they must be linked to a strong entity.
:white_check_mark: A supporting relationship, called an identifying relationship, that connects them to a strong entity.
:hammer_and_wrench: Example: Consider an Employee-Dependent relationship. A Dependent (child/spouse) doesn’t have a unique identifier but can be identified using Employee_ID + Dependent_Name. Without linking to an Employee, the Dependent entity has no existence in the database.

:small_blue_diamond: Cardinalities & Relationship Constraints
Cardinality defines how many instances of an entity can be related to another. Understanding this ensures data integrity and efficient queries.
:pushpin: Types of Cardinality:
:small_blue_diamond: One-to-One (1:1): Each entity in A maps to at most one entity in B.
:point_right: Example: A person has one passport, and each passport belongs to one person.
:small_blue_diamond: One-to-Many (1:M): An entity in A maps to multiple entities in B.
:point_right: Example: A manager supervises multiple employees, but each employee has only one manager.
:small_blue_diamond: Many-to-Many (M:N): Each entity in A relates to multiple entities in B, and vice versa.
:point_right: Example: Students enroll in multiple courses, and each course has multiple students.

:small_blue_diamond: Specialization vs. Generalization
As databases grow, organizing data becomes vital. This is where specialization and generalization help refine entity structures.
:small_blue_diamond: Specialization (Top-Down Approach):
We start with a generic entity and divide it into sub-entities based on distinguishing characteristics.
:point_right: Example: A Vehicle entity specializes into Car :red_car: and Bike :motorcycle:. Cars have a fuel type, while bikes may not.
:small_blue_diamond: Generalization (Bottom-Up Approach):
Here, we merge multiple similar entities into a higher-level super-entity to avoid redundancy.
:point_right: Example: A Doctor :man_health_worker: and a Nurse :woman_health_worker: share common attributes (e.g., Name, Salary), so they generalize into MedicalStaff.
:small_blue_diamond: Why Does This Matter?
:bulb: Weak entity sets prevent orphaned data in relationships.
:bulb: Cardinalities enforce integrity, ensuring logical data mapping.
:bulb: Specialization adds precision, while generalization reduces redundancy.

Mastering these concepts leads to better data normalization, query performance, and scalability! :rocket:

Which of these have you used in your projects? Drop your thoughts in the comments! :speech_balloon:

100daysofcode lebanon-mug

:rocket: Day 64: Understanding the Relational Model and Ensuring Consistency

Databases are everywhere, powering applications that range from social media platforms to financial systems. But how do we make sure that the data inside them is reliable, consistent, and useful? Today, we’re diving into the relational model, one of the most robust ways to manage structured data. We’ll also explore how to maintain database consistency—a critical aspect that ensures your data remains trustworthy.

:memo: Relational Model Basics

The relational model, introduced by E. F. Codd in 1970, revolutionized data storage by structuring data into tables (relations). It offers a logical way to represent data independently from the physical storage. Let’s break down the essential terms in both informal and mathematical contexts:

Informal Term Mathematical Term Example
Table Relation Student information
Row (record) Tuple (123, ‘John’, ‘CS’)
Column Attribute Student ID, Name, Major
Data Type Domain Integer, String

The relational model is fundamentally about relations (or tables), where each relation consists of tuples (or rows), each described by a set of attributes (or columns). The domain of an attribute defines its possible values, like numbers or strings.

:white_check_mark: Consistent vs. Inconsistent Databases

Let’s say you manage a database of student records. A consistent database might have a student with ID 123 listed as “John Smith” in both the Enrollment and Grades tables. An inconsistent database could show the same ID linked to two different names across these tables. Such inconsistencies are more than just nuisances—they can undermine trust and break system functionality.

:key: Maintaining Database Consistency

Maintaining consistency is crucial to ensure that data across tables and applications remains accurate and reliable. Here are some key techniques:

1. Normalization

Breaking data into smaller, non-redundant tables reduces the chances of inconsistency. Normalization ensures that one piece of information is stored only once.

2. Constraints

Apply integrity constraints like primary keys, foreign keys, and unique constraints to enforce data consistency. This means that records are uniquely identified and linked properly between tables.

3. ACID Properties

Database transactions should follow ACID (Atomicity, Consistency, Isolation, Durability) principles to ensure that operations either complete successfully or leave the database unchanged. This is especially important when performing multiple updates or batch operations.

4. Data Validation

Validate data both at the application level and database level. Use triggers or check constraints to automatically verify data before insertion or update.

5. Backup and Recovery

Maintaining consistency also involves periodic backups and implementing recovery mechanisms. This helps revert to a previous consistent state in case of system failures.

:construction: Common Pitfalls

  1. Circular References: Linking tables in a circular way can result in inconsistencies and difficulties in maintaining data integrity.
  2. Improper Use of NULL: Overuse or misuse of NULL values can lead to ambiguity in data interpretation.
  3. Schema Drift: Unplanned changes to the database schema can introduce inconsistencies.

:bulb: Key Takeaways

Maintaining a consistent database is not just about technical correctness but also about maintaining data integrity and trustworthiness. By understanding the relational model and implementing consistency practices, you can build reliable and scalable systems.

Got thoughts on relational models? Share your experiences or challenges in the comments below! :speech_balloon:

100daysofcode lebanon-mug

Day 65 | SQL Basics: Schema, Tables, Primary & Foreign Keys Explained! :bulb:

In the world of SQL, structuring your data efficiently is the key to building scalable and organized databases. Whether you’re just starting out or brushing up on your skills, understanding schemas, tables, primary keys, and foreign keys is crucial! Let’s dive into the essentials! :ocean:

:card_index_dividers: Schema

A schema is like a container for your database objects - think of it as an organizational unit! It holds tables, views, and other objects, allowing for better structure and access control.

Imagine you’re managing a company database. You might have a schema named CompanyDB to hold all related tables, such as employees, departments, and projects.

:key: Syntax:

sql

CREATE SCHEMA CompanyDB;

:bar_chart: Tables

Tables are where your data lives! They consist of rows and columns, each column having a specific data type (like INTEGER, VARCHAR, or DATE).

For example, in our company database, we might have:

Employee table for personal details

Dependent table for employee dependents

Department table for different departments

Project table for ongoing projects

WorksOn table to track which employee works on which project

:key: Syntax:

sql

CREATE TABLE Employee (

emp_id INT PRIMARY KEY, first_name VARCHAR(50), last_name VARCHAR(50), dept_id INT

);

:key: Primary Key

A primary key uniquely identifies each row in a table. No two rows can have the same primary key, ensuring data integrity.

In the Employee table, the emp_id column is the primary key, making each employee uniquely identifiable.

:key: Syntax:

sql

PRIMARY KEY (emp_id)

:link: Foreign Key

A foreign key creates a link between two tables. It enforces relationships and maintains referential integrity between data. For instance, the WorksOn table needs to link employees to projects.

:key: Syntax:

sql

CREATE TABLE WorksOn (

emp_id INT, proj_id INT, hours_worked DECIMAL(5,2), FOREIGN KEY (emp_id) REFERENCES Employee(emp_id), FOREIGN KEY (proj_id) REFERENCES Project(proj_id)

);

:memo: Example: Database Design

Here’s how the design fits together:

Employee table holds employee data.

Dependent table stores employee-dependent details.

Department table keeps department info.

DepLocation table tracks where departments are located.

Project table holds project details.

WorksOn table records which employees are assigned to which projects.

These tables are linked through primary and foreign keys, creating a robust relational database that minimizes redundancy! :link::sparkles:

:bulb: Why It Matters

Efficient database design helps maintain data consistency and integrity. By leveraging schemas and relational keys, you’re building a scalable structure that can grow with your data needs. :rocket:

Whether you’re a beginner or a pro, mastering these SQL fundamentals will set you up for success. Happy coding! :sunglasses:

100daysofcode lebanon-mug

Day 66 |:rocket: Overcoming Imposter Syndrome as a Junior Software Engineer :woman_technologist::man_technologist:

Let’s talk about something many of us in tech rarely say out loud: Imposter Syndrome. That nagging feeling that you’re not good enough, that you don’t belong, or worse — that someone’s going to “find out” you’re faking it. :performing_arts:

As a junior software engineer, I’ve felt it. You’ve probably felt it.

:mag: Why It’s So Common in Tech

Software engineering moves fast. Every day there’s a new framework, a new best practice, or a GitHub repo that makes you question your existence. :sweat_smile:

We work in environments that often reward output over learning, and it’s easy to feel like you’re falling behind — especially when:

:computer: You’re struggling to understand legacy code

:gear: You can’t fix a bug after 3 hours of trying

:brain: Everyone seems to “get it” except you

Spoiler: They don’t. They’re just googling faster.

:jigsaw: Imposter Syndrome ≠ Incompetence

In fact, feeling like an imposter is often a sign of growth. You’re challenging yourself. You’re out of your comfort zone — and that’s where learning happens.

But it can be paralyzing if left unchecked.

:hammer_and_wrench: What Actually Helps

Talk About It

Open up to teammates, mentors, or LinkedIn folks. You’ll be surprised how many people feel the same.

Join a CS Club or Tech Community :handshake:

Seriously, don’t go through this journey alone. Whether it’s a university CS club, a local dev group, or an online community — surrounding yourself with others who are learning, building, and sharing is game-changing. You’ll learn faster, feel less isolated, and stay inspired.

Track Your Progress :chart_with_upwards_trend:

Keep a “brag doc” — a list of bugs you fixed, features you shipped, or even concepts you understood better. Watch how far you’ve come!

Ask Questions — Fearlessly :question:

Asking doesn’t make you look dumb. It shows you’re engaged and willing to grow.

Stay Curious & Excited :star2:

Let your passion lead you. Tinker with side projects, explore new tech, attend hackathons — curiosity is your superpower. The more excited you stay, the faster the fear fades.

Don’t Compare Your Chapter 1 to Someone Else’s Chapter 20 :books:

Your senior might seem like a wizard now, but they were once stuck on their first null pointer exception too.

Practice Self-Compassion :person_in_lotus_position:

Tech is hard. You’re not supposed to know everything. You’re supposed to learn.

:brain: Final Thought

If you’re a junior SWE battling self-doubt, just remember:

You’re not an imposter. You’re a beginner. And beginners grow.

Stay curious. Stay excited. Keep learning. You’ve got this. :rocket::heart_on_fire:

100daysofcode lebanon-mug

:brain: Day 67 | Why Mastering DSA Still Matters in 2025

Whether you’re building scalable systems, optimizing a product, or cracking the next coding interview — Data Structures & Algorithms (DSA) remain foundational to success in tech. Yet many overlook it, dismissing it as “just interview prep” or “academic theory.” That mindset is costing developers long-term growth.
Here’s why DSA still matters — and why I’m starting this new series:
:small_blue_diamond: Problem Solving Muscle
At its core, DSA trains your brain to approach challenges methodically. It’s like going to the gym for your logic — improving how you think, not just what you code.
:small_blue_diamond: Real-World Optimization
Understanding time and space complexity isn’t just for whiteboard interviews. It translates directly to efficient code in real-life applications:
• A faster search algorithm in an e-commerce backend
• Memory-optimized data handling for edge devices
• Reduced latency in real-time systems
:small_blue_diamond: Systems Design Foundation
Before you scale, you simplify. Before you scale, you structure. Knowing when to use a hash map over a tree or why a heap can outperform a queue — that’s DSA in action. It gives you the building blocks that enable high-level design.
:small_blue_diamond: Interview-Ready, Yes — But Career-Ready Too
Mastering DSA isn’t just about passing tech interviews. It’s about having confidence when faced with ambiguous problems and being able to engineer clean, efficient, maintainable solutions.

:rocket: What’s Next?
In the coming weeks, I’ll be diving into practical DSA topics:
:white_check_mark: Hidden performance traps in common algorithms
:white_check_mark: Real-world DSA use cases from backend, frontend, and data
:white_check_mark: Simplifying complex topics like recursion, graphs, and dynamic programming

100daysofcode lebanon-mug

Day 68 | :mag: Real-World Use Cases of DSA You’re Already Relying On

If you’ve ever asked yourself “When am I really going to use Data Structures and Algorithms?” — you’re not alone. For many professionals outside of competitive programming or academia, DSA can seem abstract. But the truth is, behind nearly every system we interact with, there’s a carefully crafted blend of DSA at work.

Here are 5 practical, real-world cases where DSA isn’t just useful — it’s essential:

  1. Navigation Apps: Graphs in Action

Whether it’s Google Maps calculating the fastest route :red_car: or Uber matching you with the nearest driver, graphs and shortest path algorithms (like Dijkstra’s) are the stars here. Roads become nodes and distances become weights. Efficient route planning = happy users.

  1. Autocorrect & Search Suggestions: Tries & Heuristics

Typing “algor…” and getting “algorithm” as a suggestion? That’s not magic — it’s a Trie (prefix tree) behind the scenes. Combined with frequency data and edit distance algorithms (like Levenshtein), it helps your phone guess what you meant — even with typos.

  1. Databases & Indexing: Trees and Hashing

Ever wondered how SQL queries return results in milliseconds? Thank B-trees and hash maps. Indexing structures speed up search and retrieval, especially in large datasets. Without them, your queries would take ages.

  1. Social Media Feeds: Heaps, Queues & Graphs

Your Instagram or LinkedIn feed? Not random. It’s sorted based on relevance, engagement, or recency using priority queues, heaps, and sometimes even graph-based algorithms to suggest content from your extended network.

  1. Cybersecurity & Network Routing: Queues, Trees, Graphs

Firewalls and routing protocols often rely on tries and prefix trees for IP matching. Queues and graphs are essential in packet routing and network traffic optimization, ensuring data gets from point A to point B without chaos.

:bulb: TL;DR: DSA isn’t just academic — it’s operational. From your morning scroll to your late-night food delivery, algorithms are quietly at work. Mastering them isn’t about passing a coding test — it’s about understanding the systems that run the digital world.

100daysofcode lebanon-mug

:repeat: Day 69 | Understanding Recursion in DSA (Beginner Friendly)

When you’re just starting your journey into Data Structures and Algorithms (DSA), one of the first powerful tools you’ll encounter is recursion. At first, it might seem confusing — functions calling themselves? But once you understand it, recursion becomes an elegant way to solve many complex problems with concise code.

:seedling: What is Recursion?

Recursion is a method where the solution to a problem depends on solving smaller instances of the same problem.

In simple terms, a recursive function is one that calls itself.

To prevent infinite loops, every recursive function must have:

Base Case: The condition that stops the recursion.

Recursive Case: The part where the function calls itself with a smaller input.

:brain: Example: Factorial

python

def factorial(n):

if n == 0: # Base case return 1 return n * factorial(n - 1) # Recursive call

Calling factorial(5) will result in:

5 * 4 * 3 * 2 * 1 = 120

:gear: How Recursion Works (Call Stack)

Each recursive call is pushed onto the call stack, and the function resumes after each inner call returns. This is why understanding stack memory is important — too many calls can lead to a stack overflow.

:cyclone: Visualization

ruby

CopyEdit

factorial(3)

=> 3 * factorial(2)

=> 2 * factorial(1) => 1 * factorial(0) => 1

As the calls resolve, they “unwind” from the stack.

:jigsaw: When to Use Recursion

Recursion is ideal when:

A problem can be broken down into similar subproblems.

The problem naturally fits a divide-and-conquer approach.

The problem involves tree/graph traversal, permutations, or backtracking.

But keep in mind: recursion isn’t always efficient. Sometimes an iterative solution is better due to space concerns.

:bulb: Tips to Master Recursion

Write down the base case before the recursive logic.

Use print statements to trace recursive calls.

Practice dry-running your function on paper.

Learn to convert recursive logic to iterative, and vice versa.

Final Thoughts

Recursion is a pillar of problem-solving in computer science. It helps you think recursively, which is essential for topics like divide and conquer, trees, and backtracking. Start with easy problems and gradually build up to more complex challenges. And most importantly, don’t be afraid of recursion — embrace it!

100daysofcode lebanon-mug

Day 70: Mastering Recursion – From Basics to Brilliance :rocket:

Recursion can be intimidating at first, but once it clicks, it becomes one of the most elegant and powerful tools in your coding arsenal. Whether you’re prepping for FAANG interviews or sharpening your CS fundamentals, mastering recursion is a must.

I’m sharing a curated list of Top Recursion Problems on LeetCode – sorted from beginner to advanced – that helped me build confidence and intuition. Let’s dive in! :brain:

:beginner: Beginner Level – Build the Foundation

Start here to grasp the core concept: a function calling itself with a smaller input, and a base case to stop recursion.

Factorial of N – Implement the classic definition

:jigsaw: LeetCode Recursion Basics

(Not a specific problem, but use this page to practice basics like factorial, power, and sum of array recursively)

Reverse a String

:jigsaw: 344. Reverse String

Fibonacci Number (Top-down vs. Bottom-up)

:jigsaw: 509. Fibonacci Number

:gear: Intermediate Level – Brute Force to Backtracking

Here’s where recursion gets interesting. You’ll encounter decision trees and multiple recursive calls.

Permutations

:jigsaw: 46. Permutations

Subsets (Power Set)

:jigsaw: 78. Subsets

Generate Parentheses – Backtracking meets recursion

:jigsaw: 22. Generate Parentheses

Letter Combinations of a Phone Number

:jigsaw: 17. Letter Combinations of a Phone Number

:fire: Advanced Level – Recursion with Pruning & State Tracking

Here we combine recursion with optimization tricks (memoization, state flags, etc.)

Word Search

:jigsaw: 79. Word Search

N-Queens – Classic CS problem

:jigsaw: 51. N-Queens

Palindrome Partitioning

:jigsaw: 131. Palindrome Partitioning

Restore IP Addresses

:jigsaw: 93. Restore IP Addresses

Expression Add Operators – Deep backtracking with arithmetic

:jigsaw: 282. Expression Add Operators

:brain: Bonus: Visual Tools to Learn Recursion

Use a debugger or draw recursion trees on paper.

Try Python Tutor: http://pythontutor.com/

Memoize and compare brute force vs. optimized versions.

:speech_balloon: Final Thoughts

Recursion isn’t just a topic — it’s a mindset. Tackling it daily rewires your brain to think declaratively. And as always, happy coding!

100daysofcode lebanon-mug

:computer: Day 71 of hashtag#100DaysOfCode – Arrays in Java with a Real-World Twist :rocket:

Today, I will discuss the classic yet powerful data structure: arrays in Java. But instead of just printing numbers, let’s do something a bit more interesting.

:brain: Quick Recap: What’s an Array?
An array is a fixed-size, indexed data structure that holds elements of the same type. It’s fast, predictable, and memory-efficient — making it a go-to tool in low-level operations and algorithm-heavy scenarios.

:sparkles: Real-World Use Case: Detecting Duplicate Votes in a Poll
Say we’re building a small voting system for a student council election. Each student can vote once, but what if someone tries to vote twice?
We’ll simulate a system that flags duplicate voter IDs using a simple array approach.

:pushpin: Step 1: Simulate Voter IDs
java
CopyEdit
int voterIds = {102, 205, 102, 310, 412, 205}; // Duplicate IDs: 102 and 205

:mag: Step 2: Detect Duplicates Using Nested Loops
java
CopyEdit
for (int i = 0; i < voterIds.length; i++) {
for (int j = i + 1; j < voterIds.length; j++) {
if (voterIds[i] == voterIds[j]) {
System.out.println("Duplicate vote detected from ID: " + voterIds[i]);
}
}
}
:jigsaw: Output:
csharp
CopyEdit
Duplicate vote detected from ID: 102
Duplicate vote detected from ID: 205
This is a brute-force approach (O(n²) time), but it’s a great demonstration of how arrays can power logic in real-world-like systems — even before you move into fancy data structures.

:bulb: Why Arrays Still Matter
Despite being “basic,” arrays are the foundation for:
Efficient memory handling
Fixed-size buffers
Algorithm challenges (sorting, searching, etc.)
Under-the-hood operations in Java collections like ArrayList

Day 72: Mastering the Two Pointer Technique in Arrays: A Must-Know DSA Pattern

If you’ve just moved past recursion in your DSA journey, it’s time to unlock one of the most elegant and efficient techniques used in array and string problems: the Two Pointer Technique.

It’s simple in concept, yet incredibly powerful when applied right. Let’s break it down with a classic problem that’s often asked in interviews.

:mag: The Problem: Two Sum in a Sorted Array

Given a sorted array of integers nums and a target integer target, return the 1-based indices of the two numbers that add up to the target.

You can assume exactly one solution exists.

:x: Brute Force (O(n²))

A straightforward approach is to use a nested loop and check every pair. It works, but it’s inefficient—especially when input size grows. Interviewers usually look for more optimized thinking.

:white_check_mark: Optimized with Two Pointers (O(n))

Here’s where the two pointer technique shines. Since the array is sorted, we use two indices:

left starting at the beginning

right starting at the end

At each step:

If nums[left] + nums[right] == target → return the pair

If the sum is too small → move left rightward

If the sum is too big → move right leftward

python

CopyEdit

def twoSum(nums, target):

left, right = 0, len(nums) - 1 while left < right: curr_sum = nums[left] + nums[right] if curr_sum == target: return [left + 1, right + 1] elif curr_sum < target: left += 1 else: right -= 1

:bulb: Why this works: We’re leveraging the sorted nature of the array to discard irrelevant combinations in constant time. No extra space needed. Clean and efficient.

:repeat: Where Else Can You Use Two Pointers?

Reversing an array in place

Checking for palindromes

Removing duplicates from a sorted array

Merging two sorted arrays

Trapping rain water (advanced)

:brain: When to Reach for This Technique

The data is sorted

You need to find pairs, windows, or symmetrical properties

You want to optimize space and time complexity

Final Thoughts

Two pointers teach you to reason from both ends—a skill that’s algorithmic and deeply strategic. It’s a go-to tool for coding interviews and competitive programming alike.

If you’ve already mastered recursion, two pointers is your next must-conquer concept. It’s intuitive, versatile, and essential in real-world code.

:pushpin: Next step? Try applying this to problems like “Container With Most Water” or “3Sum”. You’ll quickly see just how far this pattern can take you.

Let me know what your favorite two-pointer problem is—or if you’ve seen an interview question where this approach saved the day!

#DSA #CodingInterviews #Arrays #TwoPointers #TechBlog python #ProgrammingTips

Day 73: :mag: The Sliding Window Technique — Why It’s a Must-Know for Every LeetCoder

Let’s say you’re given this simple problem:

:point_right: “Find the maximum sum of any 3 consecutive numbers in an array.”

You have this array:

js

nums = [1, 2, 3, 4, 5, 6]

The brute-force way?

Check all groups of 3:

1+2+3 = 6

2+3+4 = 9

3+4+5 = 12

4+5+6 = 15

:white_check_mark: Answer: 15

:x: But time complexity = O(n * k) if k is the window size.

Now imagine your array has 1 million numbers and you need the sum of every 1000 consecutive numbers — suddenly, brute force isn’t so cute.

Enter the Sliding Window Technique.

:bulb: How It Works

You build a “window” of size k (in this case, 3), calculate the sum once, and then just “slide” the window one step at a time:

Initial sum: 1 + 2 + 3 = 6

Slide window right:

Remove 1 (leftmost)

Add 4 (next in array)

→ New sum: 6 - 1 + 4 = 9

Repeat:

Remove 2, add 5 → 9 - 2 + 5 = 12

Remove 3, add 6 → 12 - 3 + 6 = 15

Same result, but in O(n) time.

:dart: This is what Sliding Window does:

It avoids repetition by reusing previous calculations and only adjusting what changed — making it a go-to for efficient algorithms.

:key: Where You’ll Use It on LeetCode

The Sliding Window technique shines in problems involving:

Subarrays or substrings

Consecutive or fixed-size elements

Dynamic tracking (length, sum, uniqueness)

:boom: Examples:

Longest Substring Without Repeating Characters

Maximum Sum Subarray of Size K

Minimum Size Subarray Sum

Permutation in String

Contains Duplicate II

:eyes: Visualize It Like This:

Imagine dragging a box across your array or string.

At every move, you only care about the element that enters and the one that exits.

The rest of the window stays intact — so your calculations are fast, clean, and focused.

:brain: When to Reach for Sliding Window:

The question mentions “subarray” or “substring”

You’re given a length or range constraint

You need to find “maximum/minimum/longest/shortest” something

Brute force is too slow, and you want to cut it to O(n)

:dart: From Two Pointers to Sliding Window

If you’ve mastered the Two Pointer approach, Sliding Window is your next step.

They’re cousins — both involve scanning with two markers — but Sliding Window is like a smarter version that carries memory with it.

You don’t restart; you slide.

:brain: From Naive Loops to O(1) Brilliance: The Power of Prefix Sums &

Difference Arrays

When I first started solving array problems, I always reached for loops. Want to find the sum of a subarray? Loop. Want to update a range of elements? Loop again.

But then I discovered something that changed everything — prefix sums and difference arrays. These techniques are all about one thing: Do a little work up front to save a lot of time later.

:round_pushpin:The Problem

Given an array, you’re asked repeatedly:

“What’s the sum of elements between index L and R?”

The naive approach:

js

CopyEdit

let sum = 0;

for (let i = L; i <= R; i++) sum += arr[i];

But that’s O(n) per query — not scalable.

:rocket: Enter: Prefix Sums

One pass builds a prefix array:

js

CopyEdit

prefix[0] = arr[0];

for (let i = 1; i < arr.length; i++) {

prefix[i] = prefix[i - 1] + arr[i];

}

Now range sum is O(1):

js

CopyEdit

sum = prefix[R] - (L > 0 ? prefix[L - 1] : 0);

:sparkles: Range Updates with Difference Arrays

Need to add +10 to every number from index 2 to 5?

Instead of looping:

js

CopyEdit

diff[2] += 10;

diff[6] -= 10;

Apply a prefix sum to diff at the end to get the final array.

This is how we update ranges in O(1) time.

:wrench: Real-Life Applications

Used in:

Range-based scoring in games :video_game:

Bulk financial transactions :moneybag:

Efficient spreadsheet operations :bar_chart:

:exploding_head: Why It Matters

Prefix sums and diff arrays teach you to solve smarter, not harder.

They’re not just coding tricks — they’re a mindset:

Minimize repetition

Maximize efficiency

Think in preprocess → query cycles

:speech_balloon: Curious to Try?

Next time you’re about to loop through a subarray — pause.

There might be a better way waiting for you.

Let’s write code that thinks ahead.

#DSA #Arrays #CodingTips #BigO #LearningByDoing

100daysofcode lebanon-mug

Day 75: :key: Mastering HashMaps for Problem Solving in DSA

If you’re diving into coding interviews or just want to level up your DSA skills, HashMaps (aka Hash Tables or Dictionaries) are a tool you need in your toolkit. They’re fast, flexible, and surprisingly fun to use once you get the hang of them.

:rocket: Why HashMaps Matter

HashMaps let you store key-value pairs and access them in O(1) time. That’s a game-changer when you’re trying to solve problems quickly and efficiently.

Think of them as smart lockers—you instantly know where the key is without checking every locker.

:bulb: Common Use Cases

Counting elements

→ E.g. {‘a’: 2, ‘b’: 1}

:repeat: For problems like “First Unique Character”

Tracking indices

→ For “Two Sum”, store value → index

Avoiding repeated work

→ Use it in memoization during recursion

:brain: Example Problem: Two Sum (Classic)

Problem: Given an array and a target, return the indices of two numbers that add up to the target.

js

CopyEdit

const twoSum = (nums, target) => {

const map = {};

for (let i = 0; i < nums.length; i++) {

const diff = target - nums[i]; if (map[diff] !== undefined) { return [map[diff], i]; } map[nums[i]] = i;

}

};

:white_check_mark: Uses a HashMap to check for the complement in O(1)

:hammer_and_wrench: Pro Tip

Always ask yourself:

“Can I reduce the time complexity if I use a map to track values?”

:books: Bonus Challenge to Try

Find the length of the longest substring without repeating characters.

Hint: You’ll need a HashMap AND a sliding window :wink:

100daysofcode lebanon-mug

:date: Day 76: Set vs Map – When and Why to Use Each in JavaScript

When solving DSA problems or building real-world apps, choosing between a Set and a Map can feel trivial—but it’s not. :crossed_swords: These two data structures serve different purposes, and knowing when to use which can make your code cleaner and faster.

:mag: Map: The Lookup King :crown:
Stores key-value pairs

Keys can be any data type

Keeps insertion order

Access time: O(1)

:brain: Use a Map when:

You need to associate values with keys

You need quick lookups based on a key

You want to track counts, indices, or flags

js
Copy
Edit
const map = new Map();
map.set(‘apple’, 2);
map.get(‘apple’); // 2
:seedling: Set: The Uniqueness Guardian :shield:
Stores only values

Each value must be unique

Also keeps insertion order

Access time: O(1)

:brain: Use a Set when:

You just need to store unique items

You want to check existence fast

You’re cleaning duplicates or tracking seen elements

js
Copy
Edit
const set = new Set([1, 2, 2, 3]);
console.log(set); // Set {1, 2, 3}
:thinking: Real DSA Examples
Use a Set in Longest Substring Without Repeating Characters

Use a Map in Two Sum, Group Anagrams, Top K Frequent Elements

:hammer_and_wrench: Quick Summary:

Use Case Set Map
Unique values only :white_check_mark: Yes :x: No
Key-value pairs :x: No :white_check_mark: Yes
Fast lookup :white_check_mark: Yes :white_check_mark: Yes
Track frequency/index :x: :white_check_mark: Yes

100daysofcode lebanon-mug

:date: Day 77: Memoization Magic – Speeding Up Recursion with Maps :zap:

Ever write a recursive function that works… but takes forever to run on big inputs? You’re not alone. That’s where memoization comes in. It’s like giving your function a short-term memory—so it doesn’t redo work it already did.

:brain: What is Memoization?
Memoization is a technique to cache the results of expensive function calls and return the cached result when the same inputs occur again.
:repeat: You save time by not recalculating the same subproblem over and over.

:gear: Classic Example: Fibonacci (Without Memoization)
js
CopyEdit
function fib(n) {
if (n <= 1) return n;
return fib(n - 1) + fib(n - 2);
}
:-1: This has exponential time complexity: O(2ⁿ)

:floppy_disk: With Memoization Using Map
js
CopyEdit
function fib(n, memo = new Map()) {
if (memo.has(n)) return memo.get(n);
if (n <= 1) return n;
const result = fib(n - 1, memo) + fib(n - 2, memo);
memo.set(n, result);
return result;
}

:white_check_mark: Time complexity now is O(n)
The Map acts as a fast-access memory :brain:

:pushpin: When to Use It
Recursive solutions with overlapping subproblems
Dynamic Programming (especially top-down)

Problems like: Climbing Stairs, Coin Change, Edit Distance
:rocket: TL;DR
Memoization = Smart caching
Map = Your function’s memory card :brain:
Next time recursion’s dragging you down, wrap it with a Map and feel the speed. :racing_car:

100daysofcode lebanon-mug

:date: Day 78: Top-Down vs Bottom-Up DP – When to Pick What? :thinking:
You’ve probably seen both styles of Dynamic Programming—top-down (with memoization) and bottom-up (with tabulation). But when should you use which? Let’s break it down.

:arrow_up: Top-Down (Memoization)
Recursive + memoization (usually with a Map or array)
Solves only the necessary subproblems
Easier to write, more intuitive
js
CopyEdit
function climbStairs(n, memo = {}) {
if (n <= 2) return n;
if (memo[n]) return memo[n];
return memo[n] = climbStairs(n - 1, memo) + climbStairs(n - 2, memo);
}
:white_check_mark: Great for:
Problems with sparse subproblem usage
Quick implementation and clarity

:arrow_down: Bottom-Up (Tabulation)
Iterative approach using a table/array
Solves all subproblems in order
Typically more space/time efficient
js
CopyEdit
function climbStairs(n) {
const dp = [1, 1];
for (let i = 2; i <= n; i++) {
dp[i] = dp[i - 1] + dp[i - 2];
}
return dp[n];
}
:white_check_mark: Great for:
Performance-critical code
When full control over iteration is needed

:dart: Final Tip
Start with top-down when exploring a problem
Refactor to bottom-up if you hit time/space issues

100daysofcode lebanon-mug

:date: Day 80: Clean API Practices – Because Your Backend Deserves Respect :soap:
Whether you’re building an internal tool or the next unicorn startup, your API is the bridge between your backend and the real world. And like any bridge—it better be clean, reliable, and consistent.
Let’s talk about a few simple but powerful practices to keep your APIs :ok_hand: and your teammates (and future self) sane.

:lock: 1. Use Proper HTTP Methods

ActionMethodGet dataGETCreate dataPOSTUpdate dataPUT / PATCHDelete dataDELETE
Don’t POST to delete something. Don’t GET to change a password. Respect the verbs.

:triangular_ruler: 2. Structure Your Routes Like a Pro
:white_check_mark: /api/users/123
:x: /api/getUserById?userId=123
Follow RESTful patterns. Use nouns for resources, not verbs.

:dart: 3. Consistent Response Format
Stick to a format like:
json
CopyEdit
{
“success”: true,
“data”: {…},
“message”: “User created successfully”
}
Don’t leave your frontend dev guessing. Consistency = clarity.

:test_tube: 4. Handle Errors Gracefully
Return clear errors, like:
json
CopyEdit
{
“success”: false,
“message”: “Email already exists”
}
Also: don’t return 200 for failed actions. Use the right status codes (e.g., 400, 404, 500).

:soap: 5. Validate Incoming Data
Before saving to DB, make sure inputs are legit. Use tools like Joi, Zod, or custom logic.
:brain: TL;DR
:white_check_mark: Follow REST
:white_check_mark: Be consistent
:white_check_mark: Return helpful errors
:white_check_mark: Validate everything

100daysofcode lebanon-mug

This topic will automatically close in 3 months.