2025-12-20 00:47:01
🧠 Introduction
A year ago, this feature would’ve stolen my entire workday.
You know the kind 👇
Requirements look simple
UI seems “straightforward”
Backend is “just CRUD”
And yet…
☕ Coffee goes cold
😵💫 Brain melts
💥 Git commits turn emotional
Last week, I built the same type of feature in one focused hour.
Same codebase.
Same language.
Same developer (me).
The difference wasn’t speed typing.
It was how I thought about the feature before touching the keyboard.
🧩 The Feature That Used to Drain My Day
Nothing fancy. Just classic enterprise app stuff:
Form-based UI
Validation
API integration
Save + edit flow
Conditional rendering
Earlier, my workflow looked like this:
Start coding UI
Realize backend needs tweaking
Modify API
Break another screen
Add custom validation
Duplicate logic “just this once”
Fix edge cases at the end (panic phase)
❌ That’s not development.
✅ That’s damage control.
🔄 What Changed This Time
♻️ Reusable Thinking > Custom Thinking
The biggest shift came from one question:
“Have I already solved 80% of this problem somewhere else?”
Turns out — I had.
Similar forms
Similar validations
Same API response shape
I wasn’t missing code.
I was missing reuse discipline.
⚙️ Automating the Boring Middle
I stopped hand-wiring things I could standardize:
Form state
Validation rules
API error mapping
Once these become predictable,
features stop being scary.
⏳ The 1-Hour Build (Step by Step)
🧠 Step 1: Define Inputs & Outputs (10 minutes)
Before coding, I answered:
What data goes in?
What shape comes out?
What can fail?
I wrote this in plain English first.
No IDE.
No distractions.
Just clarity.
♻️ Step 2: Reuse Before You Write (15 minutes)
I reused:
An existing form component
A shared validation schema
A common API wrapper
No pride.
No “I’ll clean it later”.
🧱 Step 3: Thin Backend, Smart Frontend (20 minutes)
Instead of creating custom endpoints, I used:
A generic POST handler
Config-driven behavior
🧠 Less backend code = fewer surprises.
🧪 Code Example (Simplified)
Here’s the pattern that saved me time — config-driven forms.
// formConfig.ts
export const userFormConfig = {
fields: [
{ name: "email", type: "email", required: true },
{ name: "role", type: "select", options: ["admin", "user"] }
],
endpoint: "/api/users"
};
// ReusableForm.tsx
function ReusableForm({ config }) {
const { fields, endpoint } = config;
return (
<form onSubmit={(data) => api.post(endpoint, data)}>
{fields.map(field => (
<Input key={field.name} {...field} />
))}
</form>
);
}
✨ This isn’t fancy.
🔁 It’s repeatable — and repeatability is speed.
🧠 Best Practices I Learned the Hard Way
Design patterns, not features
Write code assuming you’ll reuse it next week
If it feels repetitive → it deserves abstraction
Time spent thinking upfront saves hours later
“Simple” features expose bad architecture fast
⚠️ Common Pitfalls (I’ve Fallen Into All of These)
Over-customizing too early
Ignoring existing utilities
Mixing business logic into UI
Coding for today, not the next 5 features
Refactoring after shipping instead of before starting
💬 Community Corner
I’m curious 👇
What feature surprised you by being much faster than expected?
What abstraction saved you the most time?
Do you prefer config-driven reuse or explicit code?
Drop your stories, patterns, or counter-arguments in the comments.
Different teams solve this differently — and that’s the fun part.
❓ FAQ
Was this because of AI tools?
No. This was about architecture and reuse — not autocomplete.
Is this approach good for startups?
Especially for startups. Speed + consistency matters most there.
Doesn’t abstraction slow you down initially?
Yes. Once. Then it pays you back repeatedly.
What if requirements change?
Config-driven designs adapt faster than hardcoded flows.
Is this more frontend or backend focused?
Both — but frontend benefits immediately.
Can juniors apply this?
Absolutely. Start small: reuse one component at a time.
What’s the biggest takeaway?
👉 Think in systems, not tasks.
🎯 Conclusion
That 1-hour feature wasn’t luck.
It was the result of:
Fewer decisions
Better reuse
Respecting my future self’s time
If every feature feels heavier than it should,
don’t work faster — work differently.
If this resonated, give it a ❤️, share it with your team,
or follow me for more real-world dev lessons —
no fluff, just scars and solutions.
🔗 References
React Docs – Reusability Patterns: https://react.dev
Martin Fowler on Refactoring: https://martinfowler.com
Clean Architecture Overview: https://8thlight.com/insights/clean-architecture
2025-12-20 00:42:57
Most .NET developers eventually hit the same moment with Entity Framework Core:
“LINQ is great… but I need raw SQL here.”
That’s when APIs like FromSqlRaw, ExecuteSqlRaw, and FromSqlInterpolated enter the picture — and that’s also where security, performance, and correctness can silently go wrong.
This article goes deeper than the docs:
If you’ve ever wondered “what’s the real difference?”, this post is for you.
EF Core was designed around LINQ-to-Entities, but no ORM can fully replace SQL.
Raw SQL exists for three main reasons:
Expressiveness
Some queries (CTEs, window functions, hints) are awkward or impossible in LINQ.
Performance
Hand‑tuned SQL can outperform generated queries in hot paths.
Integration
Legacy databases, views, stored procedures, and reporting queries.
Key idea:
EF Core does not bypass ADO.NET.
Raw SQL still flows through parameterization, command preparation, and execution plans.
FromSql() (Deprecated)
Historically:
context.Users.FromSql("SELECT * FROM Users WHERE Name = {0}", name);
FromSqlRaw()
context.Users
.FromSqlRaw("SELECT * FROM Users WHERE Name = @name",
new SqlParameter("@name", name));
Characteristics:
FromSqlInterpolated() (Recommended)
context.Users
.FromSqlInterpolated($"SELECT * FROM Users WHERE Name = {name}");
EF Core converts interpolation into parameters automatically.
EF Core removed:
FromSqlExecuteSqlSqlQueryReason:
Pipeline:
DbParameter
Parameterized SQL enables plan reuse.
Injection changes the SQL parse tree.
Bad:
FromSqlRaw($"SELECT * FROM Users WHERE Name = '{input}'");
Good:
FromSqlInterpolated($"SELECT * FROM Users WHERE Name = {input}");
Secure SQL is almost always faster SQL.
context.Database.ExecuteSqlRaw(
"UPDATE Users SET IsActive = 0 WHERE LastLogin < @date",
new SqlParameter("@date", cutoff));
var query =
context.Users
.FromSqlInterpolated($"SELECT * FROM Users WHERE IsActive = {true}")
.AsNoTracking()
.Where(u => u.Role == "Admin");
AsNoTracking()
Raw SQL is not an escape hatch.
It’s a precision tool — powerful, fast, and dangerous if misunderstood.
Use it like a scientist, not like a cowboy.
2025-12-20 00:42:23
@xchainjs/xchain-ethereum is the official Ethereum client for the XChainJS ecosystem — a modular, TypeScript-first SDK for building cross-chain wallets, crypto applications, and DeFi tooling using a unified API.
This package provides:
Source package: https://github.com/xchainjs/xchainjs-lib/tree/master/packages/xchain-ethereum
Official docs: https://docs.xchainjs.org/xchain-client/xchain-ethereum/
Core dependencies:
ethers@xchainjs/xchain-client@xchainjs/xchain-utilDocs:
npm install @xchainjs/xchain-ethereum
npm install @xchainjs/xchain-client @xchainjs/xchain-util ethers
import { Client } from '@xchainjs/xchain-ethereum'
import { Network } from '@xchainjs/xchain-client'
const phrase = 'your mnemonic phrase here'
const ethClient = new Client({
phrase,
network: Network.Mainnet,
})
const address = ethClient.getAddress()
console.log('Address:', address)
const isValid = ethClient.validateAddress(address)
console.log('Valid:', isValid)
const balances = await ethClient.getBalance(address)
console.log(balances)
Balances are returned in base units and can be converted using utilities from@xchainjs/xchain-util.
import { assetAmount, assetToBase } from '@xchainjs/xchain-util'
const recipient = '0xRecipientAddressHere'
const amount = assetToBase(assetAmount(0.01))
const txHash = await ethClient.transfer({
recipient,
amount,
memo: 'ETH transfer',
})
console.log('TX hash:', txHash)
console.log('Explorer:', ethClient.getExplorerTxUrl(txHash))
const tokenAddress = '0xTokenContractAddress'
const txHash = await ethClient.transfer({
recipient,
amount,
asset: {
chain: 'ETH',
symbol: `USDT-${tokenAddress}`,
ticker: 'USDT',
},
})
const txHash = '0xTransactionHash'
const txData = await ethClient.getTransactionData(txHash)
console.log(txData)
Use @xchainjs/xchain-ethereum if you are:
GitHub source:
https://github.com/xchainjs/xchainjs-lib/tree/master/packages/xchain-ethereum
Documentation:
https://docs.xchainjs.org/xchain-client/xchain-ethereum/
XChainJS main repository:
https://github.com/xchainjs/xchainjs-lib
@xchainjs/xchain-ethereum provides a clean, consistent, and production-ready
Ethereum client for the XChainJS ecosystem.
It allows developers to interact with Ethereum using the same abstractions as
other blockchains, making it easier to build cross-chain applications.
2025-12-20 00:42:00
Frontend artık sadece React veya Vue değil; 2026’da trend, server-first mimariler, edge rendering ve AI destekli geliştirme deneyimi.
Bir dönem her geliştirici topluluğunda aynı tartışma dönerdi: React mi, Vue mu, Angular mı?
Bugünse bu savaşlar yerini daha olgun bir anlayışa bıraktı. Artık mesele “hangi framework” değil, nasıl bir mimariyle geliştirdiğin.
2026’ya gelindiğinde frontend ekosistemi yalnızca component tabanlı yapılardan ibaret değil. Artık gündemde server-first yaklaşımlar, edge rendering, AI destekli geliştirme ve developer experience (DX) odaklı yapılar var.
Yani mesele framework değil, felsefe.
Yeni nesil framework’ler artık “her şeyi tarayıcıda çalıştırmak” yerine, işi mümkün olduğunca sunucu tarafına taşıyor.
Next.js, SvelteKit ve Remix bu dönüşümün öncülerinden.
Server-first yaklaşımının avantajları:
React 19’un sunduğu Server Components özelliği bu anlayışın en somut örneği. Artık bazı bileşenler tamamen sunucuda render edilebiliyor, istemciye sadece işlenmiş HTML gönderiliyor.
Bu kod istemcide çalışmaz; yalnızca sonuç çıktısı gelir.
Sonuç: Daha az JS, daha yüksek hız.
Edge rendering – Kullanıcıya en yakın noktada render
“Server-side rendering” artık yeterli değil. 2026’da önemli olan, nerede render ettiğin.
Edge rendering, içeriği kullanıcıya en yakın fiziksel konumda oluşturmayı hedefliyor.
Vercel Edge Functions, Cloudflare Workers ve Deno Deploy gibi servisler, kodu global CDN katmanında çalıştırıyor.
Yani İstanbul’daki bir kullanıcı isteği Frankfurt’ta, Tokyo’daki biri içinse Singapur’da render ediliyor.
Bu sayede:
Edge rendering artık performans optimizasyonu değil, altyapı stratejisi haline geldi.
Yapay zekâ araçları 2026 itibarıyla frontend dünyasının ayrılmaz bir parçası haline geldi.
G*itHub Copilot, Cursor, bolt.new ve v0.dev* gibi platformlar yalnızca kod tamamlama değil, bileşen üretimi, test senaryosu ve dokümantasyon oluşturma gibi görevleri de üstleniyor.
Bu dönüşümün sonucu olarak geliştiricinin rolü değişiyor:
Artık odak nasıl kod yazılır değil, AI’ye neyi nasıl tarif ederiz.
Yeni beceri seti: Prompting
Doğru tanımlanmış bir istem (prompt), bir bileşeni sıfırdan manuel yazmaktan çok daha hızlı sonuç veriyor.
Bu da zamanla “AI-assisted developer” kavramını doğurdu — yani yapay zekâyı kod ortağı olarak kullanan geliştirici.
Developer Experience (DX) – Geliştirici deneyimi kazanıyor
Framework seçiminde eskiden performans, benchmark skorları veya syntax ön plandaydı.
Artık belirleyici olan şey developer experience (DX).
DX’i güçlü kılan faktörler:
Örneğin:
DX artık sadece geliştirme süresini değil, ekip moralini de belirliyor.
Kısacası iyi DX = daha az stres + daha fazla üretkenlik.
Islands architecture – Gerektiğinde canlanan bileşenler
Yeni nesil projeler “her şeyi hydrate etme” dönemini kapatıyor.
Islands architecture adı verilen yaklaşımda, yalnızca etkileşimli alanlar tarayıcıda canlandırılıyor.
Astro ve Qwik bu modelin önde gelen temsilcileri.
Bu sayede:
Kısacası sayfa artık tamamen “dinamik” değil, yalnızca gerektiğinde “canlı”.
Modern web artık hem hızlı hem çevreci olmayı hedefliyor.
Framework değil, felsefe seçimi
Tüm bu gelişmeler gösteriyor ki artık “React mi Vue mu?” sorusu tek başına anlamını yitirdi.
Geliştiricinin odağı “hangi araç”tan “hangi yaklaşım”a kaydı.
Yeni dönemde başarı, doğru framework’ü değil;
doğru mimariyi, doğru ortamda, doğru araçlarla kullanabilmekte yatıyor.
Bu yaklaşımlar artık modern frontend’in temel yapı taşları.
Framework’ler bu yapıların yalnızca araçları haline geldi.
Frontend geliştiricisinin yeni rolü
Bugünün frontend geliştiricisi sadece arayüz kodlayan biri değil.
Artık o:
Bu çok boyutlu rol, frontend’i yazılım mimarisinin merkezine taşıyor.
Geliştirici artık “tasarım ile backend arasında köprü” değil, tüm deneyimin mimarı.
Sonuç : Framework’lerin ötesine geçmek
Framework’ler hâlâ önemini koruyor, ancak artık oyunun tek kuralı değiller.
2026 ve sonrasında kazanan, en popüler framework’ü kullanan değil,
doğru mimari yaklaşımı seçip onu en verimli şekilde uygulayabilen geliştirici olacak.
Server-first mimariler, edge rendering, AI destekli geliştirme ve DX odaklı yapılar,
önümüzdeki yıllarda frontend ekosisteminin yönünü tamamen değiştirecek.
Gerçek yenilik, framework’te değil; onunla ne kadar bilinçli çalıştığında gizli.
2025-12-20 00:41:38
The manifest.json file is the backbone of a Chrome extension, acting as the primary metadata and configuration file that Chrome reads before loading or running the extension. It defines the extension’s identity—including its name, version, description, author, and icons—and clearly specifies how the extension behaves inside the browser. Through the manifest, developers declare permissions that control what browser APIs and websites the extension can access, ensuring security and user transparency. It also links all major components of the extension such as background service workers, content scripts, popups, options pages, and web-accessible resources, allowing Chrome to know when and where each part should execute. In Manifest Version 3 (MV3), manifest.json plays an even more critical role by enforcing modern security practices like non-persistent background execution, stricter permission handling, and improved performance, making it essential for building safe, efficient, and maintainable Chrome extensions.
{
"manifest_version": 3,
"name": "Guardium",
"short_name": "Guardium",
"description": "A secure browser-based password manager with autofill support",
"version": "1.0.0",
"action": {
"default_title": "Open Guardium",
"default_popup": "index.html"
},
"icons": {
"16": "assets/icons/icon16.png",
"32": "assets/icons/icon32.png",
"48": "assets/icons/icon48.png",
"128": "assets/icons/icon128.png"
},
"background": {
"service_worker": "background.js",
"type": "module"
},
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["contentScript.js"],
"run_at": "document_end",
"all_frames": true
}
],
"permissions": [
"activeTab",
"tabs",
"storage",
"scripting",
"alarms",
"notifications"
],
"host_permissions": [
"<all_urls>"
],
"web_accessible_resources": [
{
"resources": [
"assets/icons/*",
"injected/*.js"
],
"matches": ["<all_urls>"]
}
],
"options_page": "options.html",
"commands": {
"open-guardium": {
"suggested_key": {
"default": "Ctrl+Shift+G",
"mac": "Command+Shift+G"
},
"description": "Open Guardium popup"
}
},
"minimum_chrome_version": "114"
}
"manifest_version": 3,
🔹 Manifest Version
Specifies Manifest V3, the latest Chrome extension standard.
Enforces:
Better security
Service workers instead of background pages
Stricter permission control
"name": "Guardium",
🔹 Extension Name
The full name displayed:
In Chrome Extensions page
In Chrome Web Store
Under the toolbar icon
"short_name": "Guardium",
🔹 Short Name
Used where space is limited (e.g., toolbar labels).
Optional but recommended for UI consistency.
"description": "A secure browser-based password manager with autofill support",
🔹 Description
Brief summary of the extension’s purpose.
Visible in the Chrome Web Store and Extensions page.
"version": "1.0.0",
Version Number
Used by Chrome to manage updates.
Must follow semantic versioning format (major.minor.patch).
Toolbar Action (Popup UI)
"action": {
🔹 Defines behavior of the extension icon in the toolbar.
"default_title": "Open Guardium",
🔹 Tooltip text shown when the user hovers over the extension icon.
"default_popup": "index.html"
🔹 HTML file opened when the extension icon is clicked.
👉 This is your password manager UI (often a React build output).
},
🔹 End of action configuration.
🎨 Icons
"icons": {
🔹 Declares extension icons in different sizes.
"16": "assets/icons/icon16.png",
🔹 Used in:
Toolbar
Context menus
"32": "assets/icons/icon32.png",
🔹 Used on high-DPI displays and system UI.
"48": "assets/icons/icon48.png",
🔹 Used on the Chrome Extensions page.
"128": "assets/icons/icon128.png"
🔹 Used in the Chrome Web Store listing.
},
🔹 End of icons section.
⚙ Background Service Worker
"background": {
🔹 Defines background logic of the extension.
"service_worker": "background.js",
🔹 JavaScript file that:
Handles events
Listens for messages
Manages alarms, auth, encryption, etc.
⚠️ Runs only when needed (not persistent).
"type": "module"
🔹 Enables ES modules:
Allows import / export
Cleaner and scalable architecture
},
🔹 End of background configuration.
🌐 Content Scripts
"content_scripts": [
🔹 Declares scripts injected into web pages.
{
🔹 One content-script rule block.
"matches": ["<all_urls>"],
🔹 Injects script on all websites.
Required for password managers (login form detection).
"js": ["contentScript.js"],
🔹 JavaScript file injected into matching pages.
"run_at": "document_end",
🔹 Script runs after DOM is loaded.
Ensures forms and inputs exist.
"all_frames": true
🔹 Script runs inside:
Main page
All iframes (important for embedded login forms)
}
],
🔹 End of content script declaration.
🔐 Permissions
"permissions": [
🔹 Declares Chrome APIs the extension can use.
"activeTab",
🔹 Temporary access to the currently active tab.
"tabs",
🔹 Allows reading tab metadata (URL, ID, title).
"storage",
🔹 Enables chrome.storage for saving encrypted passwords.
"scripting",
🔹 Allows dynamic script injection (MV3 requirement).
"alarms",
🔹 Enables scheduled background tasks.
"notifications"
🔹 Allows user notifications (e.g., password saved).
],
🔹 End of permissions list.
🌍 Host Permissions
"host_permissions": [
🔹 Specifies which websites the extension can access.
"<all_urls>"
🔹 Allows interaction with all websites.
Required for autofill extensions.
],
🔹 End of host permissions.
📦 Web Accessible Resources
"web_accessible_resources": [
🔹 Allows web pages or content scripts to access extension files.
{
🔹 Resource rule object.
"resources": [
"assets/icons/*",
"injected/*.js"
],
🔹 Files that can be accessed externally.
"matches": ["<all_urls>"]
🔹 Websites allowed to access these resources.
}
],
🔹 End of web-accessible resources.
⚙ Options Page
"options_page": "options.html",
🔹 Settings page for the extension.
Used for:
Preferences
Security settings
Sync options
⌨ Keyboard Commands
"commands": {
🔹 Defines keyboard shortcuts.
"open-guardium": {
🔹 Unique command identifier.
"suggested_key": {
🔹 Platform-specific shortcuts.
"default": "Ctrl+Shift+G",
"mac": "Command+Shift+G"
🔹 Shortcut keys for Windows/Linux and macOS.
},
🔹 End of key definition.
"description": "Open Guardium popup"
🔹 Description shown in Chrome shortcut settings.
}
},
🔹 End of commands section.
🔎 Chrome Version Requirement
"minimum_chrome_version": "114"
🔹 Ensures compatibility with required MV3 APIs.
}
🔹 End of manifest file.
✅ Final Summary
This manifest.json:
Fully complies with Manifest V3
Supports password management + autofill
Is Chrome Web Store ready
Covers UI, background, content scripts, permissions, security
2025-12-20 00:39:21
Custom Litecoin (LTC) client and utilities for XChainJS — a lightweight TypeScript SDK for building cross-chain wallets, crypto payment flows, and DeFi tooling with a common interface.
This package provides:
Source package: https://github.com/xchainjs/xchainjs-lib/tree/master/packages/xchain-litecoin
XChainJS docs: https://docs.xchainjs.org/xchain-client/xchain-litecoin/
getFeeRates, getFeesWithMemo, etc.)@xchainjs/xchain-client, @xchainjs/xchain-crypto, @xchainjs/xchain-util.References:
yarn add @xchainjs/xchain-litecoin
According to the official docs, install these as well:
yarn add @xchainjs/xchain-client @xchainjs/xchain-crypto @xchainjs/xchain-util axios bitcoinjs-lib coininfo wif
Create a client instance, derive an address, validate it, and fetch its balance.
import { Client } from '@xchainjs/xchain-litecoin'
import { Network } from '@xchainjs/xchain-client'
import { baseToAsset } from '@xchainjs/xchain-util'
const connectWallet = async () => {
const phrase = 'your mnemonic phrase here'
const ltcClient = new Client({ network: Network.Mainnet, phrase })
const address = ltcClient.getAddress()
console.log('Address:', address)
const isValid = ltcClient.validateAddress(address)
if (!isValid) throw new Error('Invalid address')
const balances = await ltcClient.getBalance(address)
const readable = baseToAsset(balances[0].amount).amount()
console.log('Balance:', readable.toString())
}
connectWallet().catch(console.error)
Build and broadcast a transaction using the client.
import { Client, LTC_DECIMAL } from '@xchainjs/xchain-litecoin'
import { assetToBase, assetAmount } from '@xchainjs/xchain-util'
const transferLitecoin = async () => {
const phrase = 'your mnemonic phrase here'
const recipient = 'ltc recipient address here'
const ltcClient = new Client({ phrase })
const amount = assetToBase(assetAmount(0.01, LTC_DECIMAL))
const txid = await ltcClient.transfer({
amount,
recipient,
memo: 'memo',
})
console.log('TX sent:', txid)
console.log('Explorer:', ltcClient.getExplorerTxUrl(txid))
}
transferLitecoin().catch(console.error)
import { Client } from '@xchainjs/xchain-litecoin'
import { baseToAsset } from '@xchainjs/xchain-util'
const returnFees = async () => {
const phrase = 'your mnemonic phrase here'
const ltcClient = new Client({ phrase })
const { fast, fastest, average } = await ltcClient.getFees()
console.log('Fast:', baseToAsset(fast).amount().toString())
console.log('Fastest:', baseToAsset(fastest).amount().toString())
console.log('Average:', baseToAsset(average).amount().toString())
const feeRates = await ltcClient.getFeeRates()
console.log('FeeRates:', feeRates)
}
returnFees().catch(console.error)
You can pass feeRate into transfer parameters:
// feeRates.fastest is a number
await ltcClient.transfer({
amount,
recipient,
memo: 'memo test',
feeRate: feeRates.fastest,
})
import { Client } from '@xchainjs/xchain-litecoin'
const transactionData = async () => {
const phrase = 'your mnemonic phrase here'
const ltcClient = new Client({ phrase })
const hash = 'your tx hash'
const txData = await ltcClient.getTransactionData(hash)
console.log('TxData:', txData)
}
transactionData().catch(console.error)
Package source (GitHub):
https://github.com/xchainjs/xchainjs-lib/tree/master/packages/xchain-litecoin
Docs (overview):
https://docs.xchainjs.org/xchain-client/xchain-litecoin/
Docs (how it works):
https://docs.xchainjs.org/xchain-client/xchain-litecoin/how-it-works.html
Docs (how to use):
https://docs.xchainjs.org/xchain-client/xchain-litecoin/how-to-use.html