ویژه

ایران چگونه کار می‌کند؟

جریان پولی + کنترل = خدا. اگر به آن اعتقادی ندارید خون شما برای آن قربانی خواهد شد.

این نوشته در ابتدا در ۳۰ می ۲۰۲۲ (۹ خرداد ۱۴۰۱) به انگلیسی نوشته شده است: https://telegra.ph/How-Iran-Works-05-30

The future is already here – it’s just not evenly distributed.

William Gibson

جریان پولی

مطمئن نیستم که آن را از کجا یاد گرفتند ولی متدی که استفاده می‌کنند به خوبی طراحی شده و همین باعث می‌شود که بیشتر مطمئن باشم کار خودشان نیست.

جریان پولی به معنی داشتن پول نیست، جریان پولی به مالکیت پول و کنترل مجاری پولی اشاره می‌کند. حکومت «اسلامی» نه تنها به جریان پولی، بلکه زالووار به داشتن و پاسگاری حجم زیادی از پول بین ارکان خودش هم علاقه‌مند است.

منابع طبیعی

ایران از نظر منابع طبیعی بسیار غنی است. به طوری که اگر بتونید آن‌ها را به بازارهای جهانی برسانید عملا پول بادآورده است. اعداد برای یک «پول بادآورده» بسیار بزرگ هستند. با هم ببینیم که این پول‌ها چطور خرج میشوند:

یارانه نقدی

تا امسال (۱۴۰۱) چند میلیون ایرانی (نه همه مردم، تنها بخشی از مردم که حکومت تصمیم می‌گیرد) ماهیانه یارانه نقدی معادل حدود ۱.۸ دلار دریافت می‌کردند (میانگین حدود ۲ سال اخیر). اگر فرض کنیم که ۸۰ میلیون ایرانی این یارانه را دریافت می‌کردند (چون بخشی یارانه بیشتری دریافت می‌کردند)، حکومت ماهیانه حدود ۱۴۴ میلیون دلار برای این یارانه هزینه می‌کرد که جوکی تلخ محسوب می‌شود.

یارانه قاچاچ

ارکان حکومت با دریافت یارانه واردات، بخش بزرگی از قاچاق را انجام می‌دهد و به نام کالای وارداتی به شما می‌فروشد و عملا دست در جیب شما می‌کنند. این کار بدون توان نظامی سپاه ممکن نیست. از این طریق شما را فقیرتر می‌کنند. هدف داشتن مردمی برای بردگی ارزان است.

پروژه‌های ساخت و ساز

سپاه همچنین زیرمجموعه‌هایی برای انجام فعالیت‌های ساخت و ساز دارد (که خیلی از آن‌ها فاجعه زیست محیطی محسوب می‌شوند) که بخش قابل توجه‌ای از این پول‌ها را می‌بلعد.

می‌دانم که تمامی پول‌ها مستقیما به جیب حکومت نمی‌رود، اما مابقی از اهمیت زیادی برخوردار نیست، در نهایت آنها اجازه می‌دهند که یک جرعه آب و تکه نانی بخورید تا بتوانید برای کار و زندگی‌تان باز هم بدووید.

via GIPHY

حتی پول هنگفت هم جان شما را نجات نمی‌دهد تا اینکه از «خدا» پیروی کنید، در غیر این صورت شما «سلطان فولان و بهمان» می‌شوید و طناب دار در انتظار شماست.

چه کسی گردش دلار را دستوری کنترل می‌کند؟ حکومت. حقوق شما به ریال است. پول شما کجاست، بانک؟ چه کسی آن را دستوری کنترل می‌کند؟ به همین راحتی.

جنگ

دفاع از اسد (با ویرانی زندگی مردم) بهانه بسیار خوبی برای آنها بود تا دلارهای زیادی از منابع مردمی را تصاحب و برای جنگ یا خودشان خرج/ذخیره کنند.

پول در مقابل کمک به حکومت

اگر نمی‌توانید کار پیدا کنید، حکومت همواره یک راه نهایی برای شما قرار داده: کمک به حکومت برای سرکوب و آدمفروشی. شاید پول چندانی نسیبتان نشود، اما اگر اصرار کنید و خودتان را به خدا اثبات کنید، می‌توانید. حتی ممکن است رئیس مجلس شوید! مهم نیست که مهارت خاصی دارید یا نه، می‌توانید اطلاعات جمع‌آوری و ارائه کنید یا کسی را بکشید. راه مشابه دیگر این است که برای کسی که قبلا خودش را اثبات کرده کار کنید و باقی مانده غذای او را بخورید. در این صورت حتی حتی عذاب وجدان کمتری هم خواهید داشت، چیزی شبیه سگ یک شکارچی.

اگر علاقه‌مند باشید با صرف کمی وقت می‌توانید ردپای جریان‌های پولی را در آغاز «انقلاب اسلامی» هم رصد کنید.

کنترل

نیاز نیست که واقعا به خدا باور داشته باشید، کافی است که طوری عمل کنید که گویی باور دارید. حکومت اسلامی تمایل زیادی ندارد که شما را بکشد چرا که در نهایت به تعدادی از شما برای نیروی بردگی نیاز دارد (بیشتر بهتر)، بالاخره باید کسی باشد که حاضر باشد جانش را برای خدا به خطر بیاندازد، از این رو آنها راه‌هایی برای پیشگیری از این مسئله تدارک دیده‌اند:

۱. مشغول کردن حداکثری شما با ساده‌ترین و پیش پا افتاده‌ترین مسائل

البته آنها کوته‌بین نیستند و راه‌های دیگری را هم در نظر گرفته‌اند:

‌۲. شستشوی مغزی

