Saturday, July 25, 2026

Architecture principles and Implementation mechanics

Architecture principles
Category Principle Why It’s Important Example From Our Chat
Architecture 1️⃣ Data Integrity Belongs in the Database The database is the final source of truth and must prevent corruption. UNIQUE(slug), UNIQUE(expression), normalized schema
Architecture 2️⃣ Business Logic Belongs in the Application Workflows, permissions, and domain rules should stay outside DB for flexibility. We kept user rules out of triggers and procedures
Architecture 3️⃣ Triggers Enforce Invariants, Not Business Rules Triggers should guarantee consistency, not run workflows. Slug auto-generation ✅ Payment logic ❌
Architecture 4️⃣ Stored Procedures Are Gateways They centralize write logic but don’t replace integrity constraints. sp_insert_idiom() handled slug + dedupe
Architecture 5️⃣ Functions Are Pure Calculators Reusable, deterministic, side‑effect free. fn_make_slug() used in UPDATE and procedure
Data Processing 6️⃣ Order of Transformation Matters Improper ordering corrupts derived values. Regex before accent removal broke slugs
Schema Management 7️⃣ Schema Changes Must Be Controlled ALTER TABLE can lock production data and cause downtime. We added UNIQUE only after cleaning duplicates
Deployment 8️⃣ Idempotency Is Critical Scripts must be safe to re-run without corrupting data. INSERT IGNORE and UNIQUE constraints
Resilience 9️⃣ Defensive Design > Trusting the App The DB must guard against accidental misuse. Constraints + optional trigger safety net
System Design 🔟 Clean Architecture Requires Boundaries Clear separation reduces technical debt and confusion. Separated: normalization, slug logic, insert workflow, constraints

Scaling Concern What Changes at 10M Rows Why It Matters Architectural Decision
Primary Key INT may overflow 10M safe in INT, but future growth risk Use BIGINT for id
Slug Lookup Slug becomes main read path Every page load = SELECT by slug Keep UNIQUE INDEX on slug
Letter Column Grouping becomes heavy Frequent GROUP BY letter queries Keep indexed letter column
Search LIKE queries become slow Full table scan at scale Use FULLTEXT index or external search (Elasticsearch)
Insert Performance Triggers/procedures called millions of times Small inefficiencies multiply Keep slug function deterministic and lightweight
Bulk Imports Large batch loads slow down Index updates expensive Disable non-critical indexes during bulk load
Pagination OFFSET becomes slow OFFSET 1M is expensive Use keyset pagination (WHERE id > ?)
Index Size Indexes consume RAM 10M slugs = large B-tree Ensure enough buffer pool memory
Read Traffic High read ratio Dictionary = read-heavy system Add read replicas
Caching Hot idioms repeatedly accessed Reduce DB load Use Redis or application caching
Partitioning Single table becomes large Maintenance operations slower Partition by first letter or hash
Search Ranking Fulltext scoring needed Users expect intelligent results Move search to dedicated search engine
Writes vs Reads Mostly reads Different optimization strategy Tune for read-heavy workload
Data Integrity Constraint checks cost more UNIQUE index lookup per insert Keep constraints — integrity > micro performance
Migration Strategy ALTER TABLE becomes expensive Locks large tables Use online DDL / rolling migrations

Implementation mechanics
Topic Implementation Why It’s Good Why It Can Be Bad Architectural Insight
Table Design Created idioms table with slug, letter, meanings, etc. Normalized structure, scalable, searchable Over-design early can slow iteration Design schema for future growth, not just current data
Slug Column Added slug VARCHAR(255) SEO-friendly URLs, fast lookup Needs strict uniqueness & normalization Slug is derived data → should be deterministic
UNIQUE(slug) Added unique index Prevents duplicates at DB level Can block bulk updates if data dirty DB should enforce integrity, not rely on app
UNIQUE(expression) Added unique constraint Prevents accidental duplicate idioms May block legitimate variations Decide whether expression uniqueness is a business rule
ALTER TABLE Modified columns, added constraints Schema evolves cleanly Locks table in large datasets Schema migrations must be version-controlled
Bulk INSERT Inserted A–J idioms Efficient data loading Re-running caused duplicates Use INSERT IGNORE or constraints for idempotency
Duplicate Cleanup Used self-join DELETE Cleaned data safely Needs care with safe update mode Always verify with SELECT before DELETE
Safe Update Mode Encountered error 1175 Prevents accidental full-table updates Annoying during controlled updates Safety features protect production systems
Slug Generation Order Lowercase → remove accents → regex → trim Produces correct slugs Wrong order destroys characters Data transformation order matters
Function (fn_make_slug) Created reusable deterministic function Can use in SELECT, UPDATE, procedures Cannot modify tables Functions = value calculators
Stored Procedure Created sp_insert_idiom Encapsulates insert logic & dedupe Only safe if always used Procedure = controlled data gateway
Function vs Procedure Separated computation from action Clean responsibility separation Misuse causes confusion Function = value, Procedure = job
Trigger Discussion Debated enabling/disabling Protects DB from bad inserts Hidden logic, harder debugging Triggers enforce integrity, not business workflows
Feature Flag Trigger Used session variable toggle No redeploy needed Session-scoped behavior Elegant toggle without schema change
Business Logic in DB? Differentiated data rules vs workflows Data integrity belongs in DB Business workflows do not Layer separation is key architecture principle
Derived Fields (slug, letter) Auto-generated Prevents inconsistency Must ensure deterministic logic Derived data should not depend on user input
Data Integrity Strategy UNIQUE + procedure + optional trigger Layered protection Overlapping logic if poorly designed Defensive database design is professional
Idempotent Inserts Used INSERT IGNORE Safe re-runs May hide real errors Scripts must be rerunnable safely
Architecture Philosophy Discussed DB-centric vs App-centric Clear separation improves maintainability Mixing layers creates technical debt DB = guardian of truth, App = business brain

