2026-01-17 17:47:25
Introduction
Git and GitHub are essential tools for developers, data scientists, and anyone working with code. This guide will help beginners understand how to track changes, push and pull code, and use version control effectively.
What is Git
Git is a version control system that acts like a time machine for your code. *It tracks every change you make to your files*, so you can:
Example:
Imagine you wrote a program yesterday, but it stopped working today. Git lets you revert to yesterday’s version quickly.
What is GitHub?
GitHub is an online platform for storing Git projects. It allows you to:
Think of GitHub as a *cloud version of your Git projects*
What is Version Control?
Version control helps you track changes in your files over time. It’s useful because:
Git Workflow for Beginners
Beginner Friendly Daily Workflow
Here’s a simple workflow that combines all the above commands:
Bash code
git --version # Check Git version
git status # See changes
git add . # Stage files for commit
git commit -m "Describe what you changed" # Save snapshot locally
git push # Upload changes to GitHub
git pull # Download latest changes from GitHub
git log # Review history
Every command above is part of version control, tracking your files, saving snapshots, sharing and reviewing history.
2026-01-17 17:46:33
Introduction to SQL
If you are a web developer, chances are you have worked with a database at some point. It might be PostgreSQL, MySQL, SQLite, or something else. No matter the stack, SQL is always there behind the scenes.And let’s be honest, few things feel better than writing a single SQL query that returns exactly the data you need. Extra points if it runs fast.In this article, we’ll walk through essential SQL queries every developer should know. Whether you are building APIs, dashboards, or debugging a production issue at 2 AM, these queries are your daily tools.
Use SELECT to fetch only the data you actually need. While SELECT * looks convenient, it can slow down queries and waste bandwidth, especially on large tables.
The real power of SELECT comes when you combine it with WHERE, JOIN, and ORDER BY.
SELECT id, name, email
FROM users;
You can filter using:
Comparison operators: =, !=, <, >, <=, >=
Logical operators: AND, OR, NOT
Without WHERE, things can get dangerous. A query like DELETE FROM users; without a condition will delete everything. Always double-check.
SELECT *
FROM orders
WHERE status = 'completed';
Best practices:
Always specify column names
Use bulk inserts when possible for better performance
Never trust user input. Use parameterized queries or an ORM to prevent SQL injection
INSERT INTO users (name, email)
VALUES ('Alice', '[email protected]');
The most common and most dangerous mistake is forgetting the WHERE clause. Without it, every row gets updated.
Tips:
You can update multiple columns at once
Use transactions in production to stay safe
UPDATE users
SET email = '[email protected]'
WHERE id = 42;
Use cases:
Removing expired sessions
Cleaning test data
Deleting old logs
Many production apps use soft deletes by adding a deleted_at column instead of permanently removing records.
DELETE FROM sessions
WHERE last_active < NOW() - INTERVAL '30 days';
Become a member
Common types:
INNER JOIN: Only matching rows
LEFT JOIN: All rows from the left table, even if there is no match
RIGHT JOIN: Opposite of left join
FULL JOIN: Everything from both tables
If your results suddenly double, chances are your join condition is wrong.
SELECT users.name, orders.amount
FROM users
JOIN orders ON users.id = orders.user_id;
Common aggregates:
COUNT() – number of rows
SUM() – total
AVG() – average
MAX() / MIN() – highest or lowest values
Whenever you use aggregates with non-aggregated columns, GROUP BY is required.
SELECT status, COUNT(*) AS total
FROM orders
GROUP BY status;
Use cases:
Latest blog posts
Top users by score
Recent transactions
This combo is also great for pagination when used with OFFSET.
SELECT *
FROM orders
ORDER BY created_at DESC
LIMIT 10;
Patterns:
% matches any number of characters
_ matches a single character
Note: Case sensitivity depends on the database. PostgreSQL uses ILIKE for case-insensitive searches.
SELECT *
FROM users
WHERE email LIKE '%@gmail.com';
They are great for readability, but joins are often faster. Use subqueries when clarity matters more than raw performance.
SELECT name, email
FROM users
WHERE id IN (
SELECT user_id
FROM orders
WHERE amount > 100
);
Final Thoughts: Mastering SQL
This article is part of the “SQL Queries Every Developer Should Know” series.
Mastering these queries will help you:
Debug faster by querying the database directly
Build better and faster APIs
Write cleaner backend logic
Impress teammates during code reviews
SQL is not scary. It’s a superpower. And like any skill, the more you practice it, the more confident and unstoppable you become.
2026-01-17 17:44:43
In May 2023, a DeFi protocol launched its token claim contract. Within 48 hours, users had spent over $2 million in gas fees, not because the contract was complex, but because the developers hadn't optimized their loops. Each claim processed the same storage array 100+ times instead of caching it once.
The contract worked. It just costs users 10x more than it should have. This wasn't a hack. It wasn't a bug. It was inefficient code that silently compounded until real money started burning.
Here's the reality: Compute and storage are never free. On Ethereum, every opcode has a gas price. On Stellar's Soroban, computation and storage consume transaction budgets. Solana charges compute units. Polkadot weighs transactions. Different execution models, same outcome, inefficient code becomes a production problem fast.
If you're building on any blockchain, gas optimization isn't optional. It's the difference between a protocol users can afford to use and one they abandon for cheaper alternatives.
The biggest culprit across all chains? Storage operations.
On EVM chains (Ethereum, Polygon, BSC, Arbitrum):
mload and mstore (memory): 3 gas per operation.
sload and sstore (storage): 100+ gas minimum.
As defined in the Ethereum Yellow Paper, storage operations cost over 100× more than memory operations.
On Non-EVM (Soroban, Solana):
Writing to a new storage entry allocates ledger space, consuming significant resources.
Storage reads/writes count against your transaction's CPU and memory budget.
Cross-program invocations (CPIs) add compute overhead.
The pattern is universal: Touching a persistent state is expensive. The exact mechanism differs by chain, but the principle holds.
The problem isn't just that storage costs more; it's that developers unknowingly trigger these operations repeatedly. A loop that runs 100 times and reads from storage on each iteration? That's 100 expensive reads instead of one cached value, whether you're on EVM or Non-EVM.
Small inefficiencies multiply. And by the time you notice in production, your users are already paying for it.
Most gas bloat comes from patterns developers don't recognize as problems until deployment. These patterns appear across all blockchain architectures; the syntax changes, but the inefficiencies remain the same.
Let's break down the worst offenders with examples across different chains:
The mistake: Writing default or zero values when they're not needed, or writing data that hasn't actually changed.
Why it's expensive:
EVM chains: Each storage write costs ~20,000 gas. Even after EIP-3529 reduced refunds, writing to an already-zero slot still costs ~2,900 gas on warm slots.
Non-EVM chains (e.g., Soroban): Every storage write consumes part of your transaction budget. Writing unchanged values wastes CPU instructions and ledger I/O.
How to fix it:
On EVM (Solidity):
// ❌ Bad: Always writes
balances[user] = 0;
// ✅ Good: Only writes if needed
if (balances[user] != 0) {
delete balances[user]; // Triggers gas refund
}
On Non-EVM (Rust/Soroban):
// ❌ Bad: Always writes
env.storage().instance().set(&USER_BALANCE, &0);
// ✅ Good: Check before writing
if env.storage().instance().has(&USER_BALANCE) {
env.storage().instance().remove(&USER_BALANCE);
}
Additional optimizations:
EVM: Pack booleans and small integers into the same 256-bit slot, save entire storage slots (~20,000 gas each).
Non-EVM (Soroban): Use temporary storage for data that doesn't need to persist across ledgers.
Both: Use events/logs instead of storage for infrequently accessed data.
The mistake:Reading from or writing to storage inside loops. Each storage operation costs resources, so if your loop touches storage on every iteration, costs multiply quickly.
Why it's expensive:
A loop that processes 100 items and reads from storage each time equals 100 expensive operations instead of 1 cached read.
How to fix it:
On EVM (Solidity):
// ❌ Bad: Reads storage 100 times
for (uint i = 0; i < users.length; i++) {
totalBalance += balances[users[i]]; // sload every iteration
}
// ✅ Good: Cache values
uint length = users.length;
uint tempBalance;
for (uint i = 0; i < length; i++) {
tempBalance += balances[users[i]];
}
totalBalance = tempBalance; // Single sstore
On Non-EVM (Rust/Soroban):
// ❌ Bad: Reads storage in loop
let mut total = 0;
for user in users.iter() {
total += env.storage().instance().get::<_, i128>(&user).unwrap_or(0);
}
// ✅ Good: Batch reads or cache
let total: i128 = users.iter()
.map(|u| env.storage().instance().get::<_, i128>(u).unwrap_or(0))
.sum();
The mistake: Performing expensive operations before checking if inputs are even valid.
Why it's expensive:
If a transaction is going to fail anyway, you want it to fail as cheaply as possible. Order matters.
How to fix it:
On EVM (Solidity)
// ❌ Bad: Expensive check first
require(balances[msg.sender] >= amount); // Storage read
require(amount > 0); // Memory check
// ✅ Good: Cheap checks first
require(amount > 0); // Fails fast if zero
require(balances[msg.sender] >= amount); // Only runs if amount valid
On Non-EVM (Rust/Soroban):
// ❌ Bad: Storage check first
let balance = env.storage().instance().get::<_, i128>(&user).unwrap_or(0);
if amount <= 0 {
panic!("Invalid amount");
}
// ✅ Good: Validate inputs first
if amount <= 0 {
panic!("Invalid amount"); // Fails immediately
}
let balance = env.storage().instance().get::<_, i128>(&user).unwrap_or(0);
if balance < amount {
panic!("Insufficient balance");
}
**Universal principle: **Validate cheaply (bounds checks, null checks) before expensive operations (storage reads, cryptographic operations).
** The mistake:** Splitting work across many transactions instead of grouping operations.
Why it's expensive:
EVM chains:Each transaction has a base fee (~21,000 gas). 100 transactions = 100 base fees.
Non-EVM (eg, Soroban):Each transaction consumes base CPU/memory budget overhead.
How to fix it:
On EVM (Solidity):
// ❌ Bad: 100 transactions = 100 base fees
// User calls transfer() 100 times
// ✅ Good: 1 transaction, 1 base fee
function batchTransfer(address[] calldata recipients, uint[] calldata amounts) external {
require(recipients.length == amounts.length, "Length mismatch");
for (uint i = 0; i < recipients.length; i++) {
_transfer(msg.sender, recipients[i], amounts[i]);
}
}
On Non-EVM (Soroban/Rust):
// ✅ Good: Batch operations in single contract call
pub fn batch_transfer(
env: Env,
from: Address,
transfers: Vec<(Address, i128)>
) -> Result<(), Error> {
from.require_auth();
for (to, amount) in transfers.iter() {
transfer_internal(&env, &from, to, *amount)?;
}
Ok(())
}
The mistake: Copying data unnecessarily or using the wrong data location for function parameters.
Why it's expensive:
Memory operations and data copies cost resources across all chains.
How to fix it:
On EVM (Solidity):
// ❌ Bad: Copies array to memory
function sum(uint[] memory numbers) public returns (uint) {
uint total;
for (uint i = 0; i < numbers.length; i++) {
total += numbers[i];
}
return total;
}
// ✅ Good: Reads directly from calldata
function sum(uint[] calldata numbers) public pure returns (uint) {
uint total;
for (uint i = 0; i < numbers.length; i++) {
total += numbers[i];
}
return total;
}
On Non-Evm (Soroban/Rust):
// ❌ Bad: Cloning data unnecessarily
pub fn process_data(env: Env, data: Vec<i128>) -> i128 {
let copied = data.clone(); // Unnecessary clone
copied.iter().sum()
}
// ✅ Good: Use references
pub fn process_data(env: Env, data: Vec<i128>) -> i128 {
data.iter().sum() // No clone needed
}
EVM (Solidity): Mark read-only functions as view or pure (can be called off-chain for free).
Non-EVM (Rust): Use & references instead of cloning Vec or Map structures.
Before you deploy on any chain, run through this checklist:
a. No unnecessary writes to storage.
b. Variables/data packed efficiently.
c. Old entries deleted/removed for refunds (EVM) or budget recovery.
d. Events/logs used instead of storage for infrequently accessed data.
a. No storage reads/writes inside loops
b. Array lengths and values cached beforehand
c. Heavy computation moved off-chain or batched
a. EVM (Solidity): Large inputs use calldata, not memory.
b. Non-Evm (Rust): Use references (&) instead of cloning.
a. Cheap validation checks before expensive operations.
b. Conditions structured to short-circuit away from costly paths.
a. Current values checked before writing.
b. Conditional checks skip no-op writes.
c. State is cleared explicitly when no longer needed.
a. Gas/resource reporter integrated into test suite.
b. Functions profiled during development.
c. Static analysis in CI/CD pipeline.
a. EVM: Storage packing, immutable/constant usage, library calls.
b. Non-EVM (Rust): Storage tier usage, WASM size, Rust efficiency patterns.
Gas optimization isn't glamorous. It doesn't lend itself to flashy demos or impressive pitch decks. But it's the difference between a protocol users can actually afford to use and one they abandon after the first transaction.
I've seen great projects die because their gas costs were five times higher than those of their competitors. Not because the code was bad, but because it wasn't efficient.
Every blockchain has its quirks, but the fundamentals are universal: plan for efficiency or pay the price.
Whether you're deploying to Ethereum mainnet, launching on Stellar, or building on any other Non-EVM chains, the same patterns apply: minimize storage, batch operations, validate early, and compute off-chain.
2026-01-17 17:42:15
Hey! I built this because every online timer I found was either ugly, bloated with ads, or required signup.
VibeTimers is a free, no-signup focus timer with:
Built with React + TypeScript. No tracking, no accounts, works on mobile.
Would love feedback on the UX or feature ideas. Thanks for checking it out!
2026-01-17 17:35:53
Check out this article on how you can install and configure Git also known as gitbash and connect it to your GitHub account on a Windows operating system, using commands and prompts.
Definitions:
Github - This is a virtual control platform that allows you to create, store, manage, track, and share your code with other developers. It enables collaborations on projects.
Git/Gitbash - This is a command-line version control interface that allows you to communicate with your GitHub account using prompts and commands.
Fun fact about git:
Git uses the SHA-1 (and increasingly SHA-256) cryptographic hashing algorithm to identify every commit. This ensures that the code cannot be altered or corrupted without detection.
Now that you know the tools, let's get started!
Step 1:
Open your default browser and search github, click the first link, and sign up. OR follow this link to Github and sign up
Step 2:
Create a Profile on Github and sign up
Fill in all the necessary fields, e.g., profile picture, name, and Bio information.
Congratulations! You have successfully created a GitHub account.
Step 1:
Open your browser and search for Git. OR follow this Link Git Install
Step 2:
Select the Operating system you are installing git on, i.e., Windows/ Mac os / Linux, etc
Step 3:
Click the hyperlink "click here to download" (as shown below)
Step 4:
Once the program has finished downloading on your machine. Open and run the program.
Be sure to pick Visual Studio as your default code editor on git when going through the steps of installation
Follow each step carefully as instructed until you successfully finish installing it.
Follow the following steps
Step 1: Launch your git
Step 2: Use the commands listed below in the following order.
git --version
git config --global user.name "enter your name"git config --global user.email "enter your email"
Please use the same name and email used to create your github account
git config --list
ssh-keygen -t ed25519 -C "email"
eval "$(agent-ssh -s)"
ssh-add ~/.ssh/id_ed25519
cat ~/.ssh/id_ed25519.pub
Now let's connect gitbash to github
Follow the path provided by git to where your key is stored >> Open it using Visual Studio and copy it to your clipboard
Open your github account >> Go to settings >> Got to SSH & GPG keys.
Click add new SSH key >> Paste the key you had copied earlier in VS stduio.
Congratulations! you successfully connected your git and GitHub accounts
Command to verify connection
ssh -T [email protected]
You should get a confirmation like shown below:
Git is the most commonly used software for version control because of the following features:
It takes a snapshot of every commit in the entire project.
It provides an audit trail of all changes made to the code, who made the changes, what was changed in the code, and the date and time it was changed.
It can restore any version of the project because it keeps a permanent, unaltered record of every commit made in the entire project.
Pushing and pulling are terms used to refer to the communication between your local machine and a remote server repository where code is stored (git in this case).
An example of a command to push code
git add
An example of a command to pull code
git pull --rebase
Tracking code on git is monitoring any unsaved modifications and the history of any permanent changes that have been made to the project.
git status
git diff
git diff --staged
To check full history or logsgit log
For a condensed view of your history
git log --oneline
git log --[filename]
git show --[commit-hash]
I hope you find it informative and educational. Please comment and let me know what you think about my article!!
Adios, until the next one.
Signed
Jules.