In a terminal far, far away, a script started running...
> No hype. Just notes worth keeping 💭
🔘 @TerminalNotes <- #memory
user@terminal:~$ bash ./magic.sh
> No hype. Just notes worth keeping 💭
🔘 @TerminalNotes <- #memory
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.
👤 Martin Fowler
🔘 @TerminalNotes <- #quote
📌 #Concept: First-Class Functions
In languages like Go, Python, and Rust, functions are described as "First-Class." This is a fundamental concept in software engineering.
The term was coined by computer scientist Christopher Strachey in the mid-1960s. He drew a parallel to "citizenship."
In a society, a "First-Class Citizen" has full rights: they can own property, vote, and travel freely. A "Second-Class Citizen" has restrictions. In programming terms, if a function is "First-Class," it enjoys the same rights and privileges as primitive data types like an
🔆 Technical Definition
For a language to support first-class functions, it must allow functions to be:
1. Assigned to variables.
2. Passed as arguments to other functions.
3. Returned as values from other functions.
🔷 Example in Go
In Go, functions are values. In the example below, we treat the
💠 Why It Matters
This capability is the foundation of Higher-Order Functions (a function that operates on other functions). It allows developers to write flexible code, such as middleware in web servers (common in Go) by abstracting logic into passable parameters.
🔘 @TerminalNotes <- #programming
In languages like Go, Python, and Rust, functions are described as "First-Class." This is a fundamental concept in software engineering.
The term was coined by computer scientist Christopher Strachey in the mid-1960s. He drew a parallel to "citizenship."
In a society, a "First-Class Citizen" has full rights: they can own property, vote, and travel freely. A "Second-Class Citizen" has restrictions. In programming terms, if a function is "First-Class," it enjoys the same rights and privileges as primitive data types like an
integer or a string.In languages without first-class functions, a function is just a static block of code. It is distinct from data variables. You can call it, but you cannot store it in a variable or pass it directly to another function. Examples are: Java (Pre-version 8), Pascal, & Algol
🔆 Technical Definition
For a language to support first-class functions, it must allow functions to be:
1. Assigned to variables.
2. Passed as arguments to other functions.
3. Returned as values from other functions.
🔷 Example in Go
In Go, functions are values. In the example below, we treat the
add function just like an integer variable; we assign it and pass it around.package main
import "fmt"
func main() {
// 1. Assigning a function to a variable
// 'add' is now a variable holding a function
add := func(x, y int) int {
return x + y
}
// 2. Passing that variable to another function
process(add)
}
// This function accepts another function as a parameter
func process(operation func(int, int) int) {
result := operation(10, 5)
fmt.Println("Result:", result)
}
💠 Why It Matters
This capability is the foundation of Higher-Order Functions (a function that operates on other functions). It allows developers to write flexible code, such as middleware in web servers (common in Go) by abstracting logic into passable parameters.
🔘 @TerminalNotes <- #programming
This media is not supported in your browser
VIEW IN TELEGRAM
Beautiful things don't ask for attention.
🎥 The Secret Life of Walter Mitty 2013
🔘 @TerminalNotes <- #life #quote
❤1
The only way to learn a new programming language is by writing programs in it.
👤 Dennis Ritchie
🔘 @TerminalNotes <- #quote
📌 #concept: Populating
In software development, populating describes the process of taking an empty or partially initialized data structure and filling it with meaningful data. It is the bridge between "getting" data (fetching) and "using" data (rendering or processing).
Most applications follow a standard lifecycle for data handling:
1. Fetch: Retrieve raw data from a source (Database, API, JSON file).
2. Initialize: Create an empty container (List, Array, Map).
3. Populate: Iterate through the raw data and fill the container.
🔆 Analogy
Think of a form on a clipboard.
🔹 The Structure: The blank form with boxes for "Name" and "Age".
🔸 The Data: The person standing in front of you.
🔹 Populating: The act of asking them questions and writing the answers into the boxes.
🔷 Example in Go
Here we fetch raw IDs and use them to populate a list of User objects:
🔘 @TerminalNotes <- #programming
In software development, populating describes the process of taking an empty or partially initialized data structure and filling it with meaningful data. It is the bridge between "getting" data (fetching) and "using" data (rendering or processing).
Most applications follow a standard lifecycle for data handling:
1. Fetch: Retrieve raw data from a source (Database, API, JSON file).
2. Initialize: Create an empty container (List, Array, Map).
3. Populate: Iterate through the raw data and fill the container.
🔆 Analogy
Think of a form on a clipboard.
🔹 The Structure: The blank form with boxes for "Name" and "Age".
🔸 The Data: The person standing in front of you.
🔹 Populating: The act of asking them questions and writing the answers into the boxes.
🔷 Example in Go
Here we fetch raw IDs and use them to populate a list of User objects:
// 1. Initialize empty container
var activeUsers []User
// 2. Fetch raw data (simulated loop)
rawIDs := []int{1, 2, 3}
// 3. Populate
for _, id := range rawIDs {
newUser := User{ID: id, Name: "Guest"}
activeUsers = append(activeUsers, newUser)
}
🔘 @TerminalNotes <- #programming
تو این روزایی که وضعیت اینترنت جالب نیست، اپلیکیشنهای Todo که دنبال سینک کردنن و به اینترنت و VPN نیاز دارن (مثل Notion) رو مخ میرن. واسه همین یه Todo Manager جمعوجور با Go نوشتم که همه چی رو لوکال توی یه فایل JSON ذخیره میکنه و دیگه کاری به نت نداره:
📥 GitHub: togo
کی میدونه؛ ممکنه باز بهکار بیاد.
🔘 @TerminalNotes <- #project
📥 GitHub: togo
کی میدونه؛ ممکنه باز بهکار بیاد.
پ.ن: نمونش توی وب بود ولی به کل بازنویسیش کردن به gui. چرا خب؟ کامند لاین به این خوشگلی :)
نسخه cliش رو بر اساس فیچرها و نیازهای خودم نوشتم.
🔘 @TerminalNotes <- #project
👍2🔥1
💢 فیش ورژن 4 و تغییر Keybind های دیفالت
توی fish shell از ورژن 4 به بعد، اومدن bind های پیشفرض رو عوض کردن و ماسل مموری کاربرای قدیمی رو به چالش کشیدن. مثال تفاوت
🔹Version 3
🔸Version 4
توی ورژن 3 کلمه پاک میشه ورژن 4 توکن.
🛠 راه حل
اگه مثل من به ورژن 3 عادت دارید، برای برگشتن به رفتار قدیمی فایل
و کد زیر رو داخلش paste کنید:
پ.ن: فیش یه مکانیزم autoload داره که هر فایلی توی
قرار بگیره به عنوان یه فانکشن مستقل لود میشه.
🔗 Issue 10926
🔘 @TerminalNotes <- #linux #fish
توی fish shell از ورژن 4 به بعد، اومدن bind های پیشفرض رو عوض کردن و ماسل مموری کاربرای قدیمی رو به چالش کشیدن. مثال تفاوت
alt+backspace بین ورژن 3 و 4:🔹Version 3
curl https://wttr.in/Tehran # before
curl https://wttr.in/ # after
🔸Version 4
curl https://wttr.in/Tehran # before
curl # after
توی ورژن 3 کلمه پاک میشه ورژن 4 توکن.
🛠 راه حل
اگه مثل من به ورژن 3 عادت دارید، برای برگشتن به رفتار قدیمی فایل
fish_user_key_bindings.fish رو توی مسیر زیر بسازید:~/.config/fish/functions/
و کد زیر رو داخلش paste کنید:
function fish_user_key_bindings
bind alt-left prevd-or-backward-word
bind alt-right nextd-or-forward-word
bind alt-backspace backward-kill-word
bind alt-delete kill-word
bind ctrl-left backward-token
bind ctrl-right forward-token
bind ctrl-backspace backward-kill-token
bind ctrl-delete kill-token
bind ctrl-alt-h backward-kill-word
end
اسم فایل و فانکشن نه تنها باید با هم یکی باشن، بلکه باید دقیقا همین اسم باشن — چون fish_user_key_bindings یه هوک هاردکدشده fish هست که بعد از لود شدن bind های پیشفرض صدا زده میشه.
پ.ن: فیش یه مکانیزم autoload داره که هر فایلی توی
~/.config/fish/functions/قرار بگیره به عنوان یه فانکشن مستقل لود میشه.
🔗 Issue 10926
🔘 @TerminalNotes <- #linux #fish
📌 #Tool: eBPF
اگه دواپس کار میکنید احتمالا اسم eBPF رو شنیدید. یه تکنولوژی که خیلیها از شرکتها مثل نتفلیکس و فیسبوک بهش وابستهان.
تا قبل از eBPF، اگر میخواستید بدونید "دقیقا" توی سیستمعامل چه خبره، یا میخواستید روی ترافیک شبکه کنترل داشته باشید (مثل فیلتر کردن پکتها یا load balancing سفارشی)، دو راه داشتید:
۱. تغییر سورس کرنل: که خب زمان بره.
۲. ماژولهای کرنل: که دسترسی کامل داشتن، ولی یه باگ کوچیک توشون کافی بود تا همه چیز بیاد پایین.
🧭 راه حل مدرن: eBPF
خیلی ساده، eBPF یه ماشین مجازی (Virtual Machine) کوچیک و امنه که داخل خودِ کرنل لینوکس زندگی میکنه.
شما میتونید برنامه بنویسید، اونها رو به کرنل تزریق کنید و کرنل اونها رو اجرا کنه. اما با این مزیت که:
🔹 امنیت تضمین شده: قبل از اجرا، یه بخشی به اسم Verifier کد شما رو چک میکنه تا مطمئن شه لوپ بینهایت نداره یا به حافظه غیرمجاز دسترسی پیدا نمیکنه.
🔹 بدون توقف: برای اجرای این برنامهها نیازی به ریستارت کردن سیستم یا کامپایل دوباره کرنل نیست.
🔹 سرعت بالا: کدها به صورت JIT (Just-In-Time) کامپایل میشن و با سرعت Native اجرا میشن.
این تکنولوژی نیروی محرکه نسل بعدی ابزارهای شبکه و نظارت (Observability) هست.
⚖️ کاربردش کجاست
تقریبا هر جایی که نیاز به سرعت و دید عمیق هست:
• مانیتورینگ و Observability: ابزارهایی که نشون میدن کدوم پروسس داره چه فایلهایی رو باز میکنه یا چه پکتهایی رو میفرسته (بدون سربار ابزارهای قدیمی).
• شبکه: فیلتر کردن و مدیریت ترافیک.
شرکت هایی که ازش استفاده میکنن و چطور رو میتونید اینجا از سایت رسمی ببینید.
💠 جمعبندی
امروزه کار با eBPF با وجود زبونایی مثل Go و پایتون و کتابخونههای جدید راحت شده و نوشتن ابزارهایی که مستقیم با کرنل حرف میزنن خیلی سادهتر شده.
یه پروژه قدیمی با Go پیدا کردم که ساده پراسس های سیستم رو لایو مانیتور میکنه. چون قدیمیه یکم ریفکتورش کردم و پست های بعدی میذارمش میتونید چک کنید و ابزار خودتون رو بنویسید.
🔘 @TerminalNotes <- #linux #ebpf
اگه دواپس کار میکنید احتمالا اسم eBPF رو شنیدید. یه تکنولوژی که خیلیها از شرکتها مثل نتفلیکس و فیسبوک بهش وابستهان.
تا قبل از eBPF، اگر میخواستید بدونید "دقیقا" توی سیستمعامل چه خبره، یا میخواستید روی ترافیک شبکه کنترل داشته باشید (مثل فیلتر کردن پکتها یا load balancing سفارشی)، دو راه داشتید:
۱. تغییر سورس کرنل: که خب زمان بره.
۲. ماژولهای کرنل: که دسترسی کامل داشتن، ولی یه باگ کوچیک توشون کافی بود تا همه چیز بیاد پایین.
🧭 راه حل مدرن: eBPF
خیلی ساده، eBPF یه ماشین مجازی (Virtual Machine) کوچیک و امنه که داخل خودِ کرنل لینوکس زندگی میکنه.
شما میتونید برنامه بنویسید، اونها رو به کرنل تزریق کنید و کرنل اونها رو اجرا کنه. اما با این مزیت که:
🔹 امنیت تضمین شده: قبل از اجرا، یه بخشی به اسم Verifier کد شما رو چک میکنه تا مطمئن شه لوپ بینهایت نداره یا به حافظه غیرمجاز دسترسی پیدا نمیکنه.
🔹 بدون توقف: برای اجرای این برنامهها نیازی به ریستارت کردن سیستم یا کامپایل دوباره کرنل نیست.
🔹 سرعت بالا: کدها به صورت JIT (Just-In-Time) کامپایل میشن و با سرعت Native اجرا میشن.
این تکنولوژی نیروی محرکه نسل بعدی ابزارهای شبکه و نظارت (Observability) هست.
⚖️ کاربردش کجاست
تقریبا هر جایی که نیاز به سرعت و دید عمیق هست:
• مانیتورینگ و Observability: ابزارهایی که نشون میدن کدوم پروسس داره چه فایلهایی رو باز میکنه یا چه پکتهایی رو میفرسته (بدون سربار ابزارهای قدیمی).
• شبکه: فیلتر کردن و مدیریت ترافیک.
🛑 البته قدرت همیشه درست به کار نمیره. این ابزار قابلیت DPI هم داره که سانسورچی توی ایران ازش برای بلاک کردن و کنترل ترافیک مردم استفاده میکنه.
شرکت هایی که ازش استفاده میکنن و چطور رو میتونید اینجا از سایت رسمی ببینید.
💠 جمعبندی
امروزه کار با eBPF با وجود زبونایی مثل Go و پایتون و کتابخونههای جدید راحت شده و نوشتن ابزارهایی که مستقیم با کرنل حرف میزنن خیلی سادهتر شده.
یه پروژه قدیمی با Go پیدا کردم که ساده پراسس های سیستم رو لایو مانیتور میکنه. چون قدیمیه یکم ریفکتورش کردم و پست های بعدی میذارمش میتونید چک کنید و ابزار خودتون رو بنویسید.
قبلش برای درک برنامه لازمه چندتا مفهوم لینوکسی مثل یوزر اسپیس و کرنل اسپیس توضیح داده بشه که پست بعد مینویسم.
🔘 @TerminalNotes <- #linux #ebpf
📌 #Concept: Kernel Space & Userspace
یه رستوران بزرگ رو تصور کنید:
• مشتری (برنامهها): شما که توی سالن رستوران نشستید و میخواید غذا سفارش بدید. مشتریها اجازه ندارن وارد آشپزخانه بشن یا دست به وسایل آشپزخونه بزنن.
• گارسون (System Calls): واسطه بین شما و آشپزخونه هست. منو رو جلوتون میذاره و سفارشتون رو به آشپزخونه میبره.
• آشپز و آشپزخونه (Kernel): قلب اصلی رستوران که دسترسی کامل به همه امکانات داره، غذا میپزه، و کارهای مهم رو انجام میده.
به همین ترتیب Kernel space و userspace از هم جدا میشن و از طریق یه راه ارتباطی ایمن که syscall باشه با هم دیگه ارتباط میگیرن.
💢 چرا این جداسازی؟
1. امنیت
2. پایداری
🔆 نحوه سفارش تا تحویل با System Calls
1. انتخاب غذا: شما از منو (API سیستم عامل) چیزی مثل "پیتزا" انتخاب میکنید. برای مثال برنامه میخواد یه فایل رو باز کنه.
2. گارسون سفارش رو میبره: فراخوانی سیستمی (syscall) مثل
3. آشپز سفارش رو آماده میکنه: کرنل با دسترسی کامل به منابع سیستم، درخواست رو پردازش میکنه، فایل رو باز میکنه، دیتا رو میخونه یا تو دیسک مینویسه.
4. غذا سرو میشه: نتیجه به برنامه برمیگرده و CPU دوباره به حالت User برمیگرده.
❇️ مزایای این معماری و جمع بندی
این طراحی باعث میشه:
• هر برنامه در فضای امن خودش کار کنه و نتونه کار دیگران رو خراب کنه.
• اگه یه برنامه مشکل پیدا کرد، کل سیستم از کار نیوفته.
• منابع حیاتی سیستم (مثل دیسک، CPU و غیره) تحت کنترل کامل کرنل باشن.
🔘 @TerminalNotes <- #linux
یه رستوران بزرگ رو تصور کنید:
• مشتری (برنامهها): شما که توی سالن رستوران نشستید و میخواید غذا سفارش بدید. مشتریها اجازه ندارن وارد آشپزخانه بشن یا دست به وسایل آشپزخونه بزنن.
• گارسون (System Calls): واسطه بین شما و آشپزخونه هست. منو رو جلوتون میذاره و سفارشتون رو به آشپزخونه میبره.
• آشپز و آشپزخونه (Kernel): قلب اصلی رستوران که دسترسی کامل به همه امکانات داره، غذا میپزه، و کارهای مهم رو انجام میده.
به همین ترتیب Kernel space و userspace از هم جدا میشن و از طریق یه راه ارتباطی ایمن که syscall باشه با هم دیگه ارتباط میگیرن.
💢 چرا این جداسازی؟
1. امنیت
اگه هر مشتری بتونه مستقیم به آشپزخونه بره، هرج و مرج به پا میشه. ممکنه کسی اشتباهی اجاق رو خاموش کنه یا مواد غذایی بقیه رو خراب کنه. توی لینوکس هم همینطوره برنامههای کاربری نباید بتونن مستقیما به حافظه یا سختافزار دسترسی داشته باشن.
2. پایداری
اگه یه مشتری تو سالن غذاش بریزه، مشکلی برای آشپزخونه پیش نمیاد. ولی اگه کسی توی آشپزخانه اشتباهی بکنه، کل سفارش ها تاخیر میخورن یا حتی ممکنه کنسل بشن. توی لینوکس هم اگر یه برنامه کرش کنه، سیستم عامل به کارش ادامه میده و مختل نمیشه.
🔆 نحوه سفارش تا تحویل با System Calls
1. انتخاب غذا: شما از منو (API سیستم عامل) چیزی مثل "پیتزا" انتخاب میکنید. برای مثال برنامه میخواد یه فایل رو باز کنه.
2. گارسون سفارش رو میبره: فراخوانی سیستمی (syscall) مثل
()open شروع به کار میکنه و یه وقفه نرمافزاری ایجاد میکنه که CPU رو از حالت User به حالت Kernel تغییر میده.3. آشپز سفارش رو آماده میکنه: کرنل با دسترسی کامل به منابع سیستم، درخواست رو پردازش میکنه، فایل رو باز میکنه، دیتا رو میخونه یا تو دیسک مینویسه.
4. غذا سرو میشه: نتیجه به برنامه برمیگرده و CPU دوباره به حالت User برمیگرده.
خلاصه که نمیتونید داد بزنید "آشپز! پیتزا بده!". باید از طریق گارسون (syscall) سفارش بدهید.
❇️ مزایای این معماری و جمع بندی
این طراحی باعث میشه:
• هر برنامه در فضای امن خودش کار کنه و نتونه کار دیگران رو خراب کنه.
• اگه یه برنامه مشکل پیدا کرد، کل سیستم از کار نیوفته.
• منابع حیاتی سیستم (مثل دیسک، CPU و غیره) تحت کنترل کامل کرنل باشن.
🔘 @TerminalNotes <- #linux
👍2💔1