Wednesday, October 23, 2024

UW JS 310 Aut 24 Class 3 notes 22-OCT-2024

Functions are loosely typed in javascript, we are able to pass different types of parameters, too few args, too many argos etc. Keep function simple and make do only 1 thing which might be not feasible in real life. Function can have parameters or default values. Functions can return a value or not. 

Function expression : this type of function can be called only after being defined, generally preferred


const areaBuilder= function () { //function expression

console.log(‘area builder’)

};


areaBuilder(); // call the above function


const areaBuilder= function (h,w) { //function expression

console.log(w);

console.log(h);

console.log(‘area builder’ + (w*h));

};


areaBuilder(2,10);


const areaBuilder= function (h,w) { //function expression

return (w*h); // return the value

};


const area = areaBuilder(2,10);

console.log(area);


Recursion : a function calling itself


const adder = function(num1,num2){

 return num1+num2;

}


adder(2,’9’); // 29

adder(2,9) // 11


const adder = function(num1,num2){ // maybe this works?

 return Number(num1)+Number(num2)

}


const areaBuilder= function (h,w= 9) { //function expression with default value

return (w*h); // return the value

};


areaBuilder(3); // 27


Probably nothing will happen if you pass more arguments than needed


Function Declaration : this function can be called before being defined


console.log(minuser(3,4));


function minuser (num1,num2){ // this can be called before getting defined

return num1-num2;

}


Hoisting : order the javascript reads the file, which is top to bottom


Arrow functions shorthand in ES6, have to be careful with ‘this’ object

Example 

const areaBuilder = (h,w= 9)=> { //function expression with default value

return (w*h); // return the value

};


Why Undefined coming in chrome console?

the value of expression which is void/undefined is returned


Variable scope : to avoid unintended consequences, use const and let, do not use var   

a var can only be called in current code block, function has access to outer item/variable


IIFE ->immediately invoked function expressions. An IIFE is a function that is defined and immediately executed. The defining characteristic of an IIFE is that the function is invoked immediately after it is created.

Arguments : variable is an array like but not an array. itwill create an array inside the function and use it with for each.


const arr = [1,2,4,3]

arr.forEach(num=>{

console.log(num);

})


Rest parameters : … to spread them out in an array-like structure, is it like “the ellipsis (...)” in c??

 const myFunc = (...args) => {  

// this will take arguments from a function call and spread it to an array

return args; 

}

 const myFunc = (fristName,...args) => {  

// this will take arguments from a function call and spread it to an array

console.log(firstName);

return args; 

}

console.log(myFunc(4,6,8));


Methods inside the objects 

const car = {

make:”toyota”,

model : “Rav4”,

drive:function(){

console.log(‘VRoom’);

}

getSpecs(){

console.log(`Make:${this.make}`) // toyota

}

}

console.log(Car);

car.drive();


‘This’ object : keyword refers to the object that is currently executing the code. Its value depends on the context in which it is used.


Call : 

You can use call() to "borrow" methods from one object and use them on another.

call() gives you explicit control over the ‘this’ keyword, which is crucial in object-oriented JS.

Const teacher = {

Says:”hello”,

Talk : function(punct){

console.log(this.says + punct);

}

}


Const student = {

Says: ‘wait’

}


teacher.talk.call(student, “!!!!”);  // wait !!!!


Apply:

Key Differences between apply() and call():

  • call(): Takes individual arguments, separated by commas.

  • apply(): Takes an array of arguments.

When to use apply():

  • When you have an array of arguments that you want to pass to a function.

  • When you need to dynamically set the this value of a function.

  • For method borrowing (using a method from one object on another object).


Bind:

Maintaining context:

  • When passing object methods as callbacks, this can often be lost, leading to unexpected behavior. bind() helps you ensure that the correct this value is used.

Partial application:

  • bind() allows you to create new functions with some arguments already set, which can be helpful for creating reusable functions.


Classes : template for an object