از دوران ابتدایی مدرسه، اخبار روزانه، با هزاران حساب بات، فاکتوری و انسان‌های چشم و گوش بسته دنباله رو در شبکه‌های اجتماعی، به شما و بچه‌هایتان دروغ می‌گویند، گس‌لایت می‌کنند و شستشوی مغزی می‌دهند. تا شما را از آنچه که هستید به بمبی تبدیل کنند تا جایی که خدا از شما می‌خواهد منفجر شوید.

حکومت حتی چند عروسک خیمه‌شب‌بازی را در جامعه رها می‌کند. این عروسک‌ها حتی لزوما به ساپورت مالی یا دیکته نیاز ندارند تا نقش شستشوگر مغزی را بازی کنند یا مردم را حداکثری سرگرم نگاه دارند. زمان‌هایی هم حتی آن‌ها را به عنوان قهرمان یا «دانشمند» به خورد ملت می‌دهند. دیوانه‌هایی همچون حسن عباسی و کوتوله‌هایی نظیر رائفی‌‌پور از این گروه هستند.

۳. پیداکردن کسانی که در مقابل خدا هستند

این راه حل حکومت با خود ریسک‌هایی برایش به همراه دارد، اما در عین حال موثر است: هر از گاهی آنها یک بحران ایجاد می‌کنند، یا از دل یک رویداد/تظاهرات یک بحران ایجاد می‌کنند. در این سناریو، آنها تنها نیاز داردند تا کسانی را که در مقابل خدا قرار گرفته‌اند یا نزدیک به رویارویی با خدا هستند را پیدا کنند و تبخیرشان کنند. چگونه این موثر است؟ چون خدا برای آنها به خوبی کار می‌کند و مردم را از قبل دسته‌بندی کرده:

الف) کسانی توسط راه حل‌های ۱ و ۲ کنترل شده‌اند

ب) کسانی که (مستقیم/غیر مستقیم) با حکومت همکاری می‌کنند (کسانی هم صرفا برای پول همکاری می‌کنند)

پ) کسانی که در زندان یا در قبر هستند

ت) کسانی که در حال دویدن برای زنده‌ماندن هستند

ث) کسانی که در نبود امید، بی عمل هستند یا در حال نبرد با افسردگی

چرا این راهکار پر ریسک‌تر از راه‌های دیگر است؟ چه اتفاقی می‌افتد اگه بخش‌هایی از این ۵ گروه بتوانند به مردم در خیابان ملحق شوند؟ البته برای این حالت هم دو راهکار پیش روی آنهاست:

۴. همه را بکشند

آنها از سرنوشت شاه یاد گرفته‌اند که مدارا با مردم در خیابان پایان کار آنها خواهد بود، بنابراین وقتی که اسلحه، کانادا (متن انگلیسی این نوشته چندین ماه قبل از حرکت‌های جدید کانادا نوشته شده بود)، ترکیه و ویزا دارند، برای آنها بازی همه یا هیچ است. آنها آنقدر می‌کشند تا زمانی که مطمئن شوند که سیستم سمی‌شان (خدا) ادامه پیدا می‌کند. اما کشتار، توجه جهانی را به خود جلب می‌کند، بنابراین:

۵. داشتن کیل‌سوئیچ و کنترل بر اینترنت

آنها در حال حاضر هم برای اینترنت ایران کیل‌سوئچ دارند و در حال پیگیری برای کنترل کامل گردش اطلاعات در داخل ایران هستند.

مهم نیست که حتی فرزند خود آنها باشید، باید به خدا تعظیم کنید.

۶. «قانونی‌سازی» بخشی از کشتارها

دلیل واقعی اینکه آنها یک حکومت «اسلامی» هستند و عاشق آن هستند. آنها نمی‌توانن‌د همیشه بکشند و فقط بگویند که «آنها مخل امنیت ملی بودند». یکی از بهترین راه‌ها (خصوصا بازداشت شده‌ها) کشتار به اسم الله است و دیگران (جامعه جهانی) هم باید به دین آنها «احترام» بگذارند. جوک دو کلمه‌ای امروز: حقوق بشر.

۷. ساخت فایل‌ها و اسناد جعلی

با بکارگیری وحشیانه‌ترین شکنجه‌ها برای کارهایی که معترضین هرگز انجام نداده‌اند و یا حتی هرگز اتفاق نیوفتاده اعتراف اجباری می‌گیرند. این اتفاق بارها و بارها افتاده است و گرچه توسط هر عقل سلیمی باورپذیر نیستند، حومت بسیاری را به این روش به قتل می‌رساند.

چرا کسی از جامعه بین‌الملل مداخله نمی‌کند؟

(این بخش از نوشته مشخصا میزان نا امیدی‌ام از حمایت‌های جهانی را در چند ماه قبل بازتاب می‌دهد)

مداخله (حتی سیاسی) خیلی هم آسان نیست، از طرفی حکومت ملاها یکی از بهترین اتفاقاتی است که هم برای غرب و هم برای شرق در برابر ایران افتاد. ملاها آسان‌ترین، بی‌عمل‌ترین، بی‌عقل‌ترین‌های ایران بودند. آنها هر کاری می‌کنند تا در قدرت بمانند، هر کاری. خرید اسلحه از اسرائیل، گفتگوی مخفیانه با غرب در حالی که در نماز جمعه شعار «مرگ بر امریکا» سر می‌دهند، و توافق با غرب بدون هیچ ضمانتی. برای نزدیک شدن به شرق تلاش می‌کنند به این امید که چین در آین ه قدرت اول و آقای دنیا شود، غافل از اینکه خودشان دستمال چرکی برای چین هم نیستند.

آنها جلوی شرق و غرب لخت خم خواهند شد تا در قدرت باقی بمانند. به گونه‌ای شبیه روابط بین ایران و انگلیس در قرن گذشته است، اما با طرفین بیشتر.