Class Hero {

 constructor (name, ability){

this.name = name;

this.ability = ability;

}

useAbility(){

Const {name,ability} = this;

}

}



Anonymous functions are functions that are not bound to an identifier (i.e., they do not have a name). They are often used as arguments to other functions or as immediately invoked function expressions (IIFE).

In your example:

(args) => {

  // do something

}

This is an anonymous function (also known as an arrow function) that takes a single parameter args and performs some operations within its body.

Here's a more complete example to illustrate its usage:

const myFunction = (args) => {

  console.log(args);

};


myFunction("Hello, world!"); // Outputs: Hello, world!

In this case, myFunction is assigned an anonymous arrow function that logs the args parameter to the console. While the function itself is anonymous, it is assigned to the variable myFunction, which can then be used to call it.


Tuesday, October 15, 2024

UW JS 310 Aut 24 Class 2 notes 15-OCT-2024

Objects are complex data type

Const myObj = {};

console.log(myObj);


const person = {

firstName : ‘S’,

lastName: ‘Man’,

Age: 4

}


person.lastName = ‘Johnson’;

person.numberOfGuitars = 3;

console.log(person);


Objects destructuring : assigning properties of an object to individual variables 

const {firstName, age} = person;

console.log(“ghost emoji”, firstName, age);


Consider this example

const person = {

‘First Name’ : ‘S’,

lastName: ‘Man’,

Age: 40

}


To get the ‘First Name’ we have to do this:

person.[‘First Name’]

Also object keys should be strings, the values can be anything


Q) why does the index start with zero in javascript?

A: This one’s rooted in the history of computer science. Zero-based indexing traces

back to the C programming language, created in the early '70s. Arrays in C are

designed to start at the beginning of a memory block, and indexing from zero

simplifies the computation of an element’s address. JavaScript inherits many conventions

from C, including zero-based indexing. Once this became standard, many languages

that came afterward stuck with it to keep things consistent and predictable.

It's a nod to the past that still makes sense in today's coding world. 


array.pop() - removes the last value and 

array.push() - adds a value at the end of an array

array.concat() - takes 2 arrays and merge it to 1 array

array.slice()


Destructuring an array

const arr = [‘apple’,’orange’,’banana’];

const [first,second,third] = arr;

console.log(first); // apple


Array can be multi dimensional, can be array of arrays

const arr=[[1,2,3], [4,5,6], [7,8,9]];

console.log(arr[1][2]); // 6


const arr=[[1,2,3], [4,[‘a’,’b’,’v’],6], [7,8,9]];


Reference vs primitive data types :

Reference types are like class and arrays, when copies are made reference are copied

Primitives are like string, numbers, booleans, when copies are made values are copied

const name = ‘james’;

const firstName = name;

console.log(firstName);


Easy way to know is if we make a copy and cannot change the value then it is primitives

type when we precede with ‘const’

Eg of reference type variables

const arr=[1,2,3]

const narr = arr

arr[1] = 5

console.log(arr) // [1,5,3]

console.log(narr) // [1,5,3]




Spread operators (...) are incredibly handy in JavaScript! They allow you to easily expand elements of an array or object. 

When it comes to arrays, you can use them to create a new array that includes elements from an existing array. For example:


const arr1 = [1, 2, 3];

const arr2 = [...arr1, 4, 5, 6];

const arr3 = [...arr2] // copy by value

const arr4 = arr3 // copy by reference

console.log(arr2); // Output: [1, 2, 3, 4, 5, 6]


const arr2 = [ 4, 5, 6,...arr1];

const arr2 = [ 4, 5,...arr1,6];


You can also use them for copying arrays, combining arrays, and even spreading elements as function arguments. 


object copy by value, using spread operator

const billRodgersIV={...willRodgersIII} 


const russell = {

touchdowns:2,

yards:1123,

sacks:4

}


copy other values as is but changed the touchdowns value to 5

const russellWeek17 = {

...russell,

touchdowns:5,

interceptions : 1234 // and adding new properties like this

}


RegEx : way of validation of input from user 


Quiz notes :


In JavaScript, null and undefined don't have properties. Here's why:

Null: Represents the intentional absence of any object value. It's like a placeholder to say
"there's no value here." Since it signifies the absence of an object, it naturally doesn't have
properties or methods.
Undefined: Indicates a variable that hasn't been assigned a value yet.
It's the default value for uninitialized variables, and since it means "no value yet,"

it doesn't have properties either.

On the other hand, numbers, strings, and arrays do have properties and methods. Numbers and strings have

built-in methods (like .toFixed() for numbers or .length for strings), and arrays are objects in JavaScript,

so they come packed with a host of properties and methods.


 dot notation and bracket notation are the right ways to access properties in JavaScript objects.

Dot notation is simple and straightforward: object.property

Bracket notation allows for dynamic property access, where the property name is specified as a
string: object["property"]

Arrow notation isn’t a thing when accessing object properties. It’s actually used for functions and doesn’t

relate to property access.