ویژه

گشایش اقتصادی، از بورس تهران تا کاراکاس

در سال‌های اخیر با رشد تورم و افت ارزش پول ملی مشکلات زیربنایی اقتصاد ایران بیش از پیش نمود پیدا کرده تا جایی که توده جامعه دست از پیشرفت اقتصادی شسته و بسیاری تنها به فکر حفظ ارزش سرمایه خود هستند. در حال حاضر کارشناس‌های مستقل، میزان تورم سالیانه ایران را حدود ۱۲۲٪ تخمین ‌میزنند.

هر دوی این عوامل ورود به عرصه‌های اقتصادی مختلف را بیش از پیش دشوار کرده تا جایی که برای بخشی از جامعه فعالیت در بازارهایی غیر از ارز و بورس بسیار سخت (اگر نه غیر ممکن) شده است. در این میان تاثیر همه‌گیری کرونا نیز مزید بر علت شد.

این مسئله، حجم بسیار زیادی از سرمایه را در چند سال اخیر به سمت بازار بورس روانه کرد که نتیجه آن حباب فعلی بورس است. تا حدی که حتی برخی از شرکت‌های غوطه‌ور در بدهی نیز با رشد ارزش سهام همراه بوده‌اند.

تهران

با وجود جاری شدن سیل نقدنگی به سمت بورس تهران، همانطور که در مطلب «بورس تهران، منطبق شده با تورم» تشریح شد،‌ سرمایه‌گذاران در این بازار کماکان از میزان تورم جا مانده‌اند و ارزش سرمایه آنها حفظ نشده (به صورت جمعی).

بورس در حال حاضر برای حکومت اهمیت به سزای دارد، زیرا عملا تنها جایی است که می‌تواند آن را در حال پیشرفت نشان دهد ولی فراموش نکنیم که:

 بورس نماینده وضعیت اقتصادی نیست

رشد ارزش شاخص بورس لزوما نشانه مثبتی نیست و در مورد ما شاید نشانه کورسو امیدهای اقتصادی باقی مانده است.

https://rahavard365.com/index/1/chart

کاراکاس

رشد بازارهای سرمایه در شرایط اقتصادی نامناسب مختص ایران نیست. به طور نمونه زیمباوه و ونزوئلا هم با آن روبرو هستند.

بازار بورس کاراکاس – مربوط به سال ۲۰۱۸ https://tradingeconomics.com/venezuela/stock-market

این شباهت در تغییر جریان پول (money flow) و برخی از مشکلات زیربنایی مشترک، این سوال را به وجود می‌آورد که آیا ابر تورم از آنچه که فکر می‌کنیم به ما نزدیک‌تر است؟

محرک‌های اقتصادی، توده مردم را به سمت رفتار قابل پیشبینی و در نبود آنها، به سمت غیر قابل پیشبینی هدایت می‌کند.

فیلدهای null شونده در Protobuf، با کاربرد در golang

در Protobuf نسخه ۳ تمامی فیلدها اختیاری هستند، اما این اختیاری بودن همه جا به این معنی نیست که مقدار اون فیلد nil ست میشه. تو این مطلب می‌خوایم حالتی رو بررسی کنیم که قصد ما ارسال مقدار nil برای یک فیلده و راه حل‌هایی که برای این مسئله وجود داره رو ببینیم. برای مثال این پیام ساده رو در نظر بگیرید:

message Measurement {
string id = 1;
string name = 2;
int32 value = 3;
}

زمان ایجاد و مقداردهی یک نمونه از این پیام می‌تونیم یک یا چند فیلد اون رو مقداردهی نکنیم:

m := &pb.Measurement {
name: "heat-sensor-1"
}

مسئله مقدار صفر در golang

حالتی رو تصور کنید که سرویس A پیام بالا رو به سرویس B مخابره می‌کنه. مقدار value برای نمونه ارسال شده چند خواهد بود؟ از اونجایی که متغیرهای مقداردهی نشده در گولنگ به صورت مقدار صفر در نظر گرفته میشن مقدار value صفر خواهد بود. یعنی پیامی که سرویس B دریافت می‌کنه به صورت زیره:

*pb.Measurement {
id: "",
name: "heat-sensor-1",
value: 0,
}

اما اگر value برای سرویس A واقعا نامعلوم باشه و ما بخوایم به سرویس B این رو بگیم که value نا معلومه چه راه‌هایی داریم؟

بسته‌بندی (wrapping) فیلد

تو این روش فیلد value رو با کمک یک message دیگر بسته‌بندی می‌کنیم:

با تعریف یک message جدید

با تعریف یک message جدید برای فیلد value:

message Heat {
int32 v = 1;
}

message Measurement {
string id = 1;
string name = 2;
Heat value = 3;
}

این امکان به وجود میاد که بتونیم برای value مقدار nil ارسال کنیم:

m := &pb.Measurement {
,name: "heat-sensor-1"
,value: nil
}

و پیامی که سرویس B دریافت می‌کنه:

*pb.Measurement {
id: "",
name: "heat-sensor-1",
value: nil,
}

با استفاده از wrappers.proto

به جای تعریف message جدید می‌تونیم از messageهای از پیش تعریف شده گوگل استفاده کنیم:

import "google/protobuf/wrappers.proto";

message Measurement {
string id = 1;
string name = 2;
google.protobuf.Int32Value value = 3;
}

در موارد خاص از Oneof هم می‌توان برای این هدف استفاده کرد که از حوصله این مطلب خارجه.

استفاده از کلیدواژه optional در Protobuf

بعد از بحث‌هایی نسبتا مفصل، تیم پروتوباف راضی به اضافه کردن کلیدواژه optional شد. این ویژگی به صورت آزمایشی از نسخه ۳.۱۲ پروتوباف در دسترسه. برای استفاده از این ویژگی کافیه قبل از فیلد مورد نظرم optional رو اضافه کنیم:

message Measurement {
string id = 1;
string name = 2;
optional int32 value = 3;
}

برای کامپایل نیازه که فلگ experimental_allow_proto3_optional ست بشه:

$ protoc test.proto --go_out=plugins=grpc:./ --experimental_allow_proto3_optional

در این حالت در فایل go جنریت شده value از نوع *int خواهد بود (به جای int). حالا به راحتی می‌تونیم مقدار value رو nil ارسال کنیم:

m := &pb.Measurement {
,name: "heat-sensor-1"
,value: nil
}

در این روش نیازی نداریم که از یک نوع message دیگر که عملا کاربردی جز بسته‌بندی داده برای ما ندارد استفاده کنیم.

رفرنس‌ها:

  1. How To Implement Field Presence for Proto3
  2. Application note: Field presence

آخرین مطالب

چطور در golang یک سرویس gRPC را در تست‌ها mock کنیم

قسمت دوم از سری مطالب «چطور یک سیستم مایکروسرویس روی کوبرنیتز بسازیم».

کد کامل این پست رو می‌تونید اینجا ببینید.

gRPC

ما تقریبا در تمامی سرویس‌های پلتفرم از gRPC برای ارتباط بین سرویس‌ها استفاده می‌کنیم. gRPC یک فریم‌ورک بهینه توسعه RPC است که قبلا قابلیت‌هاش در شرکت‌های بزرگ اثبات شده است.

در کنار کارایی gRPC مهمترین دلیلی که ما gRPC رو تقریبا همه جا استفاده می‌کنیم پروتکل انتقال پیام این فریم ورک یعنی Protocol Buffers است. حتی در سرویس‌هایی که از gRPC استفاده نمی‌کنیم، پیام‌هایی که به سمت سرویس‌های داخلی ارسال می‌کنیم را توسط پروتکل‌بافر (یا به اختصار پروتوباف) منتقل می‌کنیم.

اینجا از یک مثال ساده برای نمایش نحوه mock کردن gRPC استفاده می‌کنم.

ایجاد یک سرویس gRPC

در این مطلب ابتدا با تعریف یک فایل پروتوباف اون رو کامپایل و سپس یک کلاینت برای این سرویس پیاده‌سازی و در نهایت در تست‌ها این کلاینت gRPC رو mock می‌کنیم.

تعریف فایل Protobuf

این سرویس از دو rpc تشکیل شده که یکی با دریافت پیام PING پیام PONG رو در جواب بر می‌گردونه و دومی با دریافت هر پیامی، همون پیام رو در جواب بر می‌گردونه:

syntax = "proto3";

package pb;

service Signal {
  rpc Ping (PingRequest) returns (PingResponse) {}
  rpc Echo (EchoRequest) returns (EchoResponse) {}
}

option go_package = ".;pb";

message PingRequest {
  string message = 1;
}

message PingResponse {
  string message = 1;
}

message EchoRequest {
  string message = 1;
}

message EchoResponse {
  string message = 1;
}

کدهای پروتوباف رو کامپایل می‌کنیم:

protoc -I/opt/include -I/usr/local/include -Ipb \
		--go_out=./pb --go_opt=paths=source_relative \
    	--go-grpc_out=./pb --go-grpc_opt=paths=source_relative \
    	pb/*.proto

پیاده‌سازی کلاینت

کلاینت رو به عنوان دو http.HandlerFunc پیاده سازی می‌کنم:

package signal

import (
	"context"
	"encoding/json"
	"grpc-mock-example/pb"
	"log"
	"net/http"
	"time"

	"google.golang.org/grpc/status"

	"google.golang.org/grpc"
)

var (
	conn   *grpc.ClientConn
	client pb.SignalClient
)

func New(serverAddr string) pb.SignalClient {
	var opts []grpc.DialOption
	opts = append(opts, grpc.WithInsecure())
	opts = append(opts, grpc.WithBlock())
	conn, err := grpc.Dial(serverAddr, opts...)
	if err != nil {
		log.Fatalf("fail to dial: %v", err)
	}
	client = pb.NewSignalClient(conn)

	return client
}

func Ping(w http.ResponseWriter, r *http.Request) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	message := r.URL.Path[len("/ping/"):]
	ping, err := client.Ping(ctx, &pb.PingRequest{Message: message})
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		e, ok := status.FromError(err)

		if ok {
			json.NewEncoder(w).Encode(e.Message())
			return
		}

		em := err.Error()
		log.Printf("%s", em)
		json.NewEncoder(w).Encode(em)
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	json.NewEncoder(w).Encode(ping)
}

func Echo(w http.ResponseWriter, r *http.Request) {
	ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
	defer cancel()

	message := r.URL.Path[len("/echo/"):]
	echo, err := client.Echo(ctx, &pb.EchoRequest{Message: message})
	if err != nil {
		w.WriteHeader(http.StatusInternalServerError)
		e, ok := status.FromError(err)

		if ok {
			json.NewEncoder(w).Encode(e.Message())
			return
		}

		json.NewEncoder(w).Encode(err.Error())
		return
	}

	w.Header().Set("Content-Type", "application/json; charset=UTF-8")
	json.NewEncoder(w).Encode(echo)
}

func Close() {
	conn.Close()
}

برای تولید mock ها از پکیج gomock استفاده می‌کنیم:

mockgen -source=pb/signal_grpc.pb.go -package=mocks SignalClient > ./mocks/signal_client_mock.go;

و بالاخره mock کردن gRPC در تست‌ها

package signal

import (
	"bytes"
	"encoding/json"
	"fmt"
	"grpc-mock-example/internal"
	"grpc-mock-example/mocks"
	"grpc-mock-example/pb"
	"net/http"
	"net/url"
	"reflect"
	"testing"

	"github.com/golang/mock/gomock"
	fuzz "github.com/google/gofuzz"
)

type pingRequest struct {
	message string
}

func (r *pingRequest) Matches(msg interface{}) bool {
	m, ok := msg.(*pb.PingRequest)
	if !ok {
		return false
	}

	return m.Message == r.message
}

func (r *pingRequest) String() string {
	return fmt.Sprintf("is %s %v", r.message, r.message)
}

type customResponseWriter struct {
	header     http.Header
	body       *bytes.Buffer
	statusCode int
}

func (c customResponseWriter) Header() http.Header {
	return c.header
}

func (c customResponseWriter) Write(body []byte) (int, error) {
	return c.body.Write(body)
}

func (c customResponseWriter) WriteHeader(statusCode int) {
	c.statusCode = statusCode
}

func TestPing(t *testing.T) {
	var msg string
	f := fuzz.New()
	ctrl := gomock.NewController(t)
	signalClient := mocks.NewMockSignalClient(ctrl)

	f.Fuzz(&msg)

	signalClient.
		EXPECT().
		Ping(gomock.Any(), &pingRequest{message: "Ping"}, gomock.Any()).
		Return(nil, internal.ErrInvalidPing).
		AnyTimes()

	signalClient.
		EXPECT().
		Ping(gomock.Any(), &pingRequest{message: "PING"}, gomock.Any()).
		Return(&pb.PingResponse{Message: "PONG"}, nil).
		AnyTimes()

	client = signalClient

	type args struct {
		w customResponseWriter
		r *http.Request
	}
	tests := []struct {
		name    string
		args    args
		want    string
		wantErr bool
	}{
		{
			name: "Ping",
			args: args{
				w: customResponseWriter{
					header: http.Header{},
					body:   &bytes.Buffer{},
				},
				r: &http.Request{
					Method: "GET",
					URL: &url.URL{
						Path: "/ping/Ping",
					},
				},
			},
			want: "\"invalid ping message\"\n",
		},
		{
			name: "PING",
			args: args{
				w: customResponseWriter{
					header: http.Header{},
					body:   &bytes.Buffer{},
				},
				r: &http.Request{
					Method: "GET",
					URL: &url.URL{
						Path: "/ping/PING",
					},
				},
			},
			want: "{\"message\":\"PONG\"}\n",
		},
	}
	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			Ping(tt.args.w, tt.args.r)

			got := tt.args.w.body.String()
			if !reflect.DeepEqual(tt.args.w.body.String(), tt.want) {
				t.Errorf("TestPing() = %v, want %v", got, tt.want)
			}
		})
	}
}

کد کامل این پست رو می‌تونید اینجا ببینید.

بورس تهران، منطبق شده با تورم

شاخص بازار بورس تهران در چند سال اخیر با شیب بیشتری در حال رشد بوده، از طرفی تورم هم روند افزایشی داشته است. در این مطلب میزان رشد شاخص کل بورس را با تطبیق تورم (inflation-adjusted value) بررسی می‌کنم.

محاسبه

برای محاسبه قیمت تطبیق‌داده شده با تورم نیاز به شاخص قیمت مصرف‌کننده (CPI) سبد آن کالا/دارایی داریم. به عنوان مثال برای یک پاکت شیر نیازمند مقادیر شاخص قیمت مصرف‌کننده کالاهای لبنی/خوراکی هستیم. مقادیر رسمی شاخص قیمت مصرف‌کننده را می‌توانیم از سایت آمار ایران دریافت کنیم.

با به دست آوردن مقادیر شاخص قیمت مصرف‌کننده (برای شاخص کل بورس از مقادیر شاخص کل در جدول شاخص قیمت مصرف‌کننده خانوارهای کشور به تفکیک ماه استفاده کردم)، کافی‌است قیمت دارایی مد نظر را بر آن تقسیم و در ۱۰۰ ضرب کنیم:

قیمت تطبیق‌داده شده با تورم = قیمت دارایی / مقدار شاخص مصرف‌کننده * ۱۰۰
inflation-adjusted-value = index-value / cpi-value * 100

ارزش شاخص بورس تهران (خط مشکی) و ارزش تطبیق‌ داده‌شده با تورم (خط آبی):

https://tsiia.avakh.com
sourse code: https://github.com/EricMasonFa/tsi-inflation-adjusted

این چارت چه معنایی دارد؟

تصور کنید امروز یکی از روزهای سال ۹۵ است. این سال را به عنوان سال مبنا و CPI۱ را برای کالاهای لبنی ۱۰۰ در نظر می‌گیریم. در این مثال قیمت یک پاکت شیر را در سال ۹۵ پنج هزار تومان در نظر می‌گیریم. فرض می‌کنیم CPI سبد کالاهای لبنی در سال‌های ۹۶ و ۹۷ به ترتیب ۱۱۰ و ۱۲۰ است و قیمت پاکت شیر در این دو سال ۵۵۰۰ و ۵۷۰۰ است. در نتیجه قیمت منطبق شده با تورم برای این دو سال ۵۵۰۰ و ۴۷۵۰ خواهد بود.

در سال ۹۶ قیمت شیر منطبق با تورم رشد کرده ولی در سال ۹۷ علارغم تورم (تورم کاهش نداشته)، قیمت شیر رشد زیادی نداشته و همانطور که در تصویر هم قابل مشاهده است، شیر سال ۹۷ کالایی ارزان محسوب می‌شود.

با توضیحات بالا، می‌بینیم که گرچه شاخص بورس تهران افزایش زیادی داشته، ولی سایه تورم بر آن سنگینی می‌کند. قیمت شاخص بورس تهران زمانی که با تورم تطبیق داده می‌شود کماکال ارزان محسوب می‌شود.

این مطلب به این معنا نیست که لزوما شاخص کل بورس تهران به رشد ادامه خواهد داد. باید دید که آیا جریان نقدینگی در ماه‌های پیش رو از بورس به سمت دیگری سرازیر خواهد شد یا خیر.


1 CPI = cost of basket / cost of basket in the base year * 100

بررسی وضعیت اقتصادی و دورنمای پس از کرونا

پس از شوک اقتصادی کوروناویروس به بازارها، علیرغم اینکه شاخص‌های اقتصادی وضعیت مطلوبی از خود نشان ندادند شاهد رشد بازارها بودیم. در این نوشته به بررسی اجمالی وضعیت اقتصادی و دورنمای پس از کرونا می‌پردازم.

مطالب زیر مشاهدات، گردآوری و نظرات شخصی با دید اقتصادی درازمدت است
و پیشنهاد خرید یا فروش نیست.

کروناویروس ۲۰۱۹

زمانی که کشورها پس از انتشار کروناویروس ۲۰۱۹ از چین مجبور به بستن مرزهای خود شدند و کسب و کارهای زیادی از حرکت ایستادند و با مشکل مواجه شدند، چرخه اقتصاد در عرصه جهانی با اختلال مواجه شد و موجی از نگرانی را به بازارها منتقل کرد:

سقوط ۳۵٪ شاخص S&P500 در ۵ هفته

اسم این مرحله را در این مطلب شوک می‌گذارم.

اما کرونا تنها عامل سقوط بازارها نبود. به عنوان مثال جف بزوس مدیر و مالک شرکت آمازون و مدیران چندی دیگر از شرکت‌ها قبل از گسترش بیماری بیش از ۹ میلیارد دلار از سهام خود را فروخته بودند. همچنین چند ماه قبل، شاخص نسبتِ سود ۱۰ ساله به ۱ ساله خزانه‌داری امریکا به منطقه هشدار رکود نزدیک شده بود:

The 10 year Treasury yield curve

آنچه گذشت

تعداد وقایع مرتبط بسیار زیاد و از حوصله خارج است. در اینجا چند مورد را مرور می‌کنیم.

شروع جنگ تجاری امریکا و چین

یکی از مهم‌ترین وقایع اقتصادی چند سال اخیر وضع تعرفه گمرکی دوطرفه بین امریکا و چین در سال ۲۰۱۸ بود که باعث افزایش تنش‌ها بین این دو کشور شد.

همه‌گیری کروناویروس ۲۰۱۹ و تاثیرات آن

گرچه این ویروس نرخ کشتار بالایی نداشت اما به دلیل سرعت همه‌گیری آن، باعث نگرانی کشورها در مواجهه با تعداد بالای مبتلایان شد. در این ویدئو شتاب میزان مرگ و میر توسط این ویروس در مقایسه با عوامل دیگر را مشاهده می‌کنیم:

با همه‌گیری ویروس و بسته‌شدن مرز برخی کشورها و قرنطینه گسترده، چرخه عرضه و تقاضا با مشکل مواجه شد. این تغییر تقریبا اثرات مشابهی در کشورهای درگیر بیماری داشت. به عنوان نمونه سقوط تولید ناخالص داخلی (GDP) در چین:

بخشی از تولید چین از سر گرفته شده، اما آیا تقاضا هم مانند گذشته است؟

افزایش نرخ بیکاری [ثبت شده به هزارنفر] در امریکا:

وضعیت فعلی

یکی از اتفاق‌های عجیب بعد از مرحله «شوک» این بود که دقیقا روزی که گزارش رشد سرسام‌آور بیکاری در امریکا منتشر شد شاخص‌های بازار امریکا رشد کردند که نشان از این می‌داد که بازار کف قیمت را در مرحله شوک تجربه کرده و وارد مرحله «امید» شده (مرحله‌ای که کماکان در آن قرار داریم).

اما تاریخ نشان داده که اتفاق‌هایی در این سطح تاثیرگذار بعد از مرحله امید یک مرحله هراس/ورشکستگی را تجربه خواهند کرد.

اینکه در مرحله امید بازار خلاف شاخص‌های اقتصادی حرکت می‌کند به عواملی مانند جریان پول (money flow) بر می‌گردد تا عادی شدن عوامل اقتصادی (به طور مشابه تاثیر جریان پول بر بورس ایران را می‌توان به وضوح مشاهده کرد).

در نظر داشته باشید که موج دوم شیوع کرونا چند ماه آینده آغاز می‌شود و فراموش نکنیم که کرونا تنها مسئله اقتصاد امریکا نبوده است:

  • بزرگ‌ترین موج بازنشستگی و پرداخت حقوق بازنشستگی
  • حباب قرض‌های خارجی از امریکا (استقراض کشورهای دیگر از امریکا حدود ۶.۷ تریلیون دلار – حباب دلار)
  • بزرگ‌ترین حباب سهام
  • بدهی دولت تقریبا معادل ۱۰۰٪ از تولید ناخالص (عکس زیر)
  • و ….

این حجم از استقراض کشورهای خارجی در شرایطی وجود دارد که سرعت گردش پول در چند سال اخیر به شدت پایین آمده و با اختلال در عرضه و تقاضا (به دلایل همه‌گیری ویروس)، ادامه جنگ اقتصادی امریکا-چین (سخنرانی اخیر ضد چین ترامپ) و شرایط نامطلوب برخی از کشورهای اروپایی این شرایط، وضعیت برای کشورهای اروپایی سخت‌ترر هم خواهد شد.

انتظار می‌رود دلار قدرتمند‌تر و قیمت دلار رشد بی‌سابقه‌ای را تجربه کند. جزئیات رشد دلار در آینده را می‌توانید در این ویدئو ببینید:

در نهایت کشورها به شیوه‌های جدید روی می‌آورند (حل مسئله دلار توسط امریکا، جایگزینی استاندارد دلار، تشکیل سبد ارزی، …) که افت قیمت دلار را به همراه خواهد داشت که در آن شرایط، شاید استاندارد دلار معنای فعلی خودش را از دست بدهد.

اما راهکاری که ترامپ برای جلوگیری از رشد قیمت دلار پیشنهاد داده منفی کردن سود بانکی است. در صورت اجرا، این مشتری‌ها هستند که در ازای سپرده‌گذاری در بانک به بانک‌ها پول پرداخت می‌کنند.

در تئوری، با این کار به صورت تعمدی دلار تضعیف می‌شود و سرعت گردش پول کمی افزایش پیدا می‌کند، اما در عمل به این سادگی هم نیست.

برخی از کشورهای اروپایی هم جدا از مشکلات همه‌گیری ویروس، مسائل و مشکلات اقتصادی خود را دارند.

شاخص IBEX 35 (شاخص ۳۵ شرکت با بیشترین نقدشوندگی) اسپانیا:

بانک Banco Sabadell اسپانیا:

بانک Bankia اسپانیا:

شاخص PMI (بخش تولید و خدمات) برای اروپا هم بهبود آنچنانی‌ای را نشان نمی‌دهد:

آینده پیش رو

طلا

در سایه تلاطم‌های بازار و ارزها، انتظار می‌رود قیمت طلا افزایش یابد. شاید ۳ تا ۵ برابر در ۵ سال آینده.

بیتکوین

طلا از دارایی‌های ما محافظت می‌کند، بیت‌کوین گزینه سیستم آینده است. بیت‌کوین صرفا یک روش مبادله یا ذخیره ارزش نیست، یک سیستم اعتماد، تایید، امن، مالی و حسابداری برای ارزش دیجیتال است که هرگز خارج از الگوریتم رمزنگاری تولید نمی‌شود.

این دارایی در حال حاضر بهترین عملکرد را در تمام تاریخ ثبت شده دارد و تنها ۱۱ سال از عمر آن می‌گذرد. از دل بحران مالی و دقیقا برای روزهای پیش رو متولد شد.

انتظار می‌رود بیت‌کوین رشد ۱۰برابری در ۵ سال آینده را تجربه کند.

به نظرم این بزرگ‌ترین معامله عمر ماست. دقیقا زمانی که بیش‌تر از هر وقت دیگر به آن نیاز داریم.

ایران

متاسفانه مسائلی مانند حقوق بازنشستگان، بانک‌های ورشکسته، افزایش قیمت جهانی دلار، کمبود ذخایر ارزی و دلار مبادلاتی، قیمت نفت، دشواری فروش نفت، تورم، مشکلات تولید، حجم صادرات و محدودیت‌های آن، دورنمای سختی را برای ایران ترسیم می‌کنند.

مسئله مجموع نادرست در پایگاه‌داده

دوستم امروز تماس گرفت و گفت که تو یکی از جدول‌های دیتابیسش یک مشکل ایجاد شده. دنبال راهی بود که بتونه جلوی تکرار این مشکل رو بگیره. در این پست این مشکل که به اون مسئله مجموع نادرست گفته میشه و علت ایجادش رو توضیح میدم.

ساختار دیتابیس


دیتابیس در کنار جدول کاربرها (users) لیستی از تراکنش‌های مالی اون‌ها (transactions) رو نگه‌داری میکنه و در جدول سوم لیست پکیج‌های خریداری شده (user_package) کاربرها رو (جدول پکیج‌ها در این مسئله موضوعیتی ندارد).

کاربر تنها از موجودی سپرده‌ای که پیش سایت داره امکان خرید داره. هر بار که روی دکمه خرید یک پکیج کلیک می‌کنه مراحل زیر انجام میشه:

۱- موجودی حساب کاربر از دیتابیس کوئری گرفته میشه (که از SUM مقادیر تراکنش روی جدول transaction به دست میاد)

۲- در صورتی که کاربر موجودی داشته باشه پکیج مورد نظر به کاربر نسبت داده میشه (در جدول user_package)

۳- موجودی از حساب کاربر کم میشه (یک سطر جدید در جدول transactions)

مشکل

در اتفاقی نادر برای یک کاربر که سپرده محدودی روی سایت داشت ۲ مورد خرید از ۱ پکیج ثبت شده بود و برای هر دو مورد مبلغ پکیج‌ از کاربر کسر و موجودی کاربر منفی شده بود. این اتفاق در صورتی پیش اومده بود که هر ۳ مرحله بالا در یک تراکنش (database transaction) انجام میشد.

اما چطور چنین چیزی اتفاق میوفته؟ این مسئله ریشه در همزمانی (concurrency) برنامه و پایگاه‌داده داره. زمانی که [به هر دلیلی] دو درخواست خرید از سمت کاربر به صورت همزمان در سمت دیتابیس اجرا می‌شود امکان وقوع چنین مسئله‌ای وجود دارد.

البته سطح ایزوله‌سازی پایگاه‌داده هم در این زمینه موثره. تصویر چگونگی ایجاد این مسئله رو با توجه به مراحل ذکر شده بالا نشون میده:

زمانی که تراکنش ۲ در حال محاسبه موجودی کاربر است، تراکنش ۱ هنوز موجودی کاربر را کم نکرده. حتی در صورتی که بالانس کاربر توسط تراکنش ۱ به روز شده باشد اما تراکنش اعمال (commit) نشده باشه باز هم نتیجه موجودی در تراکنش ۲ اشتباه خواهد بود.

به این مسئله، مشکل مجموع نادرست (Incorrect summary problem) یا مسئله تحلیل متناقض (Inconsistent analysis) گفته میشه.

در پست بعدی راه‌حل‌های این مسئله رو تشریح می‌کنم.

چطور یک سیستم مایکروسرویس روی کوبرنیتز بسازیم – ۱

در پایان آخرین پستم روی ویرگول با عنوان «از پیشنهاد چند فیلم و سریال تا جلسه امروز» نوشتم که قراره مدتی رو در یک تیم جدید فعالیت کنم. این تیم چندتا محصول لگسی داشت که قرار بود این محصولات با هم اینتگریت بشن و به صورت واحد فعالیت کنن. برای این کار تصمیم گرفتیم محصولات رو به سمت مایکروسرویس ببریم و در نهایت روی کوبرنیتز راه اندازی کنیم.

قرار بود با ادغام شدن محصولات، سیستم یک پارچه‌ای رو داشته باشیم که کاربر با یک بار ورود به همه محصولات دسترسی داشته باشه. این محصولات قبلا به صورت جداگانه تست شده بودن و پتانسیلشون رو نشون داده بودن و تیم مارکتینگ تصمیم گرفته بود اون‌ها رو باهم ادغام کنه.

تولید یک پلتفرم یا تغییر محصولات قدیمی

در روزهای اول با مد نظر قرار دادن هدفی نهایی سیستم، محصولات موجود رو بررسی کردیم که ببینیم چه راهکارهایی برای اینتگریت کردنشون برامون وجود داره. یکی از فاکتورهای مهم زمان بود.

طولانی شدن زمان توسعه هزینه تولید رو بالا می‌برد و بودجه توسعه محدود بود. در نهایت به این نتیجه رسیدیم که تغییر محصولات با تولید یک پلتفرم از نظر زمانی تفاوت خاصی نداره.

اجزای اصلی پلتفرم ما شامل سیستم حسابداری، احراز هویت و ارسال اعلان (ایمیل و …) میشد. البته برای پلتفرم نهایی شامل مایکروسرویس های دیگه‌ای هم میشد ولی برای مایل‌استون اول به اجزای اصلی بسنده کردیم.

بستر مقیاس‌پذیری

فاکتور مهم بعدی مقیاس‌پذیری سیستم بود. با توجه اینکه محصولات قبلا پتانسیلشون رو نشون داده بودن نیاز بود که بتونیم در زمان کوتاهی محصولات رو با رشد تعداد کاربرها منطبق کنیم. تیم ما تجربه خوبی رو با داکر داشت برای همین گزینه‌هایی مثل داکر سوارم هم روی میز بود، اما تخمین‌های تیم مارکتینگ، تعداد محصولات و نیاز به مقیاس‌پذیری بالا ما رو به کوبرنیتز رسوند.

در پست‌های بعدی از تکنولوژی‌های مورد استفاده، جزئیات فنی هر کدوم از مایکروسرویس‌ها و چالش‌هایی که باهاشون روبرو بودیم بیشتر می‌نویسم.

تحلیل بازار بیت‌کوین ۲۸ اسفند ۱۳۹۸

با تثبیت قیمت زیر ۷۲۰۰ و عبور از ۶۴۰۰ ساختار مارکت شکست و قیمت به سطح حمایتی هفتگی سقوط کرد.

موجی که ساختاری شبیه موج ۱ (ایمپالسیو) داشت عملا موج B اصلاحی بود و با شکست کف قبلی به طرف تکمیل موج C می‌ریم و بعد از اون باید ببینیم موج جدید به کدوم سمت شروع میشه. با شوکی که بازار جهانی وارد شده، حتی اگه موج بعدی بخواد صعودی باشه بعید می‌بینم که موج C سریع تموم بشه و تا چند ماه آینده با افت احتمالی حجم معاملات روبرو خواهیم بود.

سلب مسئولیت: بازارهای مالی پر ریسک هستند. این مطلب پیشنهاد خرید و فروش نیست و صرفا نظرات شخصی من هستند.

تحلیل بازار طلا (۱۷ اسفند ۱۳۹۸)

با توجه به اینکه به نظرم طلا در منطقه خاصی قرار داره یک تحلیل از قیمت طلا می‌ذارم. طلا از آگوست ۲۰۱۸ حرکت صعودی جدیدی رو شروع کرد و بعد از گذشت چند ماه به نظر می‌رسه به انتهای حرکت صعودی خودش نزدیک شده.

در حال حاضر الگوی مشابه دو قله روی چارت روزانه دیده میشه. این احتمال وجود داره قبل شروع موج دوم یک حرکت ۲۰۰ دلاری رو هم تجربه کنیم ولی احتمالش رو ضعیف می‌بینم، با این حال هنوز سیگنال ریزش دیده نشده.

پس از پایان این موج، یک موج اصلاحی نرمال می‌تونه حتی تا سطوح ۵۰٪ یا ۳۸٪ اصلاح داشته باشه.

روی چارت هفتگی هنوز به شکل واضح مشخص نیست که موج فعلی موج ۱ باشه اما شواهد با احتمال بالا این رو تایید میکه. با این احتمال می‌تونیم انتظار یک اصلاح نرمال رو داشته باشیم و بعد از اون به سمت موج ۳ (که عبور از ۱۹۰۰ دلار رو منجر میشه) بریم.

فعلا برای هفته‌های آتی می‌تونیم شروع موج اصلاحی رو در نظر داشته باشیم تا بازار اطلاعات بیشتری به ما بده.

سلب مسئولیت: بازارهای مالی پر ریسک هستند. این مطلب پیشنهاد خرید و فروش نیست و صرفا نظرات شخصی من هستند.

خروج از نسخه موبایل