[{"data":1,"prerenderedAt":4455},["ShallowReactive",2],{"i-lucide:chevron-down":3,"i-lucide:search":8,"i-lucide:sun":10,"i-lucide:moon":12,"i-lucide:arrow-right":14,"i-lucide:menu":16,"i-lucide:mail":18,"i-simple-icons:x":20,"i-simple-icons:linkedin":22,"i-simple-icons:dribbble":25,"i-simple-icons:github":27,"i-lucide:arrow-up-right":29,"blog-posts-bn":31,"i-lucide:sparkle":4433,"i-lucide:notebook-pen":4435,"i-lucide:languages":4437,"i-lucide:chevron-left":4439,"i-lucide:chevron-right":4441,"i-lucide:component":4443,"i-lucide:type":4445,"i-lucide:globe-2":4447,"i-lucide:briefcase":4449,"i-lucide:server":4451,"i-lucide:trending-up":4453},{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":7},0,24,false,"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m6 9l6 6l6-6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":9},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"m21 21l-4.34-4.34\"\u002F>\u003Ccircle cx=\"11\" cy=\"11\" r=\"8\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":11},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Ccircle cx=\"12\" cy=\"12\" r=\"4\"\u002F>\u003Cpath d=\"M12 2v2m0 16v2M4.93 4.93l1.41 1.41m11.32 11.32l1.41 1.41M2 12h2m16 0h2M6.34 17.66l-1.41 1.41M19.07 4.93l-1.41 1.41\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":13},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":15},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M5 12h14m-7-7l7 7l-7 7\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":17},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M4 5h16M4 12h16M4 19h16\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":19},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"m22 7l-8.991 5.727a2 2 0 0 1-2.009 0L2 7\"\u002F>\u003Crect width=\"20\" height=\"16\" x=\"2\" y=\"4\" rx=\"2\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":21},"\u003Cpath fill=\"currentColor\" d=\"M14.234 10.162L22.977 0h-2.072l-7.591 8.824L7.251 0H.258l9.168 13.343L.258 24H2.33l8.016-9.318L16.749 24h6.993zm-2.837 3.299l-.929-1.329L3.076 1.56h3.182l5.965 8.532l.929 1.329l7.754 11.09h-3.182z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":23,"hidden":24},"\u003Cpath fill=\"currentColor\" d=\"M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037c-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85c3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.06 2.06 0 0 1-2.063-2.065a2.064 2.064 0 1 1 2.063 2.065m1.782 13.019H3.555V9h3.564zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0z\"\u002F>",true,{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":26},"\u003Cpath fill=\"currentColor\" d=\"M12 24C5.385 24 0 18.615 0 12S5.385 0 12 0s12 5.385 12 12s-5.385 12-12 12m10.12-10.358c-.35-.11-3.17-.953-6.384-.438c1.34 3.684 1.887 6.684 1.992 7.308a10.28 10.28 0 0 0 4.395-6.87zm-6.115 7.808c-.153-.9-.75-4.032-2.19-7.77l-.066.02c-5.79 2.015-7.86 6.025-8.04 6.4a10.16 10.16 0 0 0 6.29 2.166c1.42 0 2.77-.29 4-.814zm-11.62-2.58c.232-.4 3.045-5.055 8.332-6.765q.202-.067.405-.12q-.392-.879-.832-1.74C7.17 11.775 2.206 11.71 1.756 11.7l-.004.312c0 2.633.998 5.037 2.634 6.855zm-2.42-8.955c.46.008 4.683.026 9.477-1.248a66 66 0 0 0-3.8-5.928a10.28 10.28 0 0 0-5.676 7.17zM9.6 2.052c.282.38 2.145 2.914 3.822 6c3.645-1.365 5.19-3.44 5.373-3.702A10.2 10.2 0 0 0 12 1.764c-.825 0-1.63.1-2.4.285zm10.335 3.483c-.218.29-1.935 2.493-5.724 4.04c.24.49.47.985.68 1.486c.08.18.15.36.22.53c3.41-.43 6.8.26 7.14.33c-.02-2.42-.88-4.64-2.31-6.38z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":28},"\u003Cpath fill=\"currentColor\" d=\"M12 .297c-6.63 0-12 5.373-12 12c0 5.303 3.438 9.8 8.205 11.385c.6.113.82-.258.82-.577c0-.285-.01-1.04-.015-2.04c-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729c1.205.084 1.838 1.236 1.838 1.236c1.07 1.835 2.809 1.305 3.495.998c.108-.776.417-1.305.76-1.605c-2.665-.3-5.466-1.332-5.466-5.93c0-1.31.465-2.38 1.235-3.22c-.135-.303-.54-1.523.105-3.176c0 0 1.005-.322 3.3 1.23c.96-.267 1.98-.399 3-.405c1.02.006 2.04.138 3 .405c2.28-1.552 3.285-1.23 3.285-1.23c.645 1.653.24 2.873.12 3.176c.765.84 1.23 1.91 1.23 3.22c0 4.61-2.805 5.625-5.475 5.92c.42.36.81 1.096.81 2.22c0 1.606-.015 2.896-.015 3.286c0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":30},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M7 7h10v10M7 17L17 7\"\u002F>",[32,206,322,453,822,1129,1546,1874,2845,3533,4264],{"id":33,"title":34,"author":35,"body":38,"category":189,"cover":190,"coverAlt":190,"date":191,"description":192,"draft":6,"extension":193,"featured":6,"lang":194,"meta":195,"navigation":24,"path":196,"readingTime":197,"seo":198,"seoTitle":199,"stem":200,"tags":201,"__hash__":205},"blog\u002Fblog\u002Fbn\u002Ftrust-social-proof-conversion.md","মানুষ কেন অচেনা কারো কাছ থেকে কিনতে দ্বিধা করে — Trust Signal যেভাবে সেল বাড়ায়",{"name":36,"role":37},"সাদিয়া ইসলাম","গ্রোথ ও মার্কেটিং লিড",{"type":39,"value":40,"toc":180},"minimark",[41,45,53,58,65,71,75,104,107,113,117,124,130,134,141,152,156,163,166],[42,43,44],"p",{},"একটা নতুন ফ্রিল্যান্সার, ভালো কাজ জানেন, পোর্টফোলিওও ভালো — কিন্তু ক্লায়েন্ট পাচ্ছেন না। অথচ পাশের আরেকজন, কাজের মান প্রায় কাছাকাছি, কিন্তু প্রোফাইলে \"৫০+ প্রজেক্ট সম্পন্ন, ৪.৯ রেটিং\" লেখা — তার কাছেই ক্লায়েন্ট বেশি যাচ্ছে।",[42,46,47,48,52],{},"এটা অন্যায্য মনে হতে পারে, কিন্তু মানুষের সিদ্ধান্ত নেওয়ার প্রক্রিয়াটাই এভাবে কাজ করে। কোনো কিছু সম্পর্কে নিজে যাচাই করার সময় বা তথ্য না থাকলে, মানুষ দেখে ",[49,50,51],"strong",{},"অন্যরা কী করছে"," — আর সেটাকেই নিরাপদ সিদ্ধান্ত হিসেবে ধরে নেয়।",[54,55,57],"h2",{"id":56},"social-proof-একা-সিদ্ধান্ত-নিতে-না-চাওয়ার-প্রবণতা","Social Proof — একা সিদ্ধান্ত নিতে না চাওয়ার প্রবণতা",[42,59,60,61,64],{},"মনোবিজ্ঞানী Robert Cialdini তার বিখ্যাত \"Influence\" বইতে এই প্যাটার্নটাকে বলেছেন ",[49,62,63],{},"social proof"," — অনিশ্চয়তার মুহূর্তে মানুষ অন্যদের আচরণ দেখে নিজের সিদ্ধান্ত ঠিক করে। একটা রেস্টুরেন্টের সামনে লাইন দেখলে সেটাকে \"ভালো রেস্টুরেন্ট\" ধরে নেওয়া, বা একটা প্রোডাক্টের হাজার হাজার রিভিউ দেখে ভরসা পাওয়া — দুটোই একই প্রবৃত্তি থেকে আসে।",[66,67,68],"note",{},[42,69,70],{},"Social proof সবচেয়ে বেশি কাজ করে যখন কাস্টমার নিজে নিশ্চিত না — নতুন প্রোডাক্ট, নতুন সার্ভিস প্রোভাইডার, বা দামি একটা সিদ্ধান্ত। যেখানে মানুষ ইতিমধ্যে নিশ্চিত (যেমন নিয়মিত কেনা কোনো ব্র্যান্ড), সেখানে রিভিউ-সংখ্যার প্রভাব তুলনামূলক কম।",[54,72,74],{"id":73},"নির্দিষ্ট-সংখ্যা-ভাসা-ভাসা-দাবির-চেয়ে-বেশি-কার্যকর","নির্দিষ্ট সংখ্যা, ভাসা ভাসা দাবির চেয়ে বেশি কার্যকর",[76,77,82,96],"compare",{"after":78,"before":79,"note":80,"split":81},"নির্দিষ্ট, যাচাইযোগ্য তথ্য","ভাসা ভাসা দাবি","ডান পাশের সংস্করণ নির্দিষ্ট সংখ্যা আর নাম দিয়ে যাচাইযোগ্যতা তৈরি করে — মিথ্যা বলার সুযোগ কম মনে হয়, তাই বিশ্বাসযোগ্যতাও বেশি।","একই ফ্রিল্যান্স প্রোফাইল",[83,84,86],"template",{"v-slot:before":85},"",[87,88,93],"pre",{"className":89,"code":91,"language":92},[90],"language-text","অনেক ক্লায়েন্টের সাথে কাজ\nকরেছি, সবাই খুশি হয়েছেন।\nসেরা সার্ভিস দেওয়ার\nচেষ্টা করি সবসময়।\n","text",[94,95,91],"code",{"__ignoreMap":85},[83,97,98],{"v-slot:after":85},[87,99,102],{"className":100,"code":101,"language":92},[90],"৩৭টা প্রজেক্ট, ৪.৯\u002F৫ রেটিং\n(১১ জন ক্লায়েন্ট রিভিউ)\n\"Grameenphone-এর ড্যাশবোর্ড\nরিডিজাইন — ৩ সপ্তাহে ডেলিভারি\"\n",[94,103,101],{"__ignoreMap":85},[42,105,106],{},"ভাসা ভাসা দাবি (\"সবাই খুশি\") আসলে মিথ্যা বলার মতোই সহজ, তাই মস্তিষ্ক সেটাকে বিশেষ গুরুত্ব দেয় না। কিন্তু নির্দিষ্ট সংখ্যা আর নাম — যাচাই করা যায় এমন কিছু — সহজে বানিয়ে বলা যায় না বলেই বেশি বিশ্বাসযোগ্য মনে হয়।",[108,109,110],"warning",{},[42,111,112],{},"জাল রিভিউ বা বানানো সংখ্যা ব্যবহার করাটা শুধু নৈতিকভাবে ভুল না — বাস্তবে ধরা পড়ে গেলে (আর প্রায়ই পড়ে) সেটা নিরপেক্ষভাবে বিশ্বাসহীনতার চেয়েও বেশি ক্ষতি করে, কারণ কাস্টমার তখন প্রতারিত বোধ করে। যা আছে তাই দেখান — অল্প কিছু আসল রিভিউ, বানানো অনেক রিভিউয়ের চেয়ে বেশি কাজ করে।",[54,114,116],{"id":115},"reciprocity-আগে-দিলে-পরে-পাওয়া-যায়","Reciprocity — আগে দিলে, পরে পাওয়া যায়",[42,118,119,120,123],{},"Cialdini-র আরেকটা নীতি — ",[49,121,122],{},"reciprocity","। কেউ আগে থেকে বিনামূল্যে কিছু মূল্যবান পেলে, বিনিময়ে কিছু ফেরত দেওয়ার একটা স্বাভাবিক তাগিদ অনুভব করে। এই কারণেই ফ্রি টেমপ্লেট, ফ্রি অডিট, ফ্রি কনসালটেশন — এসব দীর্ঘমেয়াদে সেল বাড়ায়: প্রথমেই বিক্রির চেষ্টা না করে, আগে সাহায্য করলে বিশ্বাস তৈরি হয়, আর সেই বিশ্বাস থেকেই লেনদেন শুরু হয়।",[125,126,127],"tip",{},[42,128,129],{},"Reciprocity কাজ করার জন্য যা দিচ্ছেন সেটা আসলেই দরকারি হতে হবে — একটা সাধারণ ব্লগ পোস্টের চেয়ে, কাস্টমারের নির্দিষ্ট সমস্যার একটা ছোট, ব্যক্তিগতকৃত সমাধান (যেমন তার ওয়েবসাইটের একটা কুইক পারফরম্যান্স অডিট) অনেক বেশি প্রভাব ফেলে — কারণ সেটা স্পষ্টভাবে বোঝায় যে তার জন্যই সময় দেওয়া হয়েছে।",[54,131,133],{"id":132},"authority-কে-বলছে-সেটাও-গুরুত্বপূর্ণ","Authority — কে বলছে সেটাও গুরুত্বপূর্ণ",[42,135,136,137,140],{},"একই তথ্য একজন নবীন ফ্রিল্যান্সার বললে এক রকম শোনায়, আর কেউ যদি জানে যে সেই একই মানুষ একটা পরিচিত কোম্পানির সাথে কাজ করেছেন, তাহলে সেটা অন্যরকম ওজন পায়। এটাকে বলে ",[49,138,139],{},"authority"," — সার্টিফিকেট, পরিচিত ক্লায়েন্টের নাম, বা কোনো প্রতিষ্ঠিত প্ল্যাটফর্মে ফিচার হওয়া — এসব প্রকৃত দক্ষতা না বাড়ালেও, সেই দক্ষতার প্রতি বিশ্বাসকে বাড়িয়ে দেয়।",[142,143],"quiz",{":answer":144,":options":145,"checkLabel":146,"correctLabel":147,"explanation":148,"incorrectLabel":149,"question":150,"resetLabel":151},"2","[\"দাম খুব বেশি দেখাচ্ছে\",\"সার্ভিস লিস্ট খুব ছোট\",\"কোনো social proof বা trust signal নেই, তাই ভিজিটর ঝুঁকি নিতে দ্বিধা করবে\",\"ওয়েবসাইটের ডিজাইন পুরনো\"]","উত্তর মিলিয়ে দেখি","ঠিক আছে","দাম বা ডিজাইন সমস্যা হতে পারে, কিন্তু মূল বাধা হলো বিশ্বাসের অভাব। একটা নতুন বা অচেনা এজেন্সির কাছ থেকে কেনার সিদ্ধান্তে ঝুঁকি বেশি মনে হয় — কেউ যাচাই করতে পারছে না এটা আসলেই কাজ করে কি না। ক্লায়েন্ট লোগো, নির্দিষ্ট সংখ্যাসহ রিভিউ, বা আসল কেস স্টাডি এই ঝুঁকির অনুভূতি কমিয়ে দেয়, কারণ সেগুলো দেখায় যে অন্যরা আগে ঝুঁকি নিয়ে সন্তুষ্ট হয়েছে।","হয়নি","একটা নতুন ওয়েব এজেন্সির ওয়েবসাইটে কোনো ক্লায়েন্ট লোগো, রিভিউ বা কেস স্টাডি নেই — শুধু সার্ভিস লিস্ট আর দাম আছে। সবচেয়ে বড় সমস্যা কী?","আবার চেষ্টা করি",[54,153,155],{"id":154},"trust-signal-অডিট-করার-চেকলিস্ট","Trust signal অডিট করার চেকলিস্ট",[157,158],"checklist",{":items":159,"doneLabel":160,"resetLabel":161,"title":162},"[{\"label\":\"রিভিউ বা টেস্টিমোনিয়ালে নির্দিষ্ট নাম, সংখ্যা বা ফলাফল আছে কি?\",\"detail\":\"\\\"ভালো লেগেছে\\\"-র চেয়ে \\\"৩ সপ্তাহে ডেলিভারি, ৪০% দ্রুত লোড টাইম\\\" বেশি বিশ্বাসযোগ্য।\"},{\"label\":\"পরিচিত ক্লায়েন্ট বা প্রতিষ্ঠানের নাম দেখানো যাচ্ছে কি (অনুমতি নিয়ে)?\",\"detail\":\"একটা পরিচিত নাম, দশটা অচেনা নামের চেয়ে বেশি কাজ করতে পারে।\"},{\"label\":\"কোনো ফ্রি মূল্যবান কিছু আগে থেকে দেওয়া হচ্ছে কি (reciprocity)?\",\"detail\":\"একটা ছোট, ব্যক্তিগতকৃত সাহায্য — সাধারণ কনটেন্টের চেয়ে বেশি বিশ্বাস তৈরি করে।\"},{\"label\":\"কোনো দাবিই কি যাচাই-অযোগ্য বা অতিরঞ্জিত শোনাচ্ছে?\",\"detail\":\"অতিরঞ্জিত দাবি সন্দেহ তৈরি করে, বিশ্বাস না।\"},{\"label\":\"রিভিউ বা প্রমাণ কি আসল, নাকি বানানো?\",\"detail\":\"জাল প্রমাণ ধরা পড়লে যেকোনো pricing বা marketing কৌশলের চেয়ে বেশি ক্ষতি করে।\"}]","শেষ","রিসেট","ওয়েবসাইট বা প্রোফাইলে বিশ্বাসযোগ্যতা যাচাই করার তালিকা",[42,164,165],{},"সেল বাড়ানোর অনেকটাই আসলে প্রোডাক্ট বদলানো না — কাস্টমারের চোখে ঝুঁকিটা কমিয়ে দেওয়া। আর সেই ঝুঁকি কমে যখন সে দেখে, তার আগে অন্যরাও একই সিদ্ধান্ত নিয়ে ঠকেনি।",[42,167,168,169,174,175,179],{},"বিশ্বাস তৈরি হয়ে গেলে পরের প্রশ্নটা আসে দাম নিয়ে — ",[170,171,173],"a",{"href":172},"\u002Fblog\u002Fbn\u002Fprice-anchoring-decoy-effect","সেটা কীভাবে উপস্থাপন করলে কাজ করে",", আর ",[170,176,178],{"href":177},"\u002Fblog\u002Fbn\u002Ffreelance-rate-setting","নিজের রেট কীভাবে ঠিক করবেন"," — দুটোই আলাদা হিসাব।",{"title":85,"searchDepth":181,"depth":181,"links":182},3,[183,185,186,187,188],{"id":56,"depth":184,"text":57},2,{"id":73,"depth":184,"text":74},{"id":115,"depth":184,"text":116},{"id":132,"depth":184,"text":133},{"id":154,"depth":184,"text":155},"business",null,"2026-09-11","একই ল্যান্ডিং পেজ, একই দাম, একই প্রোডাক্ট — শুধু নিচে তিনটা রিভিউ যোগ করলেই কনভার্শন বদলে যায়। এটা কাকতালীয় না, মানুষ সিদ্ধান্ত নেওয়ার সময় অন্যদের আচরণ দেখেই ভরসা করে।","md","bn",{},"\u002Fblog\u002Fbn\u002Ftrust-social-proof-conversion",8,{"title":34,"description":192},"মানুষ অচেনা কারো কাছ থেকে কিনতে কেন দ্বিধা করে","blog\u002Fbn\u002Ftrust-social-proof-conversion",[202,203,204],"Trust","Conversion","সাইকোলজি","zbp8wNKt8V0yU7FIOwTSAV5lhPtUdkwPcOtUAWdPOJA",{"id":207,"title":208,"author":209,"body":210,"category":189,"cover":190,"coverAlt":190,"date":310,"description":311,"draft":6,"extension":193,"featured":6,"lang":194,"meta":312,"navigation":24,"path":313,"readingTime":197,"seo":314,"seoTitle":315,"stem":316,"tags":317,"__hash__":321},"blog\u002Fblog\u002Fbn\u002Fjobs-to-be-done-customer-problem.md","প্রোডাক্ট বেচবেন না, সমস্যার সমাধান বেচুন — Customer আসলে কী 'hire' করছে",{"name":36,"role":37},{"type":39,"value":211,"toc":304},[212,215,218,221,225,232,237,241,263,266,271,275,282,287,293,297,301],[42,213,214],{},"একটা ফাস্ট-ফুড চেইন মিল্কশেকের সেল বাড়াতে চেয়েছিল। তারা শুরুতে করেছিল যা সবাই করে: কাস্টমারদের জিজ্ঞেস করেছিল মিল্কশেক আরও মিষ্টি হওয়া উচিত কি না, ঘন হওয়া উচিত কি না, ফ্লেভার বাড়ানো উচিত কি না। ফিডব্যাক অনুযায়ী বদলও করেছিল — সেলে তেমন পার্থক্য হয়নি।",[42,216,217],{},"পরে একজন গবেষক আলাদাভাবে খেয়াল করলেন: প্রায় অর্ধেক মিল্কশেক বিক্রি হচ্ছিল সকালবেলা, একা আসা মানুষদের কাছে, যারা সেটা গাড়িতে বসে খেয়ে অফিসে যাচ্ছিলেন। জিজ্ঞেস করে জানা গেল — তারা মিল্কশেক \"খেতে\" আসেননি। তারা এসেছিলেন একটা বোরিং, একঘেয়ে ড্রাইভকে একটু সহনীয় করার মতো কিছু খুঁজতে — যেটা এক হাতে খাওয়া যায়, নোংরা হয় না, আর অনেকক্ষণ ধরে টিকে থাকে যাতে পুরো জ্যামটা কাটানো যায়।",[42,219,220],{},"মিল্কশেক তাদের কাছে আসলে একটা \"সঙ্গী\" — বোরডম দূর করার একটা টুল। এই আসল কাজটা বুঝেই কোম্পানি প্রোডাক্টে বদল আনল: আরও ঘন করল (যাতে বেশিক্ষণ ধরে খাওয়া যায়, স্ট্র দিয়ে টানতে সময় লাগে), আর ছোট ছোট ফল-টুকরো যোগ করল (মাঝেমধ্যে একটা \"সারপ্রাইজ\")। মিষ্টতা নিয়ে কিছুই বদলায়নি।",[54,222,224],{"id":223},"customer-প্রোডাক্ট-কেনে-না-একটা-কাজের-জন্য-hire-করে","Customer প্রোডাক্ট কেনে না, একটা কাজের জন্য \"hire\" করে",[42,226,227,228,231],{},"এই চিন্তাধারাকে বলে ",[49,229,230],{},"Jobs-to-be-Done (JTBD)"," — মূল কথা: মানুষ কোনো প্রোডাক্ট বা সার্ভিস কেনে না, বরং তাদের জীবনের একটা নির্দিষ্ট মুহূর্তে, একটা নির্দিষ্ট সমস্যা সমাধানের জন্য সেটাকে \"hire\" করে। প্রোডাক্ট বদলে গেলেও, বা প্রতিযোগী বদলে গেলেও, \"job\"-টা একই থেকে যায়।",[66,233,234],{},[42,235,236],{},"\"Job\" মানে সবসময় ব্যবহারিক (functional) কিছু না। একটা দামি ঘড়ি কেনার job হতে পারে \"সময় দেখা\" — অথবা হতে পারে \"নিজেকে সফল হিসেবে অনুভব করা\" (emotional job) বা \"অন্যদের কাছে একটা নির্দিষ্ট ইমেজ তৈরি করা\" (social job)। একই প্রোডাক্ট, ভিন্ন কাস্টমারের কাছে ভিন্ন job সমাধান করছে হতে পারে।",[54,238,240],{"id":239},"ফিচার-ভিত্তিক-পিচ-বনাম-job-ভিত্তিক-পিচ","ফিচার-ভিত্তিক পিচ বনাম job-ভিত্তিক পিচ",[76,242,247,255],{"after":243,"before":244,"note":245,"split":246},"Job-ভিত্তিক পিচ","ফিচার-ভিত্তিক পিচ","বাম পাশেরটা প্রোডাক্ট নিয়ে কথা বলছে, ডান পাশেরটা কাস্টমারের আসল ভয় আর সময়ের সংকট নিয়ে কথা বলছে।","একই সার্ভিস — accounting সফটওয়্যার",[83,248,249],{"v-slot:before":85},[87,250,253],{"className":251,"code":252,"language":92},[90],"আমাদের সফটওয়্যারে আছে:\n- অটোমেটিক ইনভয়েস জেনারেশন\n- রিয়েল-টাইম ট্যাক্স ক্যালকুলেশন\n- মাল্টি-কারেন্সি সাপোর্ট\n",[94,254,252],{"__ignoreMap":85},[83,256,257],{"v-slot:after":85},[87,258,261],{"className":259,"code":260,"language":92},[90],"মাস শেষে হিসাব মেলাতে বসে\nরাত জাগতে হবে না।\n৫ মিনিটে ইনভয়েস, ট্যাক্সের\nহিসাব নিজে থেকেই ঠিক থাকবে।\n",[94,262,260],{"__ignoreMap":85},[42,264,265],{},"দুটোই একই ফিচার বর্ণনা করছে। কিন্তু দ্বিতীয়টা কাস্টমারের আসল অভিজ্ঞতা — মাস শেষে হিসাব নিয়ে চাপ, রাত জেগে কাজ করা — সেই জায়গা থেকে কথা বলছে। যে কাস্টমার এই ব্যথাটা অনুভব করছেন, তার কাছে দ্বিতীয় পিচটাই আগে পৌঁছায়।",[108,267,268],{},[42,269,270],{},"নিজে থেকে অনুমান করে নেওয়া সবচেয়ে বড় ভুল — \"আমার মনে হয় কাস্টমাররা স্পিড চায়\" বলে ফিচার বানিয়ে ফেলা, আসল কাস্টমারকে জিজ্ঞেস না করেই। মিল্কশেকের উদাহরণেও প্রথম রাউন্ডের সার্ভে ব্যর্থ হয়েছিল কারণ প্রশ্নগুলো ছিল প্রোডাক্ট নিয়ে (\"মিষ্টি কেমন লাগে\"), কাস্টমারের পরিস্থিতি নিয়ে না (\"কখন, কেন এটা কেনেন\")।",[54,272,274],{"id":273},"আসল-job-খুঁজে-বের-করার-একটা-সহজ-উপায়","আসল job খুঁজে বের করার একটা সহজ উপায়",[42,276,277,278,281],{},"সরাসরি \"আপনার কী দরকার\" জিজ্ঞেস করলে মানুষ প্রায়ই ফিচারের ভাষায় উত্তর দেয় (\"আরেকটু দ্রুত হলে ভালো হতো\"), আসল কারণ বলে না। এর বদলে জিজ্ঞেস করুন: ",[49,279,280],{},"\"সবশেষ কবে এই সমস্যায় পড়েছিলেন? তখন ঠিক কী হচ্ছিল, আর তখন কী করেছিলেন?\""," — একটা নির্দিষ্ট ঘটনার গল্প জিজ্ঞেস করলে আসল পরিস্থিতিটা বেরিয়ে আসে, সাধারণ মতামতের চেয়ে।",[125,283,284],{},[42,285,286],{},"একটা উত্তর পাওয়ার পর থেমে যাবেন না — একবার \"কেন\" জিজ্ঞেস করলে সাধারণত উপরিভাগের কারণ পাওয়া যায়। পরপর তিন-চারবার \"তারপর কেন এটা গুরুত্বপূর্ণ\" জিজ্ঞেস করলে আসল emotional বা social job-এ পৌঁছানো যায় — এটাকে বলে \"৫ কেন\" (5 Whys) টেকনিক।",[142,288],{":answer":289,":options":290,"checkLabel":146,"correctLabel":147,"explanation":291,"incorrectLabel":149,"question":292,"resetLabel":151},"1","[\"\\\"জিমে আর কী কী ইকুইপমেন্ট থাকলে ভালো হতো?\\\"\",\"\\\"যেদিন মেম্বারশিপ নিয়েছিলেন, সেদিন ঠিক কী হয়েছিল যে সিদ্ধান্তটা নিলেন?\\\"\",\"\\\"আপনি কি জিমের দামে সন্তুষ্ট?\\\"\",\"\\\"আর কোন জিমে ট্রাই করেছিলেন?\\\"\"]","নির্দিষ্ট একটা মুহূর্তের কথা জিজ্ঞেস করলে (মেম্বারশিপ নেওয়ার দিন কী হয়েছিল) আসল \"job\"-টা বেরিয়ে আসে — হয়তো এটা নতুন বছরের রেজোলিউশন ছিল, বা ডাক্তারের সতর্কবার্তা, বা বন্ধুর সাথে সময় কাটানোর ইচ্ছা। ইকুইপমেন্ট বা দাম নিয়ে প্রশ্ন ফিচার-লেভেলে আটকে থাকে, আসল প্রেরণা পর্যন্ত পৌঁছায় না।","একজন কাস্টমার প্রিমিয়াম জিম মেম্বারশিপ কিনেছেন, কিন্তু মাসে মাত্র ২ বার যান। ঠিক জিম কেন কিনেছিলেন সেটা বুঝতে চাইলে সবচেয়ে ভালো প্রশ্ন কোনটা?",[54,294,296],{"id":295},"customer-discovery-তে-যা-করবেন","Customer discovery-তে যা করবেন",[157,298],{":items":299,"doneLabel":160,"resetLabel":161,"title":300},"[{\"label\":\"প্রোডাক্ট নিয়ে না জিজ্ঞেস করে, নির্দিষ্ট একটা ঘটনার গল্প জিজ্ঞেস করুন\",\"detail\":\"\\\"সবশেষ কবে এই সমস্যায় পড়েছিলেন\\\" — সাধারণ মতামতের চেয়ে অনেক বেশি সত্য বেরিয়ে আসে।\"},{\"label\":\"একটা \\\"কেন\\\"-তে থেমে যাবেন না, পরপর কয়েকবার জিজ্ঞেস করুন\",\"detail\":\"প্রথম উত্তর প্রায়ই উপরিভাগের — আসল emotional\u002Fsocial কারণ তিন-চার স্তর গভীরে থাকে।\"},{\"label\":\"যারা প্রোডাক্ট কিনে ব্যবহার করছেন না (churn), তাদেরও জিজ্ঞেস করুন\",\"detail\":\"যারা \\\"job\\\"-টা অন্য কোথাও সমাধান করে ফেলেছেন, তারাই আসল প্রতিযোগী কে সেটা বলে দেয় — যেটা সবসময় সরাসরি প্রতিদ্বন্দ্বী কোম্পানি হয় না।\"},{\"label\":\"ফিচার-অনুরোধকে সরাসরি বাস্তবায়ন না করে, পেছনের কারণটা খুঁজুন\",\"detail\":\"\\\"আরও দ্রুত চাই\\\" বলার পেছনে হয়তো \\\"সময়মতো বসের কাছে রিপোর্ট পাঠাতে না পারার ভয়\\\" লুকিয়ে আছে।\"},{\"label\":\"একই প্রোডাক্টের বিভিন্ন কাস্টমারের ভিন্ন job থাকতে পারে, এটা মেনে নিন\",\"detail\":\"একটাই মেসেজ সবার জন্য কাজ নাও করতে পারে — সেগমেন্ট অনুযায়ী পিচ বদলাতে হতে পারে।\"}]","আসল \"job\" খুঁজে বের করার চেকলিস্ট",[42,302,303],{},"কাস্টমার কী কিনছে সেটা প্রশ্ন না — কাস্টমার কেন কিনছে, ঠিক কোন মুহূর্তে, কোন চাপ থেকে — সেই প্রশ্নের উত্তরেই আসল সেলস স্ট্র্যাটেজি লুকিয়ে থাকে।",{"title":85,"searchDepth":181,"depth":181,"links":305},[306,307,308,309],{"id":223,"depth":184,"text":224},{"id":239,"depth":184,"text":240},{"id":273,"depth":184,"text":274},{"id":295,"depth":184,"text":296},"2026-09-10","একজন কাস্টমার মিল্কশেক কেনে না — সকালের বোরিং গাড়ি-চালানোর সময়টাকে সহনীয় করার একটা উপায় কেনে। প্রোডাক্টের ফিচার লিস্ট না, এই \"job\"-টা বুঝলেই সেল বাড়ে।",{},"\u002Fblog\u002Fbn\u002Fjobs-to-be-done-customer-problem",{"title":208,"description":311},"প্রোডাক্ট বেচবেন না, সমস্যার সমাধান বেচুন","blog\u002Fbn\u002Fjobs-to-be-done-customer-problem",[318,319,320],"Customer Research","সেলস","বিজনেস","TOPAjOCpt_BhKxqqeV_N_Hx9tTiiamlLw20vaHTTO0E",{"id":323,"title":324,"author":325,"body":326,"category":189,"cover":190,"coverAlt":190,"date":443,"description":444,"draft":6,"extension":193,"featured":6,"lang":194,"meta":445,"navigation":24,"path":172,"readingTime":446,"seo":447,"seoTitle":448,"stem":449,"tags":450,"__hash__":452},"blog\u002Fblog\u002Fbn\u002Fprice-anchoring-decoy-effect.md","কাস্টমার দাম দেখে কেনে না, তুলনা দেখে কেনে — Price Anchoring যেভাবে কাজ করে",{"name":36,"role":37},{"type":39,"value":327,"toc":437},[328,331,334,338,345,348,357,361,368,390,393,398,402,416,421,426,430,434],[42,329,330],{},"একটা ম্যাগাজিনের সাবস্ক্রিপশন পেজে তিনটা অপশন ছিল: শুধু ওয়েব ভার্সন $59, শুধু প্রিন্ট ভার্সন $125, আর ওয়েব + প্রিন্ট একসাথে $125। তৃতীয়টা দেখে অবাক লাগার কথা — প্রিন্ট একা যা দাম, একসাথে নিলেও তাই। তাও এই সেটআপে বেশিরভাগ মানুষ তৃতীয় অপশনটাই বেছে নিয়েছিল। মাঝের অপশনটা সরিয়ে দিলে ফলাফল পুরো উল্টে যায় — তখন বেশিরভাগ মানুষ সবচেয়ে সস্তাটাই নেয়।",[42,332,333],{},"প্রোডাক্ট বদলায়নি, দামও বদলায়নি। শুধু একটা তুলনা করার মতো অপশন যোগ করা হয়েছিল — আর সেটাই সিদ্ধান্ত ঘুরিয়ে দিয়েছে।",[54,335,337],{"id":336},"মস্তিষ্ক-দাম-বিচার-করে-না-তুলনা-করে","মস্তিষ্ক দাম বিচার করে না, তুলনা করে",[42,339,340,341,344],{},"এইটাই ",[49,342,343],{},"anchoring"," — মানুষ কোনো কিছুর দাম \"ঠিক আছে না বেশি\" এভাবে বিচার করে না, বরং হাতের কাছে যা তুলনা করার আছে তার সাথে মিলিয়ে বিচার করে। প্রথম যে সংখ্যাটা চোখে পড়ে, সেটাই একটা রেফারেন্স পয়েন্ট হয়ে যায় — বাকি সবকিছু তার সাপেক্ষে \"সস্তা\" বা \"দামি\" মনে হয়।",[42,346,347],{},"এটা কোনো ম্যানিপুলেশনের কৌশল না — এটা মানুষের সিদ্ধান্ত নেওয়ার স্বাভাবিক প্রক্রিয়া। একটা ফ্রিল্যান্স প্রজেক্টের কোটেশন একা পাঠালে ক্লায়েন্ট সেটাকে \"দামি\" বা \"সস্তা\" — কীসের সাথে তুলনা করে বিচার করবে, সেটা ঠিক করার সুযোগটাই তাকে দেওয়া হয়নি।",[66,349,350],{},[42,351,352,353,356],{},"Anchor সবসময় সংখ্যায় হতে হবে এমন না। \"সাধারণত এই কাজের রেট $2000 থেকে শুরু\" — এই একটা লাইন বলার পরে $1200-এর কোটেশন পাঠালে সেটা পুরো অন্যরকম শোনায়, একই কোটেশন কোনো প্রসঙ্গ ছাড়া পাঠানোর তুলনায়। তবে anchor ঠিক করার আগে নিজের আসল রেটটা জানা লাগে — ",[170,354,355],{"href":177},"সেই হিসাবটা আলাদা","।",[54,358,360],{"id":359},"তিনটা-অপশন-একটা-decoy","তিনটা অপশন, একটা \"decoy\"",[42,362,363,364,367],{},"উপরের ম্যাগাজিনের উদাহরণে মাঝের অপশনটার নাম ",[49,365,366],{},"decoy"," — নিজে থেকে কেউ ওটা বেছে নেয় না, কিন্তু ওটার পাশে দাঁড়ালে তৃতীয় অপশনটাকে \"obviously ভালো\" মনে হয়। কাউকে সরাসরি কিছু বেছে নিতে বলার চেয়ে, দুটো ভালো অপশনের মধ্যে তুলনা করতে দিলে সিদ্ধান্ত নেওয়া সহজ হয়ে যায় — আর সেই তুলনাটা যদি সাজিয়ে দেওয়া যায়, ফলাফলও পূর্বানুমান করা যায়।",[76,369,374,382],{"after":370,"before":371,"note":372,"split":373},"তিনটা প্যাকেজ, মাঝেরটা ইচ্ছাকৃতভাবে কম আকর্ষণীয়","তিনটা প্যাকেজ, কোনো decoy নেই","ডান পাশে Standard-কে Pro-র প্রায় কাছাকাছি দামে রেখে, কিন্তু কম ফিচার দিয়ে, Pro-কে 'সহজ সিদ্ধান্ত' বানানো হয়েছে।","একই সার্ভিস",[83,375,376],{"v-slot:before":85},[87,377,380],{"className":378,"code":379,"language":92},[90],"Basic — ৳৫,০০০\u002Fমাস\nStandard — ৳১২,০০০\u002Fমাস\nPro — ৳১৫,০০০\u002Fমাস\n",[94,381,379],{"__ignoreMap":85},[83,383,384],{"v-slot:after":85},[87,385,388],{"className":386,"code":387,"language":92},[90],"Basic — ৳৫,০০০\u002Fমাস (শুধু জরুরি ফিচার)\nStandard — ৳১৪,০০০\u002Fমাস (Pro-র প্রায় সব ফিচার, তবে ২ জন ইউজার লিমিট)\nPro — ৳১৫,০০০\u002Fমাস (আনলিমিটেড ইউজার + প্রায়োরিটি সাপোর্ট)\n",[94,389,387],{"__ignoreMap":85},[42,391,392],{},"লক্ষ্য করুন: দ্বিতীয় সংস্করণে Standard আর Pro-র দামের পার্থক্য মাত্র ৳১,০০০, কিন্তু ফিচারের পার্থক্য বড়। এটা দেখার পর বেশিরভাগ মানুষের কাছে Pro-ই \"আসল ডিল\" মনে হয় — Standard-এর কাজ শুধু সেই তুলনাটা তৈরি করে দেওয়া।",[108,394,395],{},[42,396,397],{},"Anchor খুব বাড়িয়ে দিলে বা decoy খুব স্পষ্টভাবে \"বেকার অপশন\" বানিয়ে ফেললে উল্টো ফল হয় — মানুষ ম্যানিপুলেশন টের পেয়ে গেলে বিশ্বাস হারায়, আর সেটা যেকোনো pricing trick-এর চেয়ে বড় ক্ষতি করে। Decoy-কে বাস্তব, ব্যবহারযোগ্য একটা অপশন রাখতে হবে — নিছক ফাঁদ বানালে চলবে না।",[54,399,401],{"id":400},"দাম-লেখার-ধরনও-প্রভাব-ফেলে","দাম লেখার ধরনও প্রভাব ফেলে",[42,403,404,407,408,411,412,415],{},[94,405,406],{},"৳৯৯৯"," আর ",[94,409,410],{},"৳১,০০০"," — সংখ্যা প্রায় একই, কিন্তু প্রথমটা \"৯০০-এর ঘরে\" মনে হয়, দ্বিতীয়টা \"হাজারের ঘরে\"। বাম দিকের প্রথম সংখ্যাটাই মস্তিষ্ক আগে পড়ে ফেলে, বাকিটা পরে। এটাকে বলে ",[49,413,414],{},"left-digit effect"," — কোনো গোপন কৌশল না, শুধু মানুষ সংখ্যা যেভাবে স্ক্যান করে তার একটা বাস্তব ফলাফল।",[125,417,418],{},[42,419,420],{},"মাসিক আর বাৎসরিক প্যাকেজ পাশাপাশি দেখালে বাৎসরিকটাকে \"প্রতি মাসে ৳X\" হিসেবে ভেঙে দেখান, পুরো বছরের বড় সংখ্যাটা প্রথমে না দেখিয়ে। একই টাকা, কিন্তু ছোট সংখ্যাটা প্রথমে চোখে পড়লে সিদ্ধান্ত নেওয়া সহজ হয়।",[142,422],{":answer":289,":options":423,"checkLabel":146,"correctLabel":147,"explanation":424,"incorrectLabel":149,"question":425,"resetLabel":151},"[\"Basic-এর চেয়ে সস্তা, ফিচার আরও কম\",\"Pro-র কাছাকাছি দাম, কিন্তু Pro-র চেয়ে স্পষ্টভাবে কম ফিচার\",\"সবচেয়ে বেশি দাম, সবচেয়ে বেশি ফিচার\",\"Basic আর Pro-র ঠিক মাঝামাঝি দাম, আর মাঝামাঝি ফিচার\"]","decoy-র কাজ হলো একটা নির্দিষ্ট অপশনকে (এখানে Pro) \"obviously ভালো ডিল\" বানিয়ে দেওয়া। Pro-র কাছাকাছি দামে রেখে কিন্তু স্পষ্টভাবে কম ফিচার দিলে, দাম পার্থক্য সামান্য মনে হয় আর ফিচার পার্থক্য বড় মনে হয় — ফলে মানুষ সেই সামান্য বাড়তি টাকা দিয়ে Pro-ই নেয়। মাঝামাঝি একটা \"ভারসাম্য\" অপশন আসলে decoy হিসেবে কাজ করে না, কারণ সেটা নিজেই একটা যুক্তিসঙ্গত পছন্দ হয়ে ওঠে।","একটা SaaS প্রোডাক্টের দুটো প্ল্যান আছে: Basic ৳৫০০\u002Fমাস, Pro ৳২০০০\u002Fমাস। বিক্রি বাড়ানোর জন্য একটা তৃতীয় \"decoy\" প্ল্যান যোগ করতে চান। এটার দাম আর ফিচার কেমন হওয়া উচিত?",[54,427,429],{"id":428},"pricing-পেজ-রিভিউ-করার-আগে","Pricing পেজ রিভিউ করার আগে",[157,431],{":items":432,"doneLabel":160,"resetLabel":161,"title":433},"[{\"label\":\"প্রথম যে সংখ্যাটা দেখা যাচ্ছে, সেটাই কি সঠিক anchor?\",\"detail\":\"সবচেয়ে দামি অপশন বাম দিকে বা সবার আগে থাকলে, বাকি সবকিছু তুলনায় সস্তা মনে হয়।\"},{\"label\":\"তিনটা অপশনের মধ্যে একটা কি স্পষ্ট decoy?\",\"detail\":\"decoy বাস্তব ব্যবহারযোগ্য হতে হবে, নিছক ফাঁদ বানালে বিশ্বাস নষ্ট হয়।\"},{\"label\":\"সংখ্যার প্রথম অঙ্কটা (left-digit) খেয়াল করেছেন?\",\"detail\":\"৯৯৯ আর ১০০০ — সংখ্যায় কাছাকাছি, ধারণায় না।\"},{\"label\":\"বড় সংখ্যাকে ছোট এককে ভেঙে দেখানো হয়েছে কি?\",\"detail\":\"বাৎসরিক দামকে মাসিক হিসেবে দেখানো এর একটা সাধারণ উদাহরণ।\"},{\"label\":\"Anchor বা decoy কি এতটা বাড়াবাড়ি যে অবিশ্বাস্য মনে হচ্ছে?\",\"detail\":\"ধরা পড়ে গেলে সেটা যেকোনো pricing কৌশলের চেয়ে বেশি ক্ষতি করে।\"}]","দাম লেখার আগে যা যাচাই করবেন",[42,435,436],{},"দাম ঠিক করা মানে শুধু একটা সংখ্যা বসানো না — সেই সংখ্যাটা কার পাশে বসছে, সেটাই আসল সিদ্ধান্ত।",{"title":85,"searchDepth":181,"depth":181,"links":438},[439,440,441,442],{"id":336,"depth":184,"text":337},{"id":359,"depth":184,"text":360},{"id":400,"depth":184,"text":401},{"id":428,"depth":184,"text":429},"2026-09-09","একই প্রোডাক্ট, একই দাম — শুধু পাশে আরেকটা অপশন বসিয়ে দিলেই সেল বেড়ে যায়। ম্যাজিক না, এটা মানুষের মস্তিষ্কের একটা পরিচিত প্যাটার্ন — Anchoring।",{},7,{"title":324,"description":444},"কাস্টমার দাম দেখে কেনে না, তুলনা দেখে কেনে","blog\u002Fbn\u002Fprice-anchoring-decoy-effect",[451,319,204],"Pricing","ZGfdk0jKDlZ6-UkUohFeWrtqwtncS3wN60ZaBDDAQX0",{"id":454,"title":455,"author":456,"body":459,"category":810,"cover":190,"coverAlt":190,"date":811,"description":812,"draft":6,"extension":193,"featured":6,"lang":194,"meta":813,"navigation":24,"path":814,"readingTime":197,"seo":815,"seoTitle":816,"stem":817,"tags":818,"__hash__":821},"blog\u002Fblog\u002Fbn\u002Fkubernetes-rolling-update-rollback.md","Deployment আপডেট করলে সাইট ডাউন হয় না কেন — Rolling Update ভেতরে ভেতরে কী করে",{"name":457,"role":458},"রাফি হাসান","DevOps ইঞ্জিনিয়ার",{"type":39,"value":460,"toc":803},[461,471,474,478,493,503,507,512,520,535,681,700,713,717,738,748,756,760,773,783,788,792,796,799],[42,462,463,466,467,470],{},[94,464,465],{},"kubectl set image deployment\u002Fapi api=myapp:v2"," — একটা কমান্ড, আর কয়েক সেকেন্ড পর ",[94,468,469],{},"kubectl get pods"," চালালে দেখা যায় পুরনো Pod-গুলো একে একে হারিয়ে যাচ্ছে, নতুনগুলো জায়গা নিচ্ছে। এই পুরো সময়টায় সাইটে একটাও রিকোয়েস্ট ফেইল হয় না — অথচ কোনো মেইনটেন্যান্স পেজ দেখানো হয়নি, কাউকে জানানোও হয়নি।",[42,472,473],{},"এটা কীভাবে হয়, সেটা বুঝলে দুটো জিনিস পরিষ্কার হয়ে যায়: ডিপ্লয়মেন্ট স্লো কেন হচ্ছে সেটা ডিবাগ করা, আর কিছু ভুল হলে কীভাবে এক কমান্ডে ফিরিয়ে আনা যায়।",[54,475,477],{"id":476},"ডিফল্ট-স্ট্র্যাটেজি-rollingupdate","ডিফল্ট স্ট্র্যাটেজি: RollingUpdate",[42,479,480,481,484,485,488,489,492],{},"একটা Kubernetes ",[94,482,483],{},"Deployment","-এর ",[94,486,487],{},".spec.strategy.type"," ডিফল্টভাবে ",[94,490,491],{},"RollingUpdate"," — মানে নতুন ভার্সন এক ধাক্কায় পুরনোটাকে replace করে না। বরং ধাপে ধাপে: কিছু নতুন Pod তৈরি হয়, তারা readiness probe পাস করে ট্রাফিক নেওয়ার জন্য প্রস্তুত হয়, তারপরই সমপরিমাণ পুরনো Pod সরিয়ে দেওয়া হয়। পুরো ট্রানজিশন জুড়ে সবসময় যথেষ্ট সংখ্যক Pod ট্রাফিক পাওয়ার জন্য রেডি থাকে।",[66,494,495],{},[42,496,497,498,502],{},"এই পুরো প্রক্রিয়াটা সরাসরি নির্ভর করে আগের একটা জিনিসের ওপর — ",[170,499,501],{"href":500},"\u002Fblog\u002Fbn\u002Fkubernetes-liveness-readiness-probe","readiness probe ঠিকমতো সেট করা থাকা","। readiness probe না থাকলে বা ভুল থাকলে, Kubernetes ধরে নেয় নতুন Pod সাথে সাথেই \"রেডি\" — তখন rolling update আসলে আর নিরাপদ থাকে না, কারণ যে Pod-টা এখনো স্টার্টআপ শেষ করেনি তার কাছেও ট্রাফিক চলে যেতে পারে।",[54,504,506],{"id":505},"দুটো-সংখ্যা-যা-পুরো-আচরণ-নিয়ন্ত্রণ-করে","দুটো সংখ্যা যা পুরো আচরণ নিয়ন্ত্রণ করে",[42,508,509,511],{},[94,510,491],{}," স্ট্র্যাটেজির ভেতরে দুটো প্যারামিটার থাকে, দুটোই পার্সেন্টেজ বা সংখ্যা হিসেবে দেওয়া যায়:",[42,513,514,519],{},[49,515,516],{},[94,517,518],{},"maxSurge"," — কাঙ্ক্ষিত রেপ্লিকা সংখ্যার চেয়ে বেশি কতগুলো Pod সাময়িকভাবে তৈরি করা যাবে। এটা বেশি রাখলে ডিপ্লয়মেন্ট দ্রুত হয় (একসাথে বেশি নতুন Pod ওঠে), কিন্তু ওই মুহূর্তে ক্লাস্টারে বাড়তি CPU\u002Fমেমরি লাগে।",[42,521,522,527,528,531,532,534],{},[49,523,524],{},[94,525,526],{},"maxUnavailable"," — কাঙ্ক্ষিত সংখ্যার চেয়ে কতগুলো Pod সাময়িকভাবে কম থাকতে পারবে (অর্থাৎ, ট্রাফিক নেওয়ার জন্য অনুপলব্ধ থাকতে পারবে)। এটা ",[94,529,530],{},"0"," রাখলে ডিপ্লয়মেন্টের সময় ক্যাপাসিটি কখনো কমবে না — কিন্তু তার মানে ",[94,533,518],{}," অন্তত ১ না রাখলে নতুন Pod ওঠারই জায়গা থাকবে না।",[76,536,541,622],{"after":537,"before":538,"note":539,"split":540},"জিরো-ডাউনটাইম কনফিগ","ডিফল্ট (25%\u002F25%)","ডান পাশের কনফিগারেশনে ক্যাপাসিটি কখনো কমে না, শুধু সাময়িকভাবে বাড়ে — ছোট ট্রাফিক স্পাইকের সময় ডিপ্লয় করলেও এটা নিরাপদ।","একই Deployment",[83,542,543],{"v-slot:before":85},[87,544,548],{"className":545,"code":546,"language":547,"meta":85,"style":85},"language-yaml shiki shiki-themes github-dark-dimmed github-dark-dimmed","spec:\n  replicas: 4\n  strategy:\n    type: RollingUpdate\n    rollingUpdate:\n      maxSurge: 25%\n      maxUnavailable: 25%\n","yaml",[94,549,550,563,575,582,594,602,613],{"__ignoreMap":85},[551,552,555,559],"span",{"class":553,"line":554},"line",1,[551,556,558],{"class":557},"sza-u","spec",[551,560,562],{"class":561},"sM9_K",":\n",[551,564,565,568,571],{"class":553,"line":184},[551,566,567],{"class":557},"  replicas",[551,569,570],{"class":561},": ",[551,572,574],{"class":573},"sQdni","4\n",[551,576,577,580],{"class":553,"line":181},[551,578,579],{"class":557},"  strategy",[551,581,562],{"class":561},[551,583,585,588,590],{"class":553,"line":584},4,[551,586,587],{"class":557},"    type",[551,589,570],{"class":561},[551,591,593],{"class":592},"szYpP","RollingUpdate\n",[551,595,597,600],{"class":553,"line":596},5,[551,598,599],{"class":557},"    rollingUpdate",[551,601,562],{"class":561},[551,603,605,608,610],{"class":553,"line":604},6,[551,606,607],{"class":557},"      maxSurge",[551,609,570],{"class":561},[551,611,612],{"class":592},"25%\n",[551,614,615,618,620],{"class":553,"line":446},[551,616,617],{"class":557},"      maxUnavailable",[551,619,570],{"class":561},[551,621,612],{"class":592},[83,623,624],{"v-slot:after":85},[87,625,627],{"className":545,"code":626,"language":547,"meta":85,"style":85},"spec:\n  replicas: 4\n  strategy:\n    type: RollingUpdate\n    rollingUpdate:\n      maxSurge: 1\n      maxUnavailable: 0\n",[94,628,629,635,643,649,657,663,672],{"__ignoreMap":85},[551,630,631,633],{"class":553,"line":554},[551,632,558],{"class":557},[551,634,562],{"class":561},[551,636,637,639,641],{"class":553,"line":184},[551,638,567],{"class":557},[551,640,570],{"class":561},[551,642,574],{"class":573},[551,644,645,647],{"class":553,"line":181},[551,646,579],{"class":557},[551,648,562],{"class":561},[551,650,651,653,655],{"class":553,"line":584},[551,652,587],{"class":557},[551,654,570],{"class":561},[551,656,593],{"class":592},[551,658,659,661],{"class":553,"line":596},[551,660,599],{"class":557},[551,662,562],{"class":561},[551,664,665,667,669],{"class":553,"line":604},[551,666,607],{"class":557},[551,668,570],{"class":561},[551,670,671],{"class":573},"1\n",[551,673,674,676,678],{"class":553,"line":446},[551,675,617],{"class":557},[551,677,570],{"class":561},[551,679,680],{"class":573},"0\n",[42,682,683,684,687,688,691,692,695,696,699],{},"৪টা রেপ্লিকা আর ডিফল্ট ",[94,685,686],{},"25%\u002F25%"," কনফিগারেশন দিয়ে হিসাব করলে: ",[94,689,690],{},"maxUnavailable: 25%"," মানে একসাথে ১টা Pod সাময়িকভাবে কমে যেতে পারে (৪ থেকে ৩-এ), অর্থাৎ ক্যাপাসিটি সাময়িকভাবে কমে। ডান পাশের কনফিগারেশনে ",[94,693,694],{},"maxUnavailable: 0"," দেওয়ায় সেটা কখনো হয় না — সবসময় কমপক্ষে ৪টা Pod রেডি থাকে, মাঝেমধ্যে ৫টা পর্যন্ত (৪ + ",[94,697,698],{},"maxSurge: 1",")।",[108,701,702],{},[42,703,704,407,706,709,710,712],{},[94,705,694],{},[94,707,708],{},"replicas: 1"," একসাথে থাকলে rolling update কখনো এগোতে পারবে না যদি ",[94,711,518],{}," না বাড়ানো হয় — কারণ একটা মাত্র Pod-কে \"unavailable\" না করে replace করার কোনো উপায় নেই, নতুন জায়গা তৈরি না করলে। ছোট সার্ভিসে এই কম্বিনেশন একটা Deployment স্টাক হয়ে থাকার সাধারণ কারণ।",[54,714,716],{"id":715},"rollout-স্টাক-থাকলে-কী-দেখবেন","rollout স্টাক থাকলে কী দেখবেন",[42,718,719,722,723,725,726,729,730,733,734,737],{},[94,720,721],{},"kubectl rollout status deployment\u002Fapi"," কমান্ড আটকে থাকলে, প্রথম সন্দেহ করার জায়গা: নতুন Pod-গুলো readiness probe পাস করছে কি না। ",[94,724,469],{}," চালিয়ে ",[94,727,728],{},"READY"," কলামে ",[94,731,732],{},"0\u002F1"," দেখলে বোঝা যায় Pod উঠেছে কিন্তু readiness ফেইল করছে — এটাই ",[170,735,736],{"href":500},"আগের লেখার বিষয়"," (liveness বনাম readiness)।",[42,739,740,741,743,744,747],{},"আরেকটা সাধারণ কারণ: রিসোর্স কোটা বা নোডে জায়গা না থাকা। ",[94,742,518],{}," বাড়তি Pod তৈরির অনুমতি দেয়, কিন্তু ক্লাস্টারে সেই Pod বসানোর মতো CPU\u002Fমেমরি না থাকলে সেটা ",[94,745,746],{},"Pending"," অবস্থাতেই আটকে থাকবে, আর rollout এগোবে না।",[125,749,750],{},[42,751,752,755],{},[94,753,754],{},"kubectl rollout status deployment\u002Fapi --timeout=60s"," দিয়ে rollout দেখা ভালো অভ্যাস — timeout ছাড়া কমান্ডটা আটকে গেলে টার্মিনালে বসে অপেক্ষা করা ছাড়া উপায় থাকে না। CI\u002FCD পাইপলাইনে এই timeout না রাখলে একটা স্টাক rollout পুরো পাইপলাইনকে ঘণ্টার পর ঘণ্টা ব্লক করে রাখতে পারে।",[54,757,759],{"id":758},"কিছু-ভুল-হলে-rollback","কিছু ভুল হলে — Rollback",[42,761,762,763,766,767,769,770,772],{},"নতুন ভার্সন ডিপ্লয় করার পর যদি বোঝা যায় কিছু ভুল আছে, ",[94,764,765],{},"kubectl rollout undo deployment\u002Fapi"," চালালে Kubernetes ঠিক এই একই rolling update মেকানিজম ব্যবহার করে — শুধু উল্টো দিকে। আগের ভার্সনের Pod ধীরে ধীরে ফিরিয়ে আনা হয়, নতুনটা সরানো হয়, একই ",[94,768,518],{},"\u002F",[94,771,526],{}," নিয়ম মেনেই।",[42,774,775,776,779,780,356],{},"এটা কাজ করে কারণ Deployment প্রতিটা আপডেটের একটা রিভিশন হিস্টোরি রাখে (",[94,777,778],{},"kubectl rollout history deployment\u002Fapi",")। নির্দিষ্ট কোনো রিভিশনে ফিরতে চাইলে: ",[94,781,782],{},"kubectl rollout undo deployment\u002Fapi --to-revision=3",[142,784],{":answer":144,":options":785,"checkLabel":146,"correctLabel":147,"explanation":786,"incorrectLabel":149,"question":787,"resetLabel":151},"[\"৩টা\",\"৪টা\",\"৫টা\",\"৮টা\"]","maxUnavailable: 0 মানে কখনো ৪টার নিচে নামবে না। maxSurge: 1 মানে কাঙ্ক্ষিত সংখ্যার (৪) চেয়ে বেশি ১টা পর্যন্ত বাড়তি Pod থাকতে পারে। তাই সর্বোচ্চ সংখ্যা ৪ + ১ = ৫টা — নতুন একটা Pod রেডি হওয়ার পরই পুরনো একটা সরানো হবে, কখনো একসাথে দুই দিক থেকে সংখ্যা বদলাবে না।","একটা Deployment-এর replicas: 4, maxSurge: 1, maxUnavailable: 0। rolling update চলাকালীন এক মুহূর্তে সর্বোচ্চ কতগুলো Pod একসাথে থাকতে পারে?",[54,789,791],{"id":790},"ডিপ্লয়মেন্টের-আগে-পরে-যা-চেক-করবেন","ডিপ্লয়মেন্টের আগে-পরে যা চেক করবেন",[157,793],{":items":794,"doneLabel":160,"resetLabel":161,"title":795},"[{\"label\":\"readinessProbe সঠিকভাবে সেট করা আছে কি না নিশ্চিত করুন\",\"detail\":\"এটা ছাড়া rolling update-এর পুরো নিরাপত্তা ধারণাটাই ভেঙে পড়ে।\"},{\"label\":\"maxUnavailable: 0 দরকার কি না ভাবুন\",\"detail\":\"ক্রিটিক্যাল সার্ভিসে ক্যাপাসিটি কখনো না কমানোই নিরাপদ, তবে replicas কম হলে maxSurge বাড়াতে ভুলবেন না।\"},{\"label\":\"kubectl rollout status --timeout সহ ব্যবহার করুন, বিশেষত CI\u002FCD-তে\",\"detail\":\"টাইমআউট ছাড়া একটা স্টাক rollout পাইপলাইনকে অনির্দিষ্টকাল আটকে রাখতে পারে।\"},{\"label\":\"রোলআউটের সময় kubectl get pods -w দিয়ে চোখে চোখে রাখুন\",\"detail\":\"কোনো Pod বারবার রিস্টার্ট বা Pending-এ আটকে থাকলে সাথে সাথেই বোঝা যাবে।\"},{\"label\":\"সমস্যা দেখলে দ্রুত rollout undo চালাতে দ্বিধা করবেন না\",\"detail\":\"rollback নিজেও একটা rolling update — এটাও ধাপে ধাপে হয়, তাই এটাও নিরাপদ।\"}]","Rolling update নিরাপদ কি না, যাচাইয়ের তালিকা",[42,797,798],{},"Rolling update জাদু না — এটা দুটো সংখ্যার হিসাব, আর সেই হিসাবটা কাজ করার জন্য readiness probe-এর ওপর সম্পূর্ণ নির্ভরশীল। এই তিনটা জিনিস একসাথে বুঝলে — probe, maxSurge\u002FmaxUnavailable, আর rollback — একটা প্রোডাকশন Deployment দেখলে আর অন্ধকারে ঢিল ছোড়ার মতো লাগবে না।",[800,801,802],"style",{},"html pre.shiki code .sza-u, html code.shiki .sza-u{--shiki-default:#8DDB8C;--shiki-dark:#8DDB8C}html pre.shiki code .sM9_K, html code.shiki .sM9_K{--shiki-default:#ADBAC7;--shiki-dark:#ADBAC7}html pre.shiki code .sQdni, html code.shiki .sQdni{--shiki-default:#6CB6FF;--shiki-dark:#6CB6FF}html pre.shiki code .szYpP, html code.shiki .szYpP{--shiki-default:#96D0FF;--shiki-dark:#96D0FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":85,"searchDepth":181,"depth":181,"links":804},[805,806,807,808,809],{"id":476,"depth":184,"text":477},{"id":505,"depth":184,"text":506},{"id":715,"depth":184,"text":716},{"id":758,"depth":184,"text":759},{"id":790,"depth":184,"text":791},"devops","2026-09-08","kubectl apply চালানোর পর সাইট একবারও ডাউন হয় না, অথচ পুরনো কোড সরে গিয়ে নতুন কোড চলে আসে। জাদু না — maxSurge আর maxUnavailable নামের দুটো সংখ্যা এটা সম্ভব করে।",{},"\u002Fblog\u002Fbn\u002Fkubernetes-rolling-update-rollback",{"title":455,"description":812},"Deployment আপডেটে সাইট ডাউন হয় না কেন","blog\u002Fbn\u002Fkubernetes-rolling-update-rollback",[819,820,483],"Kubernetes","DevOps","TRBMuqOPVkPQeCVhP_N5GdXNCjs2ro8BO4oLubgOGeY",{"id":823,"title":824,"author":825,"body":826,"category":810,"cover":190,"coverAlt":190,"date":1120,"description":1121,"draft":6,"extension":193,"featured":6,"lang":194,"meta":1122,"navigation":24,"path":1123,"readingTime":446,"seo":1124,"seoTitle":190,"stem":1125,"tags":1126,"__hash__":1128},"blog\u002Fblog\u002Fbn\u002Fconfigmap-vs-secret.md","ConfigMap বনাম Secret — কোনটায় কী রাখবেন",{"name":457,"role":458},{"type":39,"value":827,"toc":1114},[828,831,834,838,841,848,868,872,875,915,1063,1070,1077,1081,1087,1090,1095,1100,1104,1108,1111],[42,829,830],{},"নতুন কেউ Kubernetes শিখতে গিয়ে প্রথমেই যে ভুল ধারণাটা করে বসে: \"Secret মানে এনক্রিপ্টেড, ConfigMap মানে সাধারণ টেক্সট।\" নামটাই তো \"Secret\" — তাই মনে হয় এটা নিরাপদ একটা ভল্টের মতো কিছু।",[42,832,833],{},"আসল ঘটনাটা একটু অন্যরকম, আর এটা না জানলে প্রোডাকশনে DB পাসওয়ার্ড, API key — সবকিছু কার্যত সবার সামনে খোলা রাখার মতো ভুল করে ফেলা সহজ।",[54,835,837],{"id":836},"দুটোই-আসলে-key-value-স্টোরেজ","দুটোই আসলে key-value স্টোরেজ",[42,839,840],{},"ConfigMap আর Secret — দুটো অবজেক্টেরই কাজ একই: কিছু key-value ডেটা কন্টেইনারে পাঠানো, environment variable হিসেবে অথবা ফাইল হিসেবে মাউন্ট করে। কোড থেকে কনফিগারেশনকে আলাদা রাখাই এদের উদ্দেশ্য — যাতে একই Docker image dev, staging, প্রোডাকশনে আলাদা আলাদা ভ্যালু নিয়ে চলতে পারে।",[42,842,843,844,847],{},"পার্থক্যটা তৈরি হওয়ার কথা ছিল ",[49,845,846],{},"কী ধরনের ডেটা"," এখানে যাবে তার ভিত্তিতে — কনফিডেনশিয়াল বনাম নন-কনফিডেনশিয়াল। Kubernetes নিজে থেকে এই সীমারেখা জোর করে না, এটা সম্পূর্ণ আপনার সিদ্ধান্ত।",[66,849,850],{},[42,851,852,855,856,859,860,863,864,867],{},[94,853,854],{},"kubectl get secret my-secret -o yaml"," চালিয়ে দেখুন — ভ্যালুগুলো ",[94,857,858],{},"dGVzdDEyMw=="," এই রকম দেখাবে। এটা এনক্রিপশন না, এটা ",[49,861,862],{},"base64 encoding","। ",[94,865,866],{},"echo dGVzdDEyMw== | base64 -d"," চালালে সাথে সাথে আসল ভ্যালুটা ফেরত পাবেন। base64 একটা এনকোডিং ফরম্যাট, সুরক্ষার স্তর না।",[54,869,871],{"id":870},"তাহলে-secret-কী-সুরক্ষা-দেয়","তাহলে Secret কী সুরক্ষা দেয়?",[42,873,874],{},"কিছু দেয়, কিন্তু যতটা মানুষ ভাবে তার চেয়ে কম:",[876,877,878,901,908],"ul",{},[879,880,881,884,885,888,889,892,893,896,897,900],"li",{},[94,882,883],{},"kubectl get configmap"," বা ",[94,886,887],{},"kubectl describe configmap"," চালালে ভ্যালু সরাসরি স্ক্রিনে দেখা যায়। Secret-এর ক্ষেত্রে ",[94,890,891],{},"kubectl describe secret"," ভ্যালু লুকিয়ে রাখে (",[94,894,895],{},"\u003Credacted>","), যদিও ",[94,898,899],{},"kubectl get secret -o yaml"," দিয়ে ঠিকই বের করা যায় base64 decode করে।",[879,902,903,904,907],{},"Secret অবজেক্টগুলো etcd-তে (Kubernetes-এর ডেটাবেসে) সাধারণত plaintext আকারেই সংরক্ষিত হয়, যদি না ক্লাস্টারে আলাদাভাবে ",[49,905,906],{},"encryption at rest"," চালু করা থাকে।",[879,909,910,911,914],{},"RBAC (Role-Based Access Control) দিয়ে ",[94,912,913],{},"secrets"," রিসোর্সের জন্য আলাদা পারমিশন সেট করা যায় — অর্থাৎ, \"কে Secret পড়তে পারবে\" এটা ConfigMap থেকে আলাদা করে নিয়ন্ত্রণ করা সম্ভব। এটাই আসল ব্যবহারিক সুবিধা।",[76,916,921,992],{"after":917,"before":918,"note":919,"split":920},"Secret + RBAC + encryption at rest","ConfigMap-এ পাসওয়ার্ড","বাম পাশের কনফিগারেশনে DB পাসওয়ার্ড 'read' পারমিশন থাকা যেকোনো ইউজার\u002Fসার্ভিস এক কমান্ডে প্লেইন টেক্সটে দেখতে পারবে।","একই ক্লাস্টার",[83,922,923],{"v-slot:before":85},[87,924,926],{"className":545,"code":925,"language":547,"meta":85,"style":85},"apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: db-config\ndata:\n  DB_HOST: 'db.internal'\n  DB_PASSWORD: 'p@ssw0rd123'\n",[94,927,928,938,948,955,965,972,982],{"__ignoreMap":85},[551,929,930,933,935],{"class":553,"line":554},[551,931,932],{"class":557},"apiVersion",[551,934,570],{"class":561},[551,936,937],{"class":592},"v1\n",[551,939,940,943,945],{"class":553,"line":184},[551,941,942],{"class":557},"kind",[551,944,570],{"class":561},[551,946,947],{"class":592},"ConfigMap\n",[551,949,950,953],{"class":553,"line":181},[551,951,952],{"class":557},"metadata",[551,954,562],{"class":561},[551,956,957,960,962],{"class":553,"line":584},[551,958,959],{"class":557},"  name",[551,961,570],{"class":561},[551,963,964],{"class":592},"db-config\n",[551,966,967,970],{"class":553,"line":596},[551,968,969],{"class":557},"data",[551,971,562],{"class":561},[551,973,974,977,979],{"class":553,"line":604},[551,975,976],{"class":557},"  DB_HOST",[551,978,570],{"class":561},[551,980,981],{"class":592},"'db.internal'\n",[551,983,984,987,989],{"class":553,"line":446},[551,985,986],{"class":557},"  DB_PASSWORD",[551,988,570],{"class":561},[551,990,991],{"class":592},"'p@ssw0rd123'\n",[83,993,994],{"v-slot:after":85},[87,995,997],{"className":545,"code":996,"language":547,"meta":85,"style":85},"apiVersion: v1\nkind: Secret\nmetadata:\n  name: db-config\ntype: Opaque\nstringData:\n  DB_HOST: 'db.internal'\n  DB_PASSWORD: 'p@ssw0rd123'\n",[94,998,999,1007,1016,1022,1030,1040,1047,1055],{"__ignoreMap":85},[551,1000,1001,1003,1005],{"class":553,"line":554},[551,1002,932],{"class":557},[551,1004,570],{"class":561},[551,1006,937],{"class":592},[551,1008,1009,1011,1013],{"class":553,"line":184},[551,1010,942],{"class":557},[551,1012,570],{"class":561},[551,1014,1015],{"class":592},"Secret\n",[551,1017,1018,1020],{"class":553,"line":181},[551,1019,952],{"class":557},[551,1021,562],{"class":561},[551,1023,1024,1026,1028],{"class":553,"line":584},[551,1025,959],{"class":557},[551,1027,570],{"class":561},[551,1029,964],{"class":592},[551,1031,1032,1035,1037],{"class":553,"line":596},[551,1033,1034],{"class":557},"type",[551,1036,570],{"class":561},[551,1038,1039],{"class":592},"Opaque\n",[551,1041,1042,1045],{"class":553,"line":604},[551,1043,1044],{"class":557},"stringData",[551,1046,562],{"class":561},[551,1048,1049,1051,1053],{"class":553,"line":446},[551,1050,976],{"class":557},[551,1052,570],{"class":561},[551,1054,981],{"class":592},[551,1056,1057,1059,1061],{"class":553,"line":197},[551,1058,986],{"class":557},[551,1060,570],{"class":561},[551,1062,991],{"class":592},[42,1064,1065,1066,1069],{},"উপরের দুটো YAML প্রায় একই রকম দেখতে, আর ",[94,1067,1068],{},"kubectl apply"," করলে দুটোই একইভাবে কাজ করবে অ্যাপের দৃষ্টিকোণ থেকে। পার্থক্যটা তৈরি হয় ক্লাস্টার-লেভেল কনফিগারেশনে — RBAC পলিসি, encryption at rest, আর অডিট লগিং কোন রিসোর্স টাইপের জন্য কতটা কড়া, তার ওপর।",[108,1071,1072],{},[42,1073,1074,1076],{},[94,1075,1044],{}," ব্যবহার করলে YAML-এ প্লেইন টেক্সটে লেখা যায় (Kubernetes নিজে base64 এনকোড করে নেয়), যেটা সুবিধাজনক — কিন্তু এই ফাইলটা যদি Git রিপোজিটরিতে কমিট হয়ে যায়, পুরো ইতিহাসেই পাসওয়ার্ডটা থেকে যাবে। প্রোডাকশন Secret কখনো plain YAML হিসেবে Git-এ রাখবেন না — এর জন্যই Sealed Secrets, External Secrets Operator, বা HashiCorp Vault-এর মতো টুল আছে।",[54,1078,1080],{"id":1079},"কবে-কোনটা-বাছবেন","কবে কোনটা বাছবেন",[42,1082,1083,1084],{},"সহজ নিয়ম: ",[49,1085,1086],{},"যা প্রকাশ পেলে ক্ষতি হবে, সেটা Secret-এ। যা প্রকাশ পেলে কিছু হবে না, সেটা ConfigMap-এ।",[42,1088,1089],{},"DB পাসওয়ার্ড, API key, TLS সার্টিফিকেটের প্রাইভেট কী, third-party টোকেন — Secret। ফিচার ফ্ল্যাগ, লগ লেভেল, API-র বেস URL, রিট্রাই কাউন্ট — ConfigMap। কোনো একটা ভ্যালু নিয়ে দ্বিধায় থাকলে, ধরে নিন সেটা Secret — পরে ConfigMap-এ সরানো সহজ, উল্টোটা করতে গেলে অনেক আগেই এক্সপোজ হয়ে গিয়ে থাকবে।",[125,1091,1092],{},[42,1093,1094],{},"Secret ব্যবহার করলেও পুরো নিরাপত্তা নিশ্চিত হয় না — সেটা শুধু প্রথম ধাপ। আসল প্রোডাকশন সেটআপে সাধারণত তিনটা জিনিস একসাথে থাকে: etcd encryption at rest চালু, RBAC দিয়ে কড়াকড়ি (কোন Pod\u002FServiceAccount কোন Secret পড়তে পারবে), আর Secret-গুলো Git-এ না রেখে বাইরের কোনো secret manager থেকে সিঙ্ক করা।",[142,1096],{":answer":289,":explanation":1097,":options":1098,"question":1099},"{\"Secret অবজেক্ট base64 এনকোডিং করে রাখে, যেটা এনক্রিপশন নয় — যে কেউ ডিকোড করে ফেলতে পারে। Kubernetes নিজে থেকে \\\"Secret\\\" নামের কারণে বাড়তি কোনো এনক্রিপশন যোগ করে না। আসল সুরক্ষা আসে ক্লাস্টার-লেভেল কনফিগারেশন থেকে\":\"etcd-তে encryption at rest চালু আছে কি না, RBAC দিয়ে কে পড়তে পারবে তা সীমিত করা আছে কি না, আর Secret-গুলো কীভাবে তৈরি\u002Fসিঙ্ক করা হচ্ছে (প্লেইন YAML Git-এ কমিট করা বনাম একটা secret manager থেকে আনা)।\",\"checkLabel\":\"উত্তর মিলিয়ে দেখি\",\"resetLabel\":\"আবার চেষ্টা করি\",\"correctLabel\":\"ঠিক আছে\",\"incorrectLabel\":\"হয়নি\"}","[\"হ্যাঁ, Secret সবসময় এনক্রিপ্টেড থাকে\",\"না, Secret শুধু base64-এনকোডেড — আসল নিরাপত্তা নির্ভর করে RBAC আর encryption at rest ঠিকমতো সেটআপ করা আছে কি না তার ওপর\",\"হ্যাঁ, কিন্তু শুধু Secret-টা namespace-এর বাইরে থাকলে\",\"না, Secret আসলে ConfigMap-এর চেয়ে কম নিরাপদ\"]","একজন ডেভেলপার একটা Kubernetes Secret বানিয়েছেন যাতে API key আছে। এতে কি key-টা নিরাপদ হয়ে গেছে?",[54,1101,1103],{"id":1102},"চেকলিস্ট-নতুন-করে-সেটআপ-করার-আগে","চেকলিস্ট — নতুন করে সেটআপ করার আগে",[157,1105],{":items":1106,"doneLabel":160,"resetLabel":161,"title":1107},"[{\"label\":\"কোনো Secret-এর ভ্যালু ভুল করে ConfigMap-এ চলে যায়নি তো, চেক করুন\",\"detail\":\"grep দিয়ে PASSWORD, TOKEN, KEY, SECRET শব্দগুলো ConfigMap ফাইলগুলোতে খুঁজে দেখুন।\"},{\"label\":\"Git হিস্টোরিতে কোনো Secret YAML কমিট হয়ে আছে কি না দেখুন\",\"detail\":\"একবার কমিট হয়ে গেলে সেই ভ্যালুটা রোটেট (পরিবর্তন) না করলে, শুধু ফাইল ডিলিট করলে সমাধান হয় না।\"},{\"label\":\"etcd-তে encryption at rest চালু আছে কি না নিশ্চিত করুন\",\"detail\":\"ম্যানেজড ক্লাস্টারে (EKS, GKE, AKS) এটা প্রায়ই একটা আলাদা সেটিং, ডিফল্টে চালু নাও থাকতে পারে।\"},{\"label\":\"কোন ServiceAccount\u002FPod কোন Secret পড়তে পারবে, RBAC দিয়ে সীমিত করুন\",\"detail\":\"প্রতিটা Pod-এর সব Secret দেখার দরকার নেই, শুধু যেগুলো তার নিজের।\"},{\"label\":\"Secret রোটেশনের একটা প্ল্যান আছে কি না ভাবুন\",\"detail\":\"কেউ টিম ছাড়লে বা একটা key লিক হলে, সেটা বদলাতে কতক্ষণ লাগবে — সেটাই আসল টেস্ট।\"}]","ConfigMap\u002FSecret সেটআপ রিভিউ করার আগে যা দেখবেন",[42,1109,1110],{},"Secret ব্যবহার করা মানে \"সমস্যা সমাধান হয়ে গেছে\" না — এটা শুধু সঠিক জায়গায় সঠিক প্রশ্নটা জিজ্ঞেস করার সুযোগ তৈরি করে দেয়: এই ডেটাটা কে দেখতে পারবে, আর কীভাবে সেটা নিশ্চিত করছি।",[800,1112,1113],{},"html pre.shiki code .sza-u, html code.shiki .sza-u{--shiki-default:#8DDB8C;--shiki-dark:#8DDB8C}html pre.shiki code .sM9_K, html code.shiki .sM9_K{--shiki-default:#ADBAC7;--shiki-dark:#ADBAC7}html pre.shiki code .szYpP, html code.shiki .szYpP{--shiki-default:#96D0FF;--shiki-dark:#96D0FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":85,"searchDepth":181,"depth":181,"links":1115},[1116,1117,1118,1119],{"id":836,"depth":184,"text":837},{"id":870,"depth":184,"text":871},{"id":1079,"depth":184,"text":1080},{"id":1102,"depth":184,"text":1103},"2026-09-07","দুটোরই কাজ প্রায় একই রকম দেখতে — key-value ডেটা কন্টেইনারে ইনজেক্ট করা। কিন্তু একটাতে DB পাসওয়ার্ড রাখলে সেটা টিমের সবাই plaintext-এ পড়ে ফেলতে পারবে, আরেকটাতেও আসলে পারবে — যদি না আপনি সেটা জানেন।",{},"\u002Fblog\u002Fbn\u002Fconfigmap-vs-secret",{"title":824,"description":1121},"blog\u002Fbn\u002Fconfigmap-vs-secret",[819,820,1127],"Security","1ahVPyYWUYLiXZSoAm5TaJG0XMAHuPkgl54GCxC2t4g",{"id":1130,"title":1131,"author":1132,"body":1135,"category":1534,"cover":190,"coverAlt":190,"date":1535,"description":1536,"draft":6,"extension":193,"featured":6,"lang":194,"meta":1537,"navigation":24,"path":1538,"readingTime":446,"seo":1539,"seoTitle":190,"stem":1540,"tags":1541,"__hash__":1545},"blog\u002Fblog\u002Fbn\u002Fcomponent-margin-ownership.md","কম্পোনেন্টের গায়ে margin দেবেন না",{"name":1133,"role":1134},"নাফিস রহমান","ডিজাইন সিস্টেম লিড",{"type":39,"value":1136,"toc":1527},[1137,1140,1147,1151,1154,1161,1164,1173,1177,1414,1421,1431,1438,1442,1445,1455,1460,1465,1469,1472,1478,1484,1494,1510,1514,1517,1521,1524],[42,1138,1139],{},"একটা কম্পোনেন্ট লাইব্রেরি সাধারণত একভাবেই ভাঙে — এক জায়গায় সুন্দর দেখায়, অন্য জায়গায় বসালেই ফাঁকা জায়গার হিসাব মেলে না।",[42,1141,1142,1143,1146],{},"কারণটা প্রায় সবসময় একই। কার্ডের নিজের CSS-এ ",[94,1144,1145],{},"margin-bottom: 24px"," লেখা আছে।",[54,1148,1150],{"id":1149},"সমস্যাটা-মালিকানার","সমস্যাটা মালিকানার",[42,1152,1153],{},"একটা কম্পোনেন্টের ভেতরের ফাঁকা জায়গা — প্যাডিং, আইকন আর লেখার দূরত্ব, শিরোনাম আর বডির গ্যাপ — কম্পোনেন্টেরই সম্পত্তি। ওটা তার ডিজাইনের অংশ, সব জায়গায় এক থাকা উচিত।",[42,1155,1156,1157,1160],{},"কিন্তু কম্পোনেন্টের ",[49,1158,1159],{},"বাইরের"," ফাঁকা জায়গা তার নয়। ওটা লেআউটের সিদ্ধান্ত, আর লেআউট জানে কম্পোনেন্টটা কোথায় বসছে — গ্রিডে, সাইডবারে, নাকি ডায়ালগের ভেতরে একা। কম্পোনেন্ট সেটা জানে না, জানার কথাও না।",[42,1162,1163],{},"চাইল্ড যখন নিজের বাইরের মার্জিন নিজে ঠিক করে, তখন সে এমন একটা প্রশ্নের উত্তর দিয়ে ফেলে যেটা তাকে কেউ করেনি।",[66,1165,1166],{},[42,1167,1168,1169,1172],{},"নিয়মটা এক লাইনে: ",[49,1170,1171],{},"প্যাডিং ভেতরের দিকে তাকায়, মার্জিন বাইরের দিকে।"," ভেতরের দিকের সবকিছু কম্পোনেন্টের, বাইরের দিকের সবকিছু প্যারেন্টের।",[54,1174,1176],{"id":1175},"কোডে-পার্থক্যটা","কোডে পার্থক্যটা",[76,1178,1183,1315],{"after":1179,"before":1180,"note":1181,"split":1182},"প্যারেন্ট গ্যাপ দিচ্ছে","চাইল্ড মার্জিন দিচ্ছে","দ্বিতীয়টায় কার্ড নিজে জানে না তার পরে আর কিছু আছে কি না — আর সেটাই ঠিক।","দুটোই",[83,1184,1185],{"v-slot:before":85},[87,1186,1190],{"className":1187,"code":1188,"language":1189,"meta":85,"style":85},"language-vue shiki shiki-themes github-dark-dimmed github-dark-dimmed","\u003C!-- Card.vue -->\n\u003Ctemplate>\n  \u003Carticle class=\"mb-6 rounded-xl border p-5\">\n    \u003Cslot \u002F>\n  \u003C\u002Farticle>\n\u003C\u002Ftemplate>\n\n\u003C!-- ব্যবহার -->\n\u003CCard v-for=\"item in items\" :key=\"item.id\" \u002F>\n","vue",[94,1191,1192,1198,1208,1227,1241,1250,1259,1264,1269],{"__ignoreMap":85},[551,1193,1194],{"class":553,"line":554},[551,1195,1197],{"class":1196},"s0RzX","\u003C!-- Card.vue -->\n",[551,1199,1200,1203,1205],{"class":553,"line":184},[551,1201,1202],{"class":561},"\u003C",[551,1204,83],{"class":557},[551,1206,1207],{"class":561},">\n",[551,1209,1210,1213,1216,1219,1222,1225],{"class":553,"line":181},[551,1211,1212],{"class":561},"  \u003C",[551,1214,1215],{"class":557},"article",[551,1217,1218],{"class":573}," class",[551,1220,1221],{"class":561},"=",[551,1223,1224],{"class":592},"\"mb-6 rounded-xl border p-5\"",[551,1226,1207],{"class":561},[551,1228,1229,1232,1235,1239],{"class":553,"line":584},[551,1230,1231],{"class":561},"    \u003C",[551,1233,1234],{"class":557},"slot",[551,1236,1238],{"class":1237},"skSX4"," \u002F",[551,1240,1207],{"class":561},[551,1242,1243,1246,1248],{"class":553,"line":596},[551,1244,1245],{"class":561},"  \u003C\u002F",[551,1247,1215],{"class":557},[551,1249,1207],{"class":561},[551,1251,1252,1255,1257],{"class":553,"line":604},[551,1253,1254],{"class":561},"\u003C\u002F",[551,1256,83],{"class":557},[551,1258,1207],{"class":561},[551,1260,1261],{"class":553,"line":446},[551,1262,1263],{"emptyLinePlaceholder":24},"\n",[551,1265,1266],{"class":553,"line":197},[551,1267,1268],{"class":1196},"\u003C!-- ব্যবহার -->\n",[551,1270,1272,1274,1277,1281,1283,1286,1289,1292,1295,1297,1300,1303,1305,1307,1310,1312],{"class":553,"line":1271},9,[551,1273,1202],{"class":561},[551,1275,1276],{"class":557},"Card",[551,1278,1280],{"class":1279},"sEYkB"," v-for",[551,1282,1221],{"class":561},[551,1284,1285],{"class":561},"\"",[551,1287,1288],{"class":561},"item ",[551,1290,1291],{"class":1279},"in",[551,1293,1294],{"class":561}," items",[551,1296,1285],{"class":561},[551,1298,1299],{"class":561}," :",[551,1301,1302],{"class":573},"key",[551,1304,1221],{"class":561},[551,1306,1285],{"class":561},[551,1308,1309],{"class":561},"item.id",[551,1311,1285],{"class":561},[551,1313,1314],{"class":561}," \u002F>\n",[83,1316,1317],{"v-slot:after":85},[87,1318,1320],{"className":1187,"code":1319,"language":1189,"meta":85,"style":85},"\u003C!-- Card.vue -->\n\u003Ctemplate>\n  \u003Carticle class=\"rounded-xl border p-5\">\n    \u003Cslot \u002F>\n  \u003C\u002Farticle>\n\u003C\u002Ftemplate>\n\n\u003C!-- ব্যবহার -->\n\u003Cdiv class=\"flex flex-col gap-6\">\n  \u003CCard v-for=\"item in items\" :key=\"item.id\" \u002F>\n\u003C\u002Fdiv>\n",[94,1321,1322,1326,1334,1349,1359,1367,1375,1379,1383,1399,1405],{"__ignoreMap":85},[551,1323,1324],{"class":553,"line":554},[551,1325,1197],{"class":1196},[551,1327,1328,1330,1332],{"class":553,"line":184},[551,1329,1202],{"class":561},[551,1331,83],{"class":557},[551,1333,1207],{"class":561},[551,1335,1336,1338,1340,1342,1344,1347],{"class":553,"line":181},[551,1337,1212],{"class":561},[551,1339,1215],{"class":557},[551,1341,1218],{"class":573},[551,1343,1221],{"class":561},[551,1345,1346],{"class":592},"\"rounded-xl border p-5\"",[551,1348,1207],{"class":561},[551,1350,1351,1353,1355,1357],{"class":553,"line":584},[551,1352,1231],{"class":561},[551,1354,1234],{"class":557},[551,1356,1238],{"class":1237},[551,1358,1207],{"class":561},[551,1360,1361,1363,1365],{"class":553,"line":596},[551,1362,1245],{"class":561},[551,1364,1215],{"class":557},[551,1366,1207],{"class":561},[551,1368,1369,1371,1373],{"class":553,"line":604},[551,1370,1254],{"class":561},[551,1372,83],{"class":557},[551,1374,1207],{"class":561},[551,1376,1377],{"class":553,"line":446},[551,1378,1263],{"emptyLinePlaceholder":24},[551,1380,1381],{"class":553,"line":197},[551,1382,1268],{"class":1196},[551,1384,1385,1387,1390,1392,1394,1397],{"class":553,"line":1271},[551,1386,1202],{"class":561},[551,1388,1389],{"class":557},"div",[551,1391,1218],{"class":573},[551,1393,1221],{"class":561},[551,1395,1396],{"class":592},"\"flex flex-col gap-6\"",[551,1398,1207],{"class":561},[551,1400,1402],{"class":553,"line":1401},10,[551,1403,1404],{"class":561},"  \u003CCard v-for=\"item in items\" :key=\"item.id\" \u002F>\n",[551,1406,1408,1410,1412],{"class":553,"line":1407},11,[551,1409,1254],{"class":561},[551,1411,1389],{"class":557},[551,1413,1207],{"class":561},[42,1415,1416,1417,1420],{},"প্রথমটায় লিস্টের শেষ কার্ডের নিচেও ২৪ পিক্সেল ঝুলে থাকে, যেটা কেউ চায়নি। ঠিক করতে গিয়ে ",[94,1418,1419],{},":last-child { margin-bottom: 0 }"," লেখা হয়, তারপর গ্রিডে বসালে আবার অন্য নিয়ম, তারপর ডায়ালগে আরেকটা। তিনটা ব্যতিক্রম লেখার পর কম্পোনেন্টটার স্পেসিং আর কেউ পড়ে বুঝতে পারে না।",[42,1422,1423,1424,1427,1428,1430],{},"দ্বিতীয়টায় ব্যতিক্রম নেই, কারণ নিয়মটাই নেই। প্যারেন্ট ",[94,1425,1426],{},"gap"," দিচ্ছে, শেষ আইটেমের পরে গ্যাপ বসে না — এটা ",[94,1429,1426],{},"-এর সংজ্ঞা, কারও লেখা নিয়ম নয়।",[125,1432,1433],{},[42,1434,1435,1437],{},[94,1436,1426],{}," শুধু ফ্লেক্স আর গ্রিডে কাজ করে, আর সেটাই এর সবচেয়ে বড় সুবিধা। মার্জিন যেকোনো জায়গায় বসানো যায় বলেই যেকোনো জায়গায় ভুল হতে পারে।",[54,1439,1441],{"id":1440},"মার্জিন-কলাপস-আরেকটা-কারণ","মার্জিন কলাপস আরেকটা কারণ",[42,1443,1444],{},"লম্বালম্বি মার্জিন পাশাপাশি বসলে দুটো যোগ হয় না, বড়টা টিকে থাকে। এটা CSS-এর পুরোনো আচরণ, ভুল নয় — কিন্তু কম্পোনেন্ট লেখার সময় এটাই সবচেয়ে বেশি বিভ্রান্ত করে।",[42,1446,1447,1448,1450,1451,1454],{},"উপরের কার্ডের ",[94,1449,1145],{}," আর নিচের কার্ডের ",[94,1452,1453],{},"margin-top: 16px"," মিলে ফাঁক হয় ২৪, ৪০ নয়। মানে আপনি যে সংখ্যাটা লিখেছেন, স্ক্রিনে সেটা নাও থাকতে পারে — নির্ভর করছে প্রতিবেশী কে।",[42,1456,1457,1459],{},[94,1458,1426],{}," কলাপস করে না। যা লিখবেন তাই পাবেন।",[142,1461],{":answer":144,":options":1462,"checkLabel":146,"correctLabel":147,"explanation":1463,"incorrectLabel":149,"question":1464,"resetLabel":151},"[\"১৬px — গ্রিডের gap মার্জিনকে বাতিল করে দেয়\",\"২৪px — মার্জিন আর gap কলাপস করে বড়টা থাকে\",\"৪০px — gap আর মার্জিন যোগ হয়\",\"২০px — দুটোর গড়\"]","গ্রিড আর ফ্লেক্স আইটেমে মার্জিন কলাপস হয় না, তাই gap-এর ১৬px-এর সাথে কার্ডের নিজের ২৪px যোগ হয়ে ৪০px দাঁড়ায়। একই কম্পোনেন্ট ফ্লো লেআউটে বসালে উত্তর হতো ২৪ — অর্থাৎ ফাঁকা জায়গাটা কম্পোনেন্টের নয়, তার প্রতিবেশীর উপর নির্ভরশীল। এটাই মার্জিন এড়ানোর মূল যুক্তি।","একটা কার্ড কম্পোনেন্টে `margin-bottom: 24px` দেওয়া আছে। সেটাকে একটা `display: grid` কন্টেইনারে `gap: 16px` দিয়ে বসানো হলো। দুটো কার্ডের মাঝে ফাঁক কত হবে?",[54,1466,1468],{"id":1467},"ভেতরের-স্পেসিং-অবশ্যই-কম্পোনেন্টের","ভেতরের স্পেসিং অবশ্যই কম্পোনেন্টের",[42,1470,1471],{},"উল্টো দিকটাও সমান গুরুত্বপূর্ণ। কম্পোনেন্টের ভেতরের প্যাডিং প্যারেন্টের হাতে ছেড়ে দিলে একই বোতাম দশ জায়গায় দশ রকম হয়।",[42,1473,1474,1477],{},[94,1475,1476],{},"size"," একটা বন্ধ তালিকা হওয়া উচিত — তিনটা মান, তিনটাই কম্পোনেন্টের ভেতরে লেখা। বাইরে থেকে ক্লাস দিয়ে প্যাডিং বদলানো মানে তালিকার বাইরে একটা চতুর্থ সাইজ তৈরি করা, যেটা কোথাও লেখা নেই:",[1479,1480],"playground",{":controls":1481,"component":1482,"label":1483},"[{\"prop\":\"size\",\"options\":[\"sm\",\"md\",\"lg\"]},{\"prop\":\"variant\",\"options\":[\"primary\",\"outline\",\"ghost\"]}]","button","সংরক্ষণ করুন",[42,1485,1486,1487,1490,1491,1493],{},"উপরের প্রতিটা অবস্থার জন্য নিচে যে মার্কআপটা দেখাচ্ছে, সেটাই যথেষ্ট। কোনো ",[94,1488,1489],{},"class=\"px-6\""," নেই — কারণ দরকার হলে সেটা ",[94,1492,1476],{},"-এর তালিকায় যোগ করার আলোচনা, ব্যবহারের জায়গায় চুপচাপ ওভাররাইড নয়।",[108,1495,1496],{},[42,1497,1498,1501,1502,1505,1506,1509],{},[94,1499,1500],{},"class"," প্রপ রাখা দরকার, কিন্তু সেটা অবস্থানের জন্য — ",[94,1503,1504],{},"w-full",", ",[94,1507,1508],{},"self-end",", গ্রিডের কলাম স্প্যান। ভেতরের প্যাডিং বা ফন্ট সাইজ ওভাররাইড করার জন্য নয়। দুটোর পার্থক্য রিভিউতে ধরা সহজ, কোডে নয়।",[54,1511,1513],{"id":1512},"পুরোনো-কোডে-কীভাবে-ঢুকবেন","পুরোনো কোডে কীভাবে ঢুকবেন",[42,1515,1516],{},"একবারে সব বদলানোর দরকার নেই। যে কম্পোনেন্টটা সবচেয়ে বেশি জায়গায় ব্যবহার হয়েছে, সেটা দিয়ে শুরু করলেই সবচেয়ে বেশি ব্যতিক্রম মুছে যায়।",[157,1518],{":items":1519,"doneLabel":160,"resetLabel":161,"title":1520},"[{\"label\":\"কম্পোনেন্টের বাইরের সব margin খুঁজে বের করুন\",\"detail\":\"mb-, mt-, my- আর :last-child ব্যতিক্রমগুলো একসাথে।\"},{\"label\":\"প্রতিটা ব্যবহারের জায়গা তালিকা করুন\",\"detail\":\"গ্রেপ করলেই পাওয়া যায় — এখান থেকেই বোঝা যাবে কয়টা লেআউট আসলে আছে।\"},{\"label\":\"প্যারেন্টে flex\u002Fgrid আর gap বসান\",\"detail\":\"মার্জিনের যে মানটা ছিল, সেটাই gap-এ যাবে — নতুন সংখ্যা বানানোর দরকার নেই।\"},{\"label\":\"এবার কম্পোনেন্ট থেকে margin মুছুন\",\"detail\":\"আগে নয়। আগে মুছলে মাঝের কমিটে লেআউট ভাঙা থাকে।\"},{\"label\":\"last-child ব্যতিক্রমগুলো মুছুন\",\"detail\":\"এগুলো টিকে থাকলে বুঝতে হবে কোথাও মার্জিন রয়ে গেছে।\"},{\"label\":\"সরু স্ক্রিনে একবার দেখুন\",\"detail\":\"gap দুই দিকেই কাজ করে, তাই কলাম ভেঙে গেলে হিসাব বদলায়।\"}]","একটা কম্পোনেন্ট থেকে মার্জিন সরানোর ধাপ",[42,1522,1523],{},"কাজটা ছোট, কিন্তু ফলটা কোড কমার চেয়ে বড়। এরপর থেকে কেউ কম্পোনেন্টটা নতুন কোনো জায়গায় বসালে তাকে আর জিজ্ঞেস করতে হয় না, \"এটার নিচে কি এমনিতেই ফাঁক আছে?\"",[800,1525,1526],{},"html pre.shiki code .s0RzX, html code.shiki .s0RzX{--shiki-default:#768390;--shiki-dark:#768390}html pre.shiki code .sM9_K, html code.shiki .sM9_K{--shiki-default:#ADBAC7;--shiki-dark:#ADBAC7}html pre.shiki code .sza-u, html code.shiki .sza-u{--shiki-default:#8DDB8C;--shiki-dark:#8DDB8C}html pre.shiki code .sQdni, html code.shiki .sQdni{--shiki-default:#6CB6FF;--shiki-dark:#6CB6FF}html pre.shiki code .szYpP, html code.shiki .szYpP{--shiki-default:#96D0FF;--shiki-dark:#96D0FF}html pre.shiki code .skSX4, html code.shiki .skSX4{--shiki-default:#FF938A;--shiki-default-font-style:italic;--shiki-dark:#FF938A;--shiki-dark-font-style:italic}html pre.shiki code .sEYkB, html code.shiki .sEYkB{--shiki-default:#F47067;--shiki-dark:#F47067}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":85,"searchDepth":181,"depth":181,"links":1528},[1529,1530,1531,1532,1533],{"id":1149,"depth":184,"text":1150},{"id":1175,"depth":184,"text":1176},{"id":1440,"depth":184,"text":1441},{"id":1467,"depth":184,"text":1468},{"id":1512,"depth":184,"text":1513},"web-development","2026-09-06","ফাঁকা জায়গার মালিক প্যারেন্ট, চাইল্ড নয়। একটা কম্পোনেন্ট নিজের বাইরের মার্জিন নিজে ঠিক করলে সেটা আর যেকোনো জায়গায় বসানো যায় না।",{},"\u002Fblog\u002Fbn\u002Fcomponent-margin-ownership",{"title":1131,"description":1536},"blog\u002Fbn\u002Fcomponent-margin-ownership",[1542,1543,1544],"CSS","লেআউট","কম্পোনেন্ট","8rjBjFFzefhZZ6SjjDHL64MrE_oUUP0P5go4GZiR5Mk",{"id":1547,"title":1548,"author":1549,"body":1550,"category":810,"cover":190,"coverAlt":190,"date":1535,"description":1867,"draft":6,"extension":193,"featured":6,"lang":194,"meta":1868,"navigation":24,"path":500,"readingTime":197,"seo":1869,"seoTitle":190,"stem":1870,"tags":1871,"__hash__":1873},"blog\u002Fblog\u002Fbn\u002Fkubernetes-liveness-readiness-probe.md","Pod রানিং দেখাচ্ছে, তবু ট্রাফিক পাচ্ছে না — কেন",{"name":457,"role":458},{"type":39,"value":1551,"toc":1861},[1552,1569,1577,1581,1584,1590,1596,1599,1608,1612,1787,1801,1809,1813,1820,1839,1844,1848,1852,1858],[42,1553,1554,1556,1557,729,1560,1505,1563,729,1566,1568],{},[94,1555,469],{}," চালালে সবকিছু ঠিক দেখায়। ",[94,1558,1559],{},"STATUS",[94,1561,1562],{},"Running",[94,1564,1565],{},"RESTARTS",[94,1567,530],{},"। কিন্তু ব্রাউজারে সাইট খুললে 502, আর লগে নতুন কোনো এরর নেই — কারণ অ্যাপটা তো ক্র্যাশই করেনি।",[42,1570,1571,1572],{},"এই একটা লাইন বোঝা গেলে সমস্যাটা এক মিনিটে সমাধান হয়ে যায়: ",[49,1573,1574,1576],{},[94,1575,1562],{}," মানে শুধু কন্টেইনারের প্রসেস চালু আছে। অ্যাপটা যে রিকোয়েস্ট নেওয়ার জন্য প্রস্তুত, সেটার কোনো গ্যারান্টি এতে নেই।",[54,1578,1580],{"id":1579},"দুটো-আলাদা-প্রশ্ন","দুটো আলাদা প্রশ্ন",[42,1582,1583],{},"Kubernetes একটা Pod সম্পর্কে দুটো সম্পূর্ণ আলাদা প্রশ্ন জিজ্ঞেস করতে পারে, আর দুটোর উত্তর দুই জায়গায় ব্যবহার হয়।",[42,1585,1586,1589],{},[49,1587,1588],{},"লাইভনেস (liveness):"," প্রসেসটা কি বেঁচে আছে, নাকি ডেডলক হয়ে গেছে? উত্তর \"না\" হলে kubelet কন্টেইনারটা রিস্টার্ট করে দেয়।",[42,1591,1592,1595],{},[49,1593,1594],{},"রেডিনেস (readiness):"," প্রসেসটা কি এখন রিকোয়েস্ট নেওয়ার মতো অবস্থায় আছে? উত্তর \"না\" হলে Pod-টাকে Service-এর endpoint লিস্ট থেকে সরিয়ে দেওয়া হয় — কিন্তু রিস্টার্ট করা হয় না।",[42,1597,1598],{},"এই দ্বিতীয়টাই বেশিরভাগ ডিবাগিং সেশনে মিসিং থাকে। একটা অ্যাপ চালু হতে ১৫ সেকেন্ড লাগে — DB কানেকশন পুল বানায়, ক্যাশ ওয়ার্ম করে। সেই ১৫ সেকেন্ডে প্রসেসটা \"জীবিত\" ঠিকই, কিন্তু রিকোয়েস্ট নেওয়ার জন্য প্রস্তুত না। readiness probe না থাকলে Service সেই Pod-টাকেই ট্রাফিক পাঠাতে শুরু করে দেয়, আর ইউজার 502 পায়।",[66,1600,1601],{},[42,1602,1603,1604,1607],{},"মনে রাখার সহজ উপায়: ",[49,1605,1606],{},"লাইভনেস ফেইল করলে রিস্টার্ট, রেডিনেস ফেইল করলে ট্রাফিক থেকে বাদ।"," একটা প্রসেস মেরে ফেলার সিদ্ধান্ত, আরেকটা শুধু সাময়িকভাবে সরিয়ে রাখার সিদ্ধান্ত।",[54,1609,1611],{"id":1610},"কনফিগে-পার্থক্য","কনফিগে পার্থক্য",[76,1613,1617,1678],{"after":1614,"before":1615,"note":1616,"split":1182},"liveness + readiness","শুধু liveness","দ্বিতীয়টায় স্টার্টআপের সময় Pod ট্রাফিক পায় না, যতক্ষণ না \u002Fready নিজে থেকে বলছে সে প্রস্তুত।",[83,1618,1619],{"v-slot:before":85},[87,1620,1622],{"className":545,"code":1621,"language":547,"meta":85,"style":85},"livenessProbe:\n  httpGet:\n    path: \u002Fhealth\n    port: 8080\n  initialDelaySeconds: 5\n  periodSeconds: 10\n",[94,1623,1624,1631,1638,1648,1658,1668],{"__ignoreMap":85},[551,1625,1626,1629],{"class":553,"line":554},[551,1627,1628],{"class":557},"livenessProbe",[551,1630,562],{"class":561},[551,1632,1633,1636],{"class":553,"line":184},[551,1634,1635],{"class":557},"  httpGet",[551,1637,562],{"class":561},[551,1639,1640,1643,1645],{"class":553,"line":181},[551,1641,1642],{"class":557},"    path",[551,1644,570],{"class":561},[551,1646,1647],{"class":592},"\u002Fhealth\n",[551,1649,1650,1653,1655],{"class":553,"line":584},[551,1651,1652],{"class":557},"    port",[551,1654,570],{"class":561},[551,1656,1657],{"class":573},"8080\n",[551,1659,1660,1663,1665],{"class":553,"line":596},[551,1661,1662],{"class":557},"  initialDelaySeconds",[551,1664,570],{"class":561},[551,1666,1667],{"class":573},"5\n",[551,1669,1670,1673,1675],{"class":553,"line":604},[551,1671,1672],{"class":557},"  periodSeconds",[551,1674,570],{"class":561},[551,1676,1677],{"class":573},"10\n",[83,1679,1680],{"v-slot:after":85},[87,1681,1683],{"className":545,"code":1682,"language":547,"meta":85,"style":85},"livenessProbe:\n  httpGet:\n    path: \u002Fhealth\n    port: 8080\n  initialDelaySeconds: 5\n  periodSeconds: 10\nreadinessProbe:\n  httpGet:\n    path: \u002Fready\n    port: 8080\n  initialDelaySeconds: 5\n  periodSeconds: 5\n  failureThreshold: 3\n",[94,1684,1685,1691,1697,1705,1713,1721,1729,1736,1742,1751,1759,1767,1776],{"__ignoreMap":85},[551,1686,1687,1689],{"class":553,"line":554},[551,1688,1628],{"class":557},[551,1690,562],{"class":561},[551,1692,1693,1695],{"class":553,"line":184},[551,1694,1635],{"class":557},[551,1696,562],{"class":561},[551,1698,1699,1701,1703],{"class":553,"line":181},[551,1700,1642],{"class":557},[551,1702,570],{"class":561},[551,1704,1647],{"class":592},[551,1706,1707,1709,1711],{"class":553,"line":584},[551,1708,1652],{"class":557},[551,1710,570],{"class":561},[551,1712,1657],{"class":573},[551,1714,1715,1717,1719],{"class":553,"line":596},[551,1716,1662],{"class":557},[551,1718,570],{"class":561},[551,1720,1667],{"class":573},[551,1722,1723,1725,1727],{"class":553,"line":604},[551,1724,1672],{"class":557},[551,1726,570],{"class":561},[551,1728,1677],{"class":573},[551,1730,1731,1734],{"class":553,"line":446},[551,1732,1733],{"class":557},"readinessProbe",[551,1735,562],{"class":561},[551,1737,1738,1740],{"class":553,"line":197},[551,1739,1635],{"class":557},[551,1741,562],{"class":561},[551,1743,1744,1746,1748],{"class":553,"line":1271},[551,1745,1642],{"class":557},[551,1747,570],{"class":561},[551,1749,1750],{"class":592},"\u002Fready\n",[551,1752,1753,1755,1757],{"class":553,"line":1401},[551,1754,1652],{"class":557},[551,1756,570],{"class":561},[551,1758,1657],{"class":573},[551,1760,1761,1763,1765],{"class":553,"line":1407},[551,1762,1662],{"class":557},[551,1764,570],{"class":561},[551,1766,1667],{"class":573},[551,1768,1770,1772,1774],{"class":553,"line":1769},12,[551,1771,1672],{"class":557},[551,1773,570],{"class":561},[551,1775,1667],{"class":573},[551,1777,1779,1782,1784],{"class":553,"line":1778},13,[551,1780,1781],{"class":557},"  failureThreshold",[551,1783,570],{"class":561},[551,1785,1786],{"class":573},"3\n",[42,1788,1789,1790,1793,1794,863,1797,1800],{},"দুটো আলাদা এন্ডপয়েন্ট রাখাটা ইচ্ছাকৃত। ",[94,1791,1792],{},"\u002Fhealth"," শুধু বলে প্রসেসটা বেঁচে আছে কি না — সাধারণত একটা স্ট্যাটিক ",[94,1795,1796],{},"200 OK",[94,1798,1799],{},"\u002Fready"," আসল কাজ করে: DB কানেকশন আছে কি না, প্রয়োজনীয় ক্যাশ লোড হয়েছে কি না, সেটা চেক করে তারপর উত্তর দেয়। দুটো একই এন্ডপয়েন্টে বেঁধে ফেললে DB কানেকশন সাময়িকভাবে হারালে পুরো Pod-টাই রিস্টার্ট হতে থাকবে — যেটার দরকার ছিল না, শুধু ট্রাফিক সরিয়ে রাখলেই চলত।",[108,1802,1803],{},[42,1804,1805,1808],{},[94,1806,1807],{},"initialDelaySeconds"," কম রাখলে একটা ধীরে-শুরু-হওয়া অ্যাপ নিজের readiness probe ফেইল করতে করতেই বারবার রিস্টার্ট খেতে থাকে (liveness probe সেটাকে \"ডেড\" ভেবে বসে) — CrashLoopBackOff-এর একটা বড় কারণ এটাই, অ্যাপ আসলে ক্র্যাশই করছে না।",[54,1810,1812],{"id":1811},"স্লো-স্টার্ট-অ্যাপের-জন্য-আরেকটা-প্রোব","স্লো-স্টার্ট অ্যাপের জন্য আরেকটা প্রোব",[42,1814,1815,1816,1819],{},"যেসব অ্যাপ চালু হতে বেশি সময় নেয় — বড় Java অ্যাপ্লিকেশন, ভারী মাইগ্রেশন চালায় এমন সার্ভিস — তাদের জন্য ",[94,1817,1818],{},"startupProbe"," আলাদা রাখা ভালো। এটা পাস না হওয়া পর্যন্ত liveness আর readiness প্রোব শুরুই হয় না, তাই স্টার্টআপের ধীর গতিকে \"ক্র্যাশ\" ভেবে ভুল করার সুযোগ থাকে না।",[125,1821,1822],{},[42,1823,1824,1825,1827,1828,1830,1831,1834,1835,1838],{},"তিনটা প্রোবের জন্য তিনটা আলাদা এন্ডপয়েন্ট বানানোর দরকার নেই। ",[94,1826,1818],{}," প্রায়ই ",[94,1829,1733],{},"-এর মতোই এন্ডপয়েন্ট ব্যবহার করে, শুধু ",[94,1832,1833],{},"failureThreshold"," বেশি আর ",[94,1836,1837],{},"periodSeconds"," কম রেখে — স্লো স্টার্টআপকে বেশি সময় দেওয়ার জন্য।",[142,1840],{":answer":289,":options":1841,"checkLabel":146,"correctLabel":147,"explanation":1842,"incorrectLabel":149,"question":1843,"resetLabel":151},"[\"Pod-টা রিস্টার্ট করবে\",\"Pod-টাকে Service-এর endpoint থেকে সরিয়ে দেবে, রিস্টার্ট করবে না\",\"কিছুই করবে না, শুধু লগে ওয়ার্নিং লিখবে\",\"পুরো Deployment রোলব্যাক করে দেবে\"]","readiness আর liveness সম্পূর্ণ আলাদা সিদ্ধান্ত নেয়। liveness পাস করছে মানে প্রসেসটা বেঁচে আছে, তাই রিস্টার্ট করার কোনো কারণ নেই। readiness ফেইল করছে মানে এই মুহূর্তে ট্রাফিক নেওয়ার মতো অবস্থায় নেই, তাই Service তাকে সাময়িকভাবে বাদ দেয়। প্রসেসটা বেঁচে থেকেই এই বাদ পড়া থেকে ফিরে আসতে পারে — পরের সফল readiness চেকেই আবার endpoint লিস্টে যোগ হয়ে যাবে।","একটা Pod-এর readinessProbe তিনবার ফেইল করেছে, কিন্তু livenessProbe পাস করছে। Kubernetes কী করবে?",[54,1845,1847],{"id":1846},"pod-ট্রাফিক-না-পেলে-যা-চেক-করবেন","Pod ট্রাফিক না পেলে যা চেক করবেন",[157,1849],{":items":1850,"doneLabel":160,"resetLabel":161,"title":1851},"[{\"label\":\"kubectl describe pod \u003Cname> চালিয়ে Events সেকশন দেখুন\",\"detail\":\"readiness probe ফেইল করলে এখানেই প্রথম দেখা যাবে।\"},{\"label\":\"kubectl get endpoints \u003Cservice> চেক করুন\",\"detail\":\"Pod-টার IP যদি লিস্টে না থাকে, তাহলে সে ট্রাফিকই পাচ্ছে না — এটাই নিশ্চিত করার প্রথম ধাপ।\"},{\"label\":\"readiness আর liveness একই এন্ডপয়েন্ট ব্যবহার করছে কি না দেখুন\",\"detail\":\"করলে সেটাই সবচেয়ে বড় সন্দেহভাজন।\"},{\"label\":\"initialDelaySeconds অ্যাপের আসল স্টার্টআপ টাইমের সাথে মিলিয়ে দেখুন\",\"detail\":\"অ্যাপ যদি ১৫ সেকেন্ডে চালু হয় আর delay থাকে ৫ সেকেন্ড, সমস্যাটা এখানেই।\"},{\"label\":\"\u002Fready এন্ডপয়েন্ট নিজে curl করে দেখুন Pod-এর ভেতর থেকে\",\"detail\":\"kubectl exec দিয়ে ঢুকে curl localhost:PORT\u002Fready — Kubernetes যা দেখছে সেটাই সরাসরি দেখা যাবে।\"}]","Running অথচ ট্রাফিক পাচ্ছে না — ডিবাগিং অর্ডার",[42,1853,1854,1855,1857],{},"এরপর থেকে ",[94,1856,1562],{}," দেখলেই আর ভরসা করার দরকার নেই। প্রশ্নটা হবে — কোন প্রোব, কী বলছে।",[800,1859,1860],{},"html pre.shiki code .sza-u, html code.shiki .sza-u{--shiki-default:#8DDB8C;--shiki-dark:#8DDB8C}html pre.shiki code .sM9_K, html code.shiki .sM9_K{--shiki-default:#ADBAC7;--shiki-dark:#ADBAC7}html pre.shiki code .szYpP, html code.shiki .szYpP{--shiki-default:#96D0FF;--shiki-dark:#96D0FF}html pre.shiki code .sQdni, html code.shiki .sQdni{--shiki-default:#6CB6FF;--shiki-dark:#6CB6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":85,"searchDepth":181,"depth":181,"links":1862},[1863,1864,1865,1866],{"id":1579,"depth":184,"text":1580},{"id":1610,"depth":184,"text":1611},{"id":1811,"depth":184,"text":1812},{"id":1846,"depth":184,"text":1847},"kubectl get pods বলছে Running, অথচ ইউজার 502 পাচ্ছে। কারণটা Kubernetes-এর দোষ না — কেউ liveness আর readiness probe-এর পার্থক্যটা কখনো বুঝিয়ে দেয়নি।",{},{"title":1548,"description":1867},"blog\u002Fbn\u002Fkubernetes-liveness-readiness-probe",[819,820,1872],"Probe","lPq5RJVIEmzpDHe9ypVgCcG1_TNNqGf7Dttcjmbq08Y",{"id":1875,"title":1876,"author":1877,"body":1880,"category":2833,"cover":2834,"coverAlt":1876,"date":2835,"description":2836,"draft":6,"extension":193,"featured":24,"lang":194,"meta":2837,"navigation":24,"path":2838,"readingTime":1271,"seo":2839,"seoTitle":190,"stem":2840,"tags":2841,"__hash__":2844},"blog\u002Fblog\u002Fbn\u002Fbangla-typography-on-the-web.md","ওয়েবে বাংলা টাইপোগ্রাফি — যে সমস্যাগুলো নিয়ে কেউ লেখে না",{"name":1878,"role":1879},"তাসনিম আরা","প্রোডাক্ট ডিজাইনার",{"type":39,"value":1881,"toc":2823},[1882,1885,1888,1892,1895,1938,1945,2061,2068,2073,2076,2121,2124,2127,2187,2190,2194,2197,2204,2256,2263,2270,2273,2371,2378,2382,2389,2400,2469,2472,2476,2479,2517,2525,2529,2532,2535,2571,2574,2581,2766,2769,2773,2780,2809,2820],[42,1883,1884],{},"একটা ডিজাইন সিস্টেম ল্যাটিন স্ক্রিপ্টের জন্য বানানো হলে সেটা বাংলায় ভাঙে — কিন্তু এমনভাবে ভাঙে যে প্রথম দেখায় বোঝা যায় না। পেজ লোড হয়, লেখা পড়া যায়, কিছু একটা \"ঠিক লাগছে না\" — এইটুকুই।",[42,1886,1887],{},"এই সাইটে বাংলা ট্র্যাক যোগ করতে গিয়ে যে পাঁচটা জিনিস আলাদা করে ঠিক করতে হয়েছিল, সেগুলোই এখানে। প্রতিটার কারণ স্ক্রিপ্টের গঠনে, রুচিতে নয়।",[54,1889,1891],{"id":1890},"১-ফন্টে-গ্লিফই-নেই","১. ফন্টে গ্লিফই নেই",[42,1893,1894],{},"সবচেয়ে বড় সমস্যাটা সবচেয়ে সহজ। Inter, Geist, Satoshi — এদের কারও মধ্যে বাংলা গ্লিফ নেই। বাংলা লেখা এই ফন্টে রেন্ডার করতে দিলে ব্রাউজার fallback খোঁজে, আর সেটা যা পায় তা-ই দেখায়: সিস্টেম ফন্ট, বা টোফু বক্স।",[87,1896,1900],{"className":1897,"code":1898,"language":1899,"meta":85,"style":85},"language-css shiki shiki-themes github-dark-dimmed github-dark-dimmed","\u002F* যথেষ্ট নয় *\u002F\nbody {\n  font-family: 'Inter', sans-serif;\n}\n","css",[94,1901,1902,1907,1915,1933],{"__ignoreMap":85},[551,1903,1904],{"class":553,"line":554},[551,1905,1906],{"class":1196},"\u002F* যথেষ্ট নয় *\u002F\n",[551,1908,1909,1912],{"class":553,"line":184},[551,1910,1911],{"class":557},"body",[551,1913,1914],{"class":561}," {\n",[551,1916,1917,1920,1922,1925,1927,1930],{"class":553,"line":181},[551,1918,1919],{"class":573},"  font-family",[551,1921,570],{"class":561},[551,1923,1924],{"class":592},"'Inter'",[551,1926,1505],{"class":561},[551,1928,1929],{"class":573},"sans-serif",[551,1931,1932],{"class":561},";\n",[551,1934,1935],{"class":553,"line":584},[551,1936,1937],{"class":561},"}\n",[42,1939,1940,1941,1944],{},"বাংলার জন্য আলাদা ফন্ট লাগবেই, আর সেটা ",[94,1942,1943],{},"subset"," ধরে আনতে হবে:",[87,1946,1950],{"className":1947,"code":1948,"language":1949,"meta":85,"style":85},"language-ts shiki shiki-themes github-dark-dimmed github-dark-dimmed","fonts: {\n  defaults: { subsets: ['latin'] },\n  families: [\n    { name: 'Inter', provider: 'google' },\n    {\n      name: 'Noto Sans Bengali',\n      provider: 'google',\n      subsets: ['bengali'], \u002F\u002F গ্লোবাল ডিফল্ট latin — এখানে override না করলে\n    },                       \u002F\u002F যে ফাইলটা আসবে তাতে একটাও দরকারি গ্লিফ নেই\n  ],\n}\n","ts",[94,1951,1952,1961,1981,1989,2005,2010,2021,2030,2044,2052,2057],{"__ignoreMap":85},[551,1953,1954,1958],{"class":553,"line":554},[551,1955,1957],{"class":1956},"siJwO","fonts",[551,1959,1960],{"class":561},": {\n",[551,1962,1963,1966,1969,1972,1975,1978],{"class":553,"line":184},[551,1964,1965],{"class":1956},"  defaults",[551,1967,1968],{"class":561},": { ",[551,1970,1971],{"class":1956},"subsets",[551,1973,1974],{"class":561},": [",[551,1976,1977],{"class":592},"'latin'",[551,1979,1980],{"class":561},"] },\n",[551,1982,1983,1986],{"class":553,"line":181},[551,1984,1985],{"class":1956},"  families",[551,1987,1988],{"class":561},": [\n",[551,1990,1991,1994,1996,1999,2002],{"class":553,"line":584},[551,1992,1993],{"class":561},"    { name: ",[551,1995,1924],{"class":592},[551,1997,1998],{"class":561},", provider: ",[551,2000,2001],{"class":592},"'google'",[551,2003,2004],{"class":561}," },\n",[551,2006,2007],{"class":553,"line":596},[551,2008,2009],{"class":561},"    {\n",[551,2011,2012,2015,2018],{"class":553,"line":604},[551,2013,2014],{"class":561},"      name: ",[551,2016,2017],{"class":592},"'Noto Sans Bengali'",[551,2019,2020],{"class":561},",\n",[551,2022,2023,2026,2028],{"class":553,"line":446},[551,2024,2025],{"class":561},"      provider: ",[551,2027,2001],{"class":592},[551,2029,2020],{"class":561},[551,2031,2032,2035,2038,2041],{"class":553,"line":197},[551,2033,2034],{"class":561},"      subsets: [",[551,2036,2037],{"class":592},"'bengali'",[551,2039,2040],{"class":561},"], ",[551,2042,2043],{"class":1196},"\u002F\u002F গ্লোবাল ডিফল্ট latin — এখানে override না করলে\n",[551,2045,2046,2049],{"class":553,"line":1271},[551,2047,2048],{"class":561},"    },                       ",[551,2050,2051],{"class":1196},"\u002F\u002F যে ফাইলটা আসবে তাতে একটাও দরকারি গ্লিফ নেই\n",[551,2053,2054],{"class":553,"line":1401},[551,2055,2056],{"class":561},"  ],\n",[551,2058,2059],{"class":553,"line":1407},[551,2060,1937],{"class":561},[42,2062,2063,2064,2067],{},"শেষ লাইনটা আসল ফাঁদ। গ্লোবাল ",[94,2065,2066],{},"subsets: ['latin']"," থাকলে Noto Sans Bengali-ও latin subset নিয়ে আসবে — ফাইলটা ডাউনলোড হবে, ওজন যোগ হবে, আর একটা বাংলা অক্ষরও দেখাবে না।",[2069,2070,2072],"h3",{"id":2071},"fallback-এর-ক্রমটাও-ভাবার-বিষয়","fallback-এর ক্রমটাও ভাবার বিষয়",[42,2074,2075],{},"বাংলা পেজে ইংরেজিও থাকে — কোড, প্রোডাক্টের নাম, সংখ্যা। ব্রাউজার প্রতি-গ্লিফ ধরে fallback করে, তাই ক্রম ঠিক করে দিলে দুটোই ঠিক ফন্ট পায়:",[87,2077,2079],{"className":1897,"code":2078,"language":1899,"meta":85,"style":85},":lang(bn) {\n  font-family: 'Noto Sans Bengali', 'Inter', ui-sans-serif, sans-serif;\n}\n",[94,2080,2081,2094,2117],{"__ignoreMap":85},[551,2082,2083,2086,2089,2091],{"class":553,"line":554},[551,2084,2085],{"class":573},":lang",[551,2087,2088],{"class":561},"(",[551,2090,194],{"class":573},[551,2092,2093],{"class":561},") {\n",[551,2095,2096,2098,2100,2102,2104,2106,2108,2111,2113,2115],{"class":553,"line":184},[551,2097,1919],{"class":573},[551,2099,570],{"class":561},[551,2101,2017],{"class":592},[551,2103,1505],{"class":561},[551,2105,1924],{"class":592},[551,2107,1505],{"class":561},[551,2109,2110],{"class":573},"ui-sans-serif",[551,2112,1505],{"class":561},[551,2114,1929],{"class":573},[551,2116,1932],{"class":561},[551,2118,2119],{"class":553,"line":181},[551,2120,1937],{"class":561},[42,2122,2123],{},"Noto আগে, তাই বাংলা Noto পায়। ইংরেজি অক্ষর Noto-র ল্যাটিন সেটে আছে বটে, কিন্তু সেটা দেখতে অন্যরকম — পাতায় আলাদা রঙের মতো লাগে। Inter দ্বিতীয়তে থাকায় ল্যাটিন গ্লিফগুলো Inter-এই পড়ে।",[42,2125,2126],{},"কোড কিন্তু দুই ট্র্যাকেই ল্যাটিন থাকা উচিত:",[87,2128,2130],{"className":1897,"code":2129,"language":1899,"meta":85,"style":85},":lang(bn) :is(code, pre, kbd, samp) {\n  font-family: var(--font-mono);\n}\n",[94,2131,2132,2166,2183],{"__ignoreMap":85},[551,2133,2134,2136,2138,2140,2143,2146,2148,2150,2152,2154,2156,2159,2161,2164],{"class":553,"line":554},[551,2135,2085],{"class":573},[551,2137,2088],{"class":561},[551,2139,194],{"class":573},[551,2141,2142],{"class":561},") ",[551,2144,2145],{"class":573},":is",[551,2147,2088],{"class":561},[551,2149,94],{"class":557},[551,2151,1505],{"class":561},[551,2153,87],{"class":557},[551,2155,1505],{"class":561},[551,2157,2158],{"class":557},"kbd",[551,2160,1505],{"class":561},[551,2162,2163],{"class":557},"samp",[551,2165,2093],{"class":561},[551,2167,2168,2170,2172,2175,2177,2180],{"class":553,"line":184},[551,2169,1919],{"class":573},[551,2171,570],{"class":561},[551,2173,2174],{"class":573},"var",[551,2176,2088],{"class":561},[551,2178,2179],{"class":1956},"--font-mono",[551,2181,2182],{"class":561},");\n",[551,2184,2185],{"class":553,"line":181},[551,2186,1937],{"class":561},[42,2188,2189],{},"একটা shell কমান্ড বাংলা ফন্টে রেন্ডার করার কোনো কারণ নেই, আর কোড ব্লকের লেআউট মনোস্পেসের গ্লিফ-প্রস্থ ধরে বানানো।",[54,2191,2193],{"id":2192},"২-মাত্রা-উপরে-নিচে-জায়গা-চায়","২. মাত্রা উপরে-নিচে জায়গা চায়",[42,2195,2196],{},"এইটা সবচেয়ে কম আলোচিত, আর সবচেয়ে বেশি চোখে লাগে।",[42,2198,2199,2200,2203],{},"বাংলায় কার-চিহ্ন বেসলাইনের উপরে আর নিচে বসে — ি, ী, ু, ূ, ৃ, ে, ৈ, ো, ৌ, রেফ, হসন্ত, যুক্তাক্ষরের নিচের অংশ। ল্যাটিন প্রোজে যে ",[94,2201,2202],{},"line-height: 1.6"," স্বাভাবিক, বাংলায় সেই মাপে পরপর দুই লাইনের চিহ্নগুলো একে অপরকে ছুঁয়ে ফেলে।",[87,2205,2207],{"className":1897,"code":2206,"language":1899,"meta":85,"style":85},":lang(bn) .ux-prose :is(p, li, blockquote) {\n  line-height: 1.9;\n}\n",[94,2208,2209,2240,2252],{"__ignoreMap":85},[551,2210,2211,2213,2215,2217,2219,2222,2225,2227,2229,2231,2233,2235,2238],{"class":553,"line":554},[551,2212,2085],{"class":573},[551,2214,2088],{"class":561},[551,2216,194],{"class":573},[551,2218,2142],{"class":561},[551,2220,2221],{"class":573},".ux-prose",[551,2223,2224],{"class":573}," :is",[551,2226,2088],{"class":561},[551,2228,42],{"class":557},[551,2230,1505],{"class":561},[551,2232,879],{"class":557},[551,2234,1505],{"class":561},[551,2236,2237],{"class":557},"blockquote",[551,2239,2093],{"class":561},[551,2241,2242,2245,2247,2250],{"class":553,"line":184},[551,2243,2244],{"class":573},"  line-height",[551,2246,570],{"class":561},[551,2248,2249],{"class":573},"1.9",[551,2251,1932],{"class":561},[551,2253,2254],{"class":553,"line":181},[551,2255,1937],{"class":561},[42,2257,2258,2259,2262],{},"কিন্তু ",[49,2260,2261],{},"সব সাইজে এক মান বসানো ভুল"," — আর এই ভুলটা আমরা করেছিলাম।",[42,2264,2265,2266,2269],{},"প্রথমে লেখা ছিল ",[94,2267,2268],{},":lang(bn) :is(h1, h2, h3) { line-height: 1.45 }","। বডি টেক্সটের মাপে এটা ঠিক। কিন্তু পেজ টাইটেল ক্ল্যাম্প হয়ে ৬৪px-এ যায় — সেখানে ১.৪৫ মানে দুই লাইনের মাঝে ৯৩px ফাঁক। দুই শব্দের একটা হেডিং দেখাচ্ছিল যেন ডাবল-স্পেসড।",[42,2271,2272],{},"টাইপ যত বড়, আনুপাতিক লিডিং তত কম দরকার। একটা fixed multiplier ঠিক উল্টোটা করে। তাই প্রতিটা ধাপে আলাদা:",[87,2274,2276],{"className":1897,"code":2275,"language":1899,"meta":85,"style":85},":lang(bn) {\n  --text-hero--line-height: 1.16; \u002F* ল্যাটিনের চেয়ে সামান্যই বেশি *\u002F\n  --text-section--line-height: 1.22;\n  --text-title--line-height: 1.35;\n  --text-lg--line-height: 1.75;\n  --text-base--line-height: 1.8; \u002F* পড়ার মাপে উদার *\u002F\n  --text-sm--line-height: 1.65;\n}\n",[94,2277,2278,2288,2304,2316,2328,2340,2355,2367],{"__ignoreMap":85},[551,2279,2280,2282,2284,2286],{"class":553,"line":554},[551,2281,2085],{"class":573},[551,2283,2088],{"class":561},[551,2285,194],{"class":573},[551,2287,2093],{"class":561},[551,2289,2290,2293,2295,2298,2301],{"class":553,"line":184},[551,2291,2292],{"class":1956},"  --text-hero--line-height",[551,2294,570],{"class":561},[551,2296,2297],{"class":573},"1.16",[551,2299,2300],{"class":561},"; ",[551,2302,2303],{"class":1196},"\u002F* ল্যাটিনের চেয়ে সামান্যই বেশি *\u002F\n",[551,2305,2306,2309,2311,2314],{"class":553,"line":181},[551,2307,2308],{"class":1956},"  --text-section--line-height",[551,2310,570],{"class":561},[551,2312,2313],{"class":573},"1.22",[551,2315,1932],{"class":561},[551,2317,2318,2321,2323,2326],{"class":553,"line":584},[551,2319,2320],{"class":1956},"  --text-title--line-height",[551,2322,570],{"class":561},[551,2324,2325],{"class":573},"1.35",[551,2327,1932],{"class":561},[551,2329,2330,2333,2335,2338],{"class":553,"line":596},[551,2331,2332],{"class":1956},"  --text-lg--line-height",[551,2334,570],{"class":561},[551,2336,2337],{"class":573},"1.75",[551,2339,1932],{"class":561},[551,2341,2342,2345,2347,2350,2352],{"class":553,"line":604},[551,2343,2344],{"class":1956},"  --text-base--line-height",[551,2346,570],{"class":561},[551,2348,2349],{"class":573},"1.8",[551,2351,2300],{"class":561},[551,2353,2354],{"class":1196},"\u002F* পড়ার মাপে উদার *\u002F\n",[551,2356,2357,2360,2362,2365],{"class":553,"line":446},[551,2358,2359],{"class":1956},"  --text-sm--line-height",[551,2361,570],{"class":561},[551,2363,2364],{"class":573},"1.65",[551,2366,1932],{"class":561},[551,2368,2369],{"class":553,"line":197},[551,2370,1937],{"class":561},[42,2372,2373,2374,2377],{},"টোকেনটা রিডিফাইন করাই যথেষ্ট, কারণ ইউটিলিটিগুলো ",[94,2375,2376],{},"line-height: var(--text-\u003Csize>--line-height)","-এ কম্পাইল হয়। কোনো সিলেক্টর লিখতে হয় না, আর ওই ধাপ ব্যবহার করা প্রতিটা এলিমেন্ট আপনাআপনি ঠিক হয়ে যায়।",[54,2379,2381],{"id":2380},"৩-uppercase-বাংলায়-একটা-no-op","৩. uppercase বাংলায় একটা no-op",[42,2383,2384,2385,2388],{},"বাংলায় বড় হাতের অক্ষর নেই। ",[94,2386,2387],{},"text-transform: uppercase"," কিছুই বদলায় না।",[42,2390,2391,2392,2395,2396,2399],{},"সমস্যা হলো, eyebrow বা badge-এর স্টাইলে ",[94,2393,2394],{},"uppercase"," একা আসে না — সাথে ",[94,2397,2398],{},"letter-spacing"," আসে। ল্যাটিনে বড় হাতের অক্ষর ফাঁক ফাঁক করে বসালে ভালো লাগে। বাংলায় ট্র্যাকিং বাড়ালে যুক্তাক্ষর টেনে আলাদা হয়ে যায়, আর লেবেলটা ভাঙা দেখায়।",[87,2401,2403],{"className":1897,"code":2402,"language":1899,"meta":85,"style":85},":lang(bn) :is(.ux-eyebrow, .uppercase, [class*='tracking-']) {\n  text-transform: none;\n  letter-spacing: normal;\n}\n",[94,2404,2405,2441,2453,2465],{"__ignoreMap":85},[551,2406,2407,2409,2411,2413,2415,2417,2419,2422,2424,2427,2430,2432,2435,2438],{"class":553,"line":554},[551,2408,2085],{"class":573},[551,2410,2088],{"class":561},[551,2412,194],{"class":573},[551,2414,2142],{"class":561},[551,2416,2145],{"class":573},[551,2418,2088],{"class":561},[551,2420,2421],{"class":573},".ux-eyebrow",[551,2423,1505],{"class":561},[551,2425,2426],{"class":573},".uppercase",[551,2428,2429],{"class":561},", [",[551,2431,1500],{"class":573},[551,2433,2434],{"class":1279},"*=",[551,2436,2437],{"class":592},"'tracking-'",[551,2439,2440],{"class":561},"]) {\n",[551,2442,2443,2446,2448,2451],{"class":553,"line":184},[551,2444,2445],{"class":573},"  text-transform",[551,2447,570],{"class":561},[551,2449,2450],{"class":573},"none",[551,2452,1932],{"class":561},[551,2454,2455,2458,2460,2463],{"class":553,"line":181},[551,2456,2457],{"class":573},"  letter-spacing",[551,2459,570],{"class":561},[551,2461,2462],{"class":573},"normal",[551,2464,1932],{"class":561},[551,2466,2467],{"class":553,"line":584},[551,2468,1937],{"class":561},[42,2470,2471],{},"দুটোই বাতিল করা হয়েছে, নতুন করে স্টাইল করা হয়নি — ইংরেজি ট্র্যাক তার নিজের ট্রিটমেন্ট অক্ষত রাখে।",[54,2473,2475],{"id":2474},"৪-একই-px-এ-বাংলা-ছোট-দেখায়","৪. একই px-এ বাংলা ছোট দেখায়",[42,2477,2478],{},"একই ফন্ট-সাইজে বাংলার x-height ল্যাটিনের তুলনায় কম, তাই পাশাপাশি রাখলে বাংলাটা ছোট লাগে। খুব সামান্য একটা বাম্প দুই ট্র্যাককে একই ডিজাইন সিস্টেমের মতো দেখায়:",[87,2480,2482],{"className":1897,"code":2481,"language":1899,"meta":85,"style":85},":lang(bn) .ux-prose {\n  font-size: 1.03em;\n}\n",[94,2483,2484,2498,2513],{"__ignoreMap":85},[551,2485,2486,2488,2490,2492,2494,2496],{"class":553,"line":554},[551,2487,2085],{"class":573},[551,2489,2088],{"class":561},[551,2491,194],{"class":573},[551,2493,2142],{"class":561},[551,2495,2221],{"class":573},[551,2497,1914],{"class":561},[551,2499,2500,2503,2505,2508,2511],{"class":553,"line":184},[551,2501,2502],{"class":573},"  font-size",[551,2504,570],{"class":561},[551,2506,2507],{"class":573},"1.03",[551,2509,2510],{"class":1279},"em",[551,2512,1932],{"class":561},[551,2514,2515],{"class":553,"line":181},[551,2516,1937],{"class":561},[42,2518,2519,1505,2521,2524],{},[94,2520,2510],{},[94,2522,2523],{},"px"," নয় — যাতে ব্যবহারকারীর নিজের ফন্ট-সাইজ সেটিং কাজ করতে থাকে।",[54,2526,2528],{"id":2527},"৫-সংখ্যার-হাইড্রেশন-মিসম্যাচ","৫. সংখ্যার হাইড্রেশন মিসম্যাচ",[42,2530,2531],{},"এইটা টাইপোগ্রাফির সমস্যা নয়, কিন্তু একই কাজ করতে গিয়ে ধরা পড়ে।",[42,2533,2534],{},"বাংলা সংখ্যা ফরম্যাট করতে স্বাভাবিক পছন্দ:",[87,2536,2538],{"className":1947,"code":2537,"language":1949,"meta":85,"style":85},"new Intl.NumberFormat('bn-BD').format(12480)\n",[94,2539,2540],{"__ignoreMap":85},[551,2541,2542,2545,2548,2552,2554,2557,2560,2563,2565,2568],{"class":553,"line":554},[551,2543,2544],{"class":1279},"new",[551,2546,2547],{"class":561}," Intl.",[551,2549,2551],{"class":2550},"s-wk_","NumberFormat",[551,2553,2088],{"class":561},[551,2555,2556],{"class":592},"'bn-BD'",[551,2558,2559],{"class":561},").",[551,2561,2562],{"class":2550},"format",[551,2564,2088],{"class":561},[551,2566,2567],{"class":573},"12480",[551,2569,2570],{"class":561},")\n",[42,2572,2573],{},"কিন্তু ICU বিল্ডগুলো একমত নয় — কেউ হাজার ধরে গ্রুপ করে (১২,৪৮০), কেউ লাখ ধরে (১২,৪৮০ বনাম ১,২৪৮০ ধরনের পার্থক্য)। Node-এর ICU আর ব্রাউজারের ICU আলাদা হলে সার্ভার একরকম লেখে, ক্লায়েন্ট আরেকরকম — আর prerendered পেজে সেটা সরাসরি hydration mismatch।",[42,2575,2576,2577,2580],{},"তাই গ্রুপিংটা ",[94,2578,2579],{},"en-US"," থেকে নিয়ে শুধু অঙ্কগুলো বদলানো হয়:",[87,2582,2584],{"className":1947,"code":2583,"language":1949,"meta":85,"style":85},"const BN_DIGITS = ['০', '১', '২', '৩', '৪', '৫', '৬', '৭', '৮', '৯']\n\nexport function formatBnNumber(value: number): string {\n  return new Intl.NumberFormat('en-US')\n    .format(value)\n    .replace(\u002F\\d\u002Fg, (d) => BN_DIGITS[Number(d)]!)\n}\n",[94,2585,2586,2651,2655,2687,2706,2716,2762],{"__ignoreMap":85},[551,2587,2588,2591,2594,2597,2600,2603,2605,2608,2610,2613,2615,2618,2620,2623,2625,2628,2630,2633,2635,2638,2640,2643,2645,2648],{"class":553,"line":554},[551,2589,2590],{"class":1279},"const",[551,2592,2593],{"class":573}," BN_DIGITS",[551,2595,2596],{"class":1279}," =",[551,2598,2599],{"class":561}," [",[551,2601,2602],{"class":592},"'০'",[551,2604,1505],{"class":561},[551,2606,2607],{"class":592},"'১'",[551,2609,1505],{"class":561},[551,2611,2612],{"class":592},"'২'",[551,2614,1505],{"class":561},[551,2616,2617],{"class":592},"'৩'",[551,2619,1505],{"class":561},[551,2621,2622],{"class":592},"'৪'",[551,2624,1505],{"class":561},[551,2626,2627],{"class":592},"'৫'",[551,2629,1505],{"class":561},[551,2631,2632],{"class":592},"'৬'",[551,2634,1505],{"class":561},[551,2636,2637],{"class":592},"'৭'",[551,2639,1505],{"class":561},[551,2641,2642],{"class":592},"'৮'",[551,2644,1505],{"class":561},[551,2646,2647],{"class":592},"'৯'",[551,2649,2650],{"class":561},"]\n",[551,2652,2653],{"class":553,"line":184},[551,2654,1263],{"emptyLinePlaceholder":24},[551,2656,2657,2660,2663,2666,2668,2671,2674,2677,2680,2682,2685],{"class":553,"line":181},[551,2658,2659],{"class":1279},"export",[551,2661,2662],{"class":1279}," function",[551,2664,2665],{"class":2550}," formatBnNumber",[551,2667,2088],{"class":561},[551,2669,2670],{"class":1956},"value",[551,2672,2673],{"class":1279},":",[551,2675,2676],{"class":573}," number",[551,2678,2679],{"class":561},")",[551,2681,2673],{"class":1279},[551,2683,2684],{"class":573}," string",[551,2686,1914],{"class":561},[551,2688,2689,2692,2695,2697,2699,2701,2704],{"class":553,"line":584},[551,2690,2691],{"class":1279},"  return",[551,2693,2694],{"class":1279}," new",[551,2696,2547],{"class":561},[551,2698,2551],{"class":2550},[551,2700,2088],{"class":561},[551,2702,2703],{"class":592},"'en-US'",[551,2705,2570],{"class":561},[551,2707,2708,2711,2713],{"class":553,"line":596},[551,2709,2710],{"class":561},"    .",[551,2712,2562],{"class":2550},[551,2714,2715],{"class":561},"(value)\n",[551,2717,2718,2720,2723,2725,2727,2730,2732,2735,2738,2741,2743,2746,2748,2751,2754,2757,2760],{"class":553,"line":604},[551,2719,2710],{"class":561},[551,2721,2722],{"class":2550},"replace",[551,2724,2088],{"class":561},[551,2726,769],{"class":592},[551,2728,2729],{"class":573},"\\d",[551,2731,769],{"class":592},[551,2733,2734],{"class":1279},"g",[551,2736,2737],{"class":561},", (",[551,2739,2740],{"class":1956},"d",[551,2742,2142],{"class":561},[551,2744,2745],{"class":1279},"=>",[551,2747,2593],{"class":573},[551,2749,2750],{"class":561},"[",[551,2752,2753],{"class":2550},"Number",[551,2755,2756],{"class":561},"(d)]",[551,2758,2759],{"class":1279},"!",[551,2761,2570],{"class":561},[551,2763,2764],{"class":553,"line":446},[551,2765,1937],{"class":561},[42,2767,2768],{},"দেখতে হ্যাক লাগে। কিন্তু এটা deterministic, আর দুই রানটাইমে এক আউটপুট দেয় — যেটাই আসল দাবি।",[54,2770,2772],{"id":2771},"সব-মিলিয়ে","সব মিলিয়ে",[42,2774,2775,2776,2779],{},"লক্ষ্য করার মতো ব্যাপার: এর কোনোটাই \"বাংলার জন্য আলাদা ডিজাইন\" নয়। সবগুলো ",[94,2777,2778],{},":lang(bn)","-এর ভেতরে, একটা আলাদা ফাইলে, সবার শেষে ইমপোর্ট করা — যাতে ল্যাটিন ডিফল্টের উপরে জেতে।",[87,2781,2783],{"className":1897,"code":2782,"language":1899,"meta":85,"style":85},"@import '.\u002Fprose.css';\n\u002F* সবার শেষে, যাতে :lang(bn) আগেরগুলোকে override করে *\u002F\n@import '.\u002Fbangla.css';\n",[94,2784,2785,2795,2800],{"__ignoreMap":85},[551,2786,2787,2790,2793],{"class":553,"line":554},[551,2788,2789],{"class":1279},"@import",[551,2791,2792],{"class":592}," '.\u002Fprose.css'",[551,2794,1932],{"class":561},[551,2796,2797],{"class":553,"line":184},[551,2798,2799],{"class":1196},"\u002F* সবার শেষে, যাতে :lang(bn) আগেরগুলোকে override করে *\u002F\n",[551,2801,2802,2804,2807],{"class":553,"line":181},[551,2803,2789],{"class":1279},[551,2805,2806],{"class":592}," '.\u002Fbangla.css'",[551,2808,1932],{"class":561},[42,2810,2811,2812,2815,2816,2819],{},"ইংরেজি ট্র্যাক এই ফাইলটার একটা লাইনও ছোঁয় না। আর ",[94,2813,2814],{},"\u003Chtml lang>"," ভুল হলে পুরো স্টাইলশিটটা চুপচাপ নিষ্ক্রিয় হয়ে যায় — উপসর্গ দেখায় \"বাংলা ভুল ফন্টে রেন্ডার হচ্ছে\", যেটা আসল কারণ থেকে অনেক দূরে। তাই ",[94,2817,2818],{},"lang"," অ্যাট্রিবিউটটা রুট থেকে সেট হয়, প্রতি পেজে নয়, আর একটা নতুন রুট সেটা ভুলে যেতে পারে না।",[800,2821,2822],{},"html pre.shiki code .s0RzX, html code.shiki .s0RzX{--shiki-default:#768390;--shiki-dark:#768390}html pre.shiki code .sza-u, html code.shiki .sza-u{--shiki-default:#8DDB8C;--shiki-dark:#8DDB8C}html pre.shiki code .sM9_K, html code.shiki .sM9_K{--shiki-default:#ADBAC7;--shiki-dark:#ADBAC7}html pre.shiki code .sQdni, html code.shiki .sQdni{--shiki-default:#6CB6FF;--shiki-dark:#6CB6FF}html pre.shiki code .szYpP, html code.shiki .szYpP{--shiki-default:#96D0FF;--shiki-dark:#96D0FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .siJwO, html code.shiki .siJwO{--shiki-default:#F69D50;--shiki-dark:#F69D50}html pre.shiki code .sEYkB, html code.shiki .sEYkB{--shiki-default:#F47067;--shiki-dark:#F47067}html pre.shiki code .s-wk_, html code.shiki .s-wk_{--shiki-default:#DCBDFB;--shiki-dark:#DCBDFB}",{"title":85,"searchDepth":181,"depth":181,"links":2824},[2825,2828,2829,2830,2831,2832],{"id":1890,"depth":184,"text":1891,"children":2826},[2827],{"id":2071,"depth":181,"text":2072},{"id":2192,"depth":184,"text":2193},{"id":2380,"depth":184,"text":2381},{"id":2474,"depth":184,"text":2475},{"id":2527,"depth":184,"text":2528},{"id":2771,"depth":184,"text":2772},"design","\u002Fcovers\u002Fblog\u002Fbn\u002Fbangla-typography-on-the-web.webp","2026-07-22","লাইন-হাইট, মাত্রার সংঘর্ষ, uppercase-এর অর্থহীনতা আর ফন্ট ফলব্যাক। ল্যাটিনের জন্য বানানো একটা ডিজাইন সিস্টেমে বাংলা বসাতে গিয়ে যা যা ঠিক করতে হয়েছিল।",{},"\u002Fblog\u002Fbn\u002Fbangla-typography-on-the-web",{"title":1876,"description":2836},"blog\u002Fbn\u002Fbangla-typography-on-the-web",[2842,2843,1542],"টাইপোগ্রাফি","বাংলা","MVkMQ9Bn56OKaLn_Qv4vIA_XiUbXdfdED8iw1ALAt8c",{"id":2846,"title":2847,"author":2848,"body":2849,"category":3520,"cover":3521,"coverAlt":2847,"date":3522,"description":3523,"draft":6,"extension":193,"featured":6,"lang":194,"meta":3524,"navigation":24,"path":3525,"readingTime":197,"seo":3526,"seoTitle":190,"stem":3527,"tags":3528,"__hash__":3532},"blog\u002Fblog\u002Fbn\u002Fdesign-system-mistakes.md","ডিজাইন সিস্টেম বানানোর আগে যে ভুলগুলো এড়ানো দরকার",{"name":1133,"role":1134},{"type":39,"value":2850,"toc":3511},[2851,2854,2858,2861,2978,2988,2994,2998,3004,3211,3222,3225,3271,3278,3282,3291,3303,3307,3310,3360,3374,3377,3381,3384,3387,3391,3394,3485,3492,3496,3502,3505,3508],[42,2852,2853],{},"একটা ডিজাইন সিস্টেম হয় তার প্রথম রিব্র্যান্ড পার করে, নয়তো পারে না। বেশিরভাগ পারে না — আর কারণটা প্রায় সবসময় একই: সিস্টেমে দুইটা লেয়ার আছে, যেখানে দরকার ছিল তিনটা।",[54,2855,2857],{"id":2856},"দুই-লেয়ারের-ফাঁদ","দুই-লেয়ারের ফাঁদ",[42,2859,2860],{},"প্রায় প্রতিটা টোকেন সিস্টেম এইভাবে শুরু হয়। একটা প্যালেট, আর কম্পোনেন্ট যেগুলো সেটা ব্যবহার করে।",[87,2862,2864],{"className":1897,"code":2863,"language":1899,"meta":85,"style":85},":root {\n  --blue-500: #00d4ff;\n  --gray-900: #18181b;\n}\n\n.card {\n  background: var(--gray-900);\n  border-color: var(--gray-800);\n}\n\n.button-primary {\n  background: var(--blue-500);\n}\n",[94,2865,2866,2873,2885,2897,2901,2905,2912,2928,2944,2948,2952,2959,2974],{"__ignoreMap":85},[551,2867,2868,2871],{"class":553,"line":554},[551,2869,2870],{"class":573},":root",[551,2872,1914],{"class":561},[551,2874,2875,2878,2880,2883],{"class":553,"line":184},[551,2876,2877],{"class":1956},"  --blue-500",[551,2879,570],{"class":561},[551,2881,2882],{"class":573},"#00d4ff",[551,2884,1932],{"class":561},[551,2886,2887,2890,2892,2895],{"class":553,"line":181},[551,2888,2889],{"class":1956},"  --gray-900",[551,2891,570],{"class":561},[551,2893,2894],{"class":573},"#18181b",[551,2896,1932],{"class":561},[551,2898,2899],{"class":553,"line":584},[551,2900,1937],{"class":561},[551,2902,2903],{"class":553,"line":596},[551,2904,1263],{"emptyLinePlaceholder":24},[551,2906,2907,2910],{"class":553,"line":604},[551,2908,2909],{"class":573},".card",[551,2911,1914],{"class":561},[551,2913,2914,2917,2919,2921,2923,2926],{"class":553,"line":446},[551,2915,2916],{"class":573},"  background",[551,2918,570],{"class":561},[551,2920,2174],{"class":573},[551,2922,2088],{"class":561},[551,2924,2925],{"class":1956},"--gray-900",[551,2927,2182],{"class":561},[551,2929,2930,2933,2935,2937,2939,2942],{"class":553,"line":197},[551,2931,2932],{"class":573},"  border-color",[551,2934,570],{"class":561},[551,2936,2174],{"class":573},[551,2938,2088],{"class":561},[551,2940,2941],{"class":1956},"--gray-800",[551,2943,2182],{"class":561},[551,2945,2946],{"class":553,"line":1271},[551,2947,1937],{"class":561},[551,2949,2950],{"class":553,"line":1401},[551,2951,1263],{"emptyLinePlaceholder":24},[551,2953,2954,2957],{"class":553,"line":1407},[551,2955,2956],{"class":573},".button-primary",[551,2958,1914],{"class":561},[551,2960,2961,2963,2965,2967,2969,2972],{"class":553,"line":1769},[551,2962,2916],{"class":573},[551,2964,570],{"class":561},[551,2966,2174],{"class":573},[551,2968,2088],{"class":561},[551,2970,2971],{"class":1956},"--blue-500",[551,2973,2182],{"class":561},[551,2975,2976],{"class":553,"line":1778},[551,2977,1937],{"class":561},[42,2979,2980,2981,2983,2984,2987],{},"দেখতে পরিষ্কার। ছয় মাস ভালোই চলে। তারপর ব্র্যান্ড বদলায় — নীল থেকে সবুজ — আর তখন বোঝা যায় ",[94,2982,2971],{}," নামটাই সমস্যা। এখন হয় সবুজ রঙ একটা ",[94,2985,2986],{},"blue"," নামের ভেরিয়েবলে রাখতে হবে, নয়তো কোডবেসে ৪০০টা জায়গায় খুঁজে বদলাতে হবে।",[42,2989,2990,2991,2993],{},"আরও খারাপ ব্যাপারটা হলো ডার্ক মোড। ",[94,2992,2925],{}," ডার্ক থিমে ব্যাকগ্রাউন্ড, লাইট থিমে টেক্সট। একই টোকেন, দুইটা উল্টো ভূমিকা। কম্পোনেন্ট যখন সরাসরি প্যালেট ছোঁয়, তখন প্রতিটা কম্পোনেন্টকে জানতে হয় থিম কী — আর সেটাই সিস্টেমটার মৃত্যু।",[54,2995,2997],{"id":2996},"তৃতীয়-লেয়ারটা-ভূমিকা","তৃতীয় লেয়ারটা: ভূমিকা",[42,2999,3000,3001,356],{},"মাঝখানে যা দরকার, সেটা রঙ নয় — ",[49,3002,3003],{},"ভূমিকা",[87,3005,3007],{"className":1897,"code":3006,"language":1899,"meta":85,"style":85},"\u002F* লেয়ার ১ — প্রিমিটিভ। কোনো প্রোডাক্ট-অর্থ নেই। *\u002F\n:root {\n  --cyan-400: #22d3ee;\n  --cyan-600: #0891b2;\n  --zinc-50: #fafafa;\n  --zinc-900: #18181b;\n}\n\n\u002F* লেয়ার ২ — সিমান্টিক। থিম অনুযায়ী বদলায়। *\u002F\n:root {\n  --surface: var(--zinc-50);\n  --foreground: var(--zinc-900);\n  --primary: var(--cyan-600);\n}\n\n[data-theme='dark'] {\n  --surface: var(--zinc-900);\n  --foreground: var(--zinc-50);\n  --primary: var(--cyan-400);\n}\n",[94,3008,3009,3014,3020,3032,3044,3056,3067,3071,3075,3080,3086,3102,3118,3134,3139,3144,3160,3175,3190,3206],{"__ignoreMap":85},[551,3010,3011],{"class":553,"line":554},[551,3012,3013],{"class":1196},"\u002F* লেয়ার ১ — প্রিমিটিভ। কোনো প্রোডাক্ট-অর্থ নেই। *\u002F\n",[551,3015,3016,3018],{"class":553,"line":184},[551,3017,2870],{"class":573},[551,3019,1914],{"class":561},[551,3021,3022,3025,3027,3030],{"class":553,"line":181},[551,3023,3024],{"class":1956},"  --cyan-400",[551,3026,570],{"class":561},[551,3028,3029],{"class":573},"#22d3ee",[551,3031,1932],{"class":561},[551,3033,3034,3037,3039,3042],{"class":553,"line":584},[551,3035,3036],{"class":1956},"  --cyan-600",[551,3038,570],{"class":561},[551,3040,3041],{"class":573},"#0891b2",[551,3043,1932],{"class":561},[551,3045,3046,3049,3051,3054],{"class":553,"line":596},[551,3047,3048],{"class":1956},"  --zinc-50",[551,3050,570],{"class":561},[551,3052,3053],{"class":573},"#fafafa",[551,3055,1932],{"class":561},[551,3057,3058,3061,3063,3065],{"class":553,"line":604},[551,3059,3060],{"class":1956},"  --zinc-900",[551,3062,570],{"class":561},[551,3064,2894],{"class":573},[551,3066,1932],{"class":561},[551,3068,3069],{"class":553,"line":446},[551,3070,1937],{"class":561},[551,3072,3073],{"class":553,"line":197},[551,3074,1263],{"emptyLinePlaceholder":24},[551,3076,3077],{"class":553,"line":1271},[551,3078,3079],{"class":1196},"\u002F* লেয়ার ২ — সিমান্টিক। থিম অনুযায়ী বদলায়। *\u002F\n",[551,3081,3082,3084],{"class":553,"line":1401},[551,3083,2870],{"class":573},[551,3085,1914],{"class":561},[551,3087,3088,3091,3093,3095,3097,3100],{"class":553,"line":1407},[551,3089,3090],{"class":1956},"  --surface",[551,3092,570],{"class":561},[551,3094,2174],{"class":573},[551,3096,2088],{"class":561},[551,3098,3099],{"class":1956},"--zinc-50",[551,3101,2182],{"class":561},[551,3103,3104,3107,3109,3111,3113,3116],{"class":553,"line":1769},[551,3105,3106],{"class":1956},"  --foreground",[551,3108,570],{"class":561},[551,3110,2174],{"class":573},[551,3112,2088],{"class":561},[551,3114,3115],{"class":1956},"--zinc-900",[551,3117,2182],{"class":561},[551,3119,3120,3123,3125,3127,3129,3132],{"class":553,"line":1778},[551,3121,3122],{"class":1956},"  --primary",[551,3124,570],{"class":561},[551,3126,2174],{"class":573},[551,3128,2088],{"class":561},[551,3130,3131],{"class":1956},"--cyan-600",[551,3133,2182],{"class":561},[551,3135,3137],{"class":553,"line":3136},14,[551,3138,1937],{"class":561},[551,3140,3142],{"class":553,"line":3141},15,[551,3143,1263],{"emptyLinePlaceholder":24},[551,3145,3147,3149,3152,3154,3157],{"class":553,"line":3146},16,[551,3148,2750],{"class":561},[551,3150,3151],{"class":573},"data-theme",[551,3153,1221],{"class":1279},[551,3155,3156],{"class":592},"'dark'",[551,3158,3159],{"class":561},"] {\n",[551,3161,3163,3165,3167,3169,3171,3173],{"class":553,"line":3162},17,[551,3164,3090],{"class":1956},[551,3166,570],{"class":561},[551,3168,2174],{"class":573},[551,3170,2088],{"class":561},[551,3172,3115],{"class":1956},[551,3174,2182],{"class":561},[551,3176,3178,3180,3182,3184,3186,3188],{"class":553,"line":3177},18,[551,3179,3106],{"class":1956},[551,3181,570],{"class":561},[551,3183,2174],{"class":573},[551,3185,2088],{"class":561},[551,3187,3099],{"class":1956},[551,3189,2182],{"class":561},[551,3191,3193,3195,3197,3199,3201,3204],{"class":553,"line":3192},19,[551,3194,3122],{"class":1956},[551,3196,570],{"class":561},[551,3198,2174],{"class":573},[551,3200,2088],{"class":561},[551,3202,3203],{"class":1956},"--cyan-400",[551,3205,2182],{"class":561},[551,3207,3209],{"class":553,"line":3208},20,[551,3210,1937],{"class":561},[42,3212,3213,3214,3217,3218,3221],{},"খেয়াল করুন ",[94,3215,3216],{},"--primary"," দুই থিমে ",[49,3219,3220],{},"আলাদা hex","। এটা ভুল নয়, এটাই মূল কথা। ডার্ক মোডের উজ্জ্বল সায়ান সাদা ব্যাকগ্রাউন্ডে কনট্রাস্ট পরীক্ষায় ফেল করে। \"একটা ব্র্যান্ড কালার সব জায়গায়\" — এই ধারণাটাই অ্যাক্সেসিবিলিটির সাথে সাংঘর্ষিক।",[42,3223,3224],{},"কম্পোনেন্ট এখন শুধু ভূমিকা ব্যবহার করে:",[87,3226,3228],{"className":1897,"code":3227,"language":1899,"meta":85,"style":85},".card {\n  background: var(--surface);\n  color: var(--foreground);\n}\n",[94,3229,3230,3236,3251,3267],{"__ignoreMap":85},[551,3231,3232,3234],{"class":553,"line":554},[551,3233,2909],{"class":573},[551,3235,1914],{"class":561},[551,3237,3238,3240,3242,3244,3246,3249],{"class":553,"line":184},[551,3239,2916],{"class":573},[551,3241,570],{"class":561},[551,3243,2174],{"class":573},[551,3245,2088],{"class":561},[551,3247,3248],{"class":1956},"--surface",[551,3250,2182],{"class":561},[551,3252,3253,3256,3258,3260,3262,3265],{"class":553,"line":181},[551,3254,3255],{"class":573},"  color",[551,3257,570],{"class":561},[551,3259,2174],{"class":573},[551,3261,2088],{"class":561},[551,3263,3264],{"class":1956},"--foreground",[551,3266,2182],{"class":561},[551,3268,3269],{"class":553,"line":584},[551,3270,1937],{"class":561},[42,3272,3273,3274,3277],{},"রিব্র্যান্ড এখন ",[49,3275,3276],{},"লেয়ার দুইয়ের একটা এডিট","। কম্পোনেন্ট একটাও ছুঁতে হয় না।",[54,3279,3281],{"id":3280},"ভুল-১-টোকেনের-নাম-রঙ-দিয়ে-রাখা","ভুল ১ — টোকেনের নাম রঙ দিয়ে রাখা",[42,3283,3284,3287,3288,3290],{},[94,3285,3286],{},"--brand-blue"," একটা টাইম বোমা। ",[94,3289,3216],{}," নয়।",[42,3292,3293,3294,1505,3296,1505,3299,3302],{},"নিয়মটা সহজ: টোকেনের নামে যদি এমন কিছু থাকে যা রিব্র্যান্ডে মিথ্যা হয়ে যেতে পারে, নামটা ভুল। ",[94,3295,2986],{},[94,3297,3298],{},"large",[94,3300,3301],{},"top-nav"," — সবগুলোই কোনো না কোনো দিন মিথ্যা হয়।",[54,3304,3306],{"id":3305},"ভুল-২-বিল্ড-টাইমে-রিজলভ-করা","ভুল ২ — বিল্ড টাইমে রিজলভ করা",[42,3308,3309],{},"Tailwind v4-এ এইটা নিঃশব্দে কামড় দেয়।",[87,3311,3313],{"className":1897,"code":3312,"language":1899,"meta":85,"style":85},"\u002F* ভুল — টগল কাজ করা বন্ধ করে দেয় *\u002F\n@theme {\n  --color-surface: var(--surface);\n}\n\n\u002F* ঠিক *\u002F\n@theme inline {\n  --color-surface: var(--surface);\n}\n",[94,3314,3315,3320,3327,3332,3336,3340,3345,3352,3356],{"__ignoreMap":85},[551,3316,3317],{"class":553,"line":554},[551,3318,3319],{"class":1196},"\u002F* ভুল — টগল কাজ করা বন্ধ করে দেয় *\u002F\n",[551,3321,3322,3325],{"class":553,"line":184},[551,3323,3324],{"class":1279},"@theme",[551,3326,1914],{"class":561},[551,3328,3329],{"class":553,"line":181},[551,3330,3331],{"class":561},"  --color-surface: var(--surface);\n",[551,3333,3334],{"class":553,"line":584},[551,3335,1937],{"class":561},[551,3337,3338],{"class":553,"line":596},[551,3339,1263],{"emptyLinePlaceholder":24},[551,3341,3342],{"class":553,"line":604},[551,3343,3344],{"class":1196},"\u002F* ঠিক *\u002F\n",[551,3346,3347,3349],{"class":553,"line":446},[551,3348,3324],{"class":1279},[551,3350,3351],{"class":561}," inline {\n",[551,3353,3354],{"class":553,"line":197},[551,3355,3331],{"class":561},[551,3357,3358],{"class":553,"line":1271},[551,3359,1937],{"class":561},[42,3361,3362,3363,3365,3366,3369,3370,3373],{},"সাধারণ ",[94,3364,3324],{}," ব্লক মানটা বিল্ড টাইমে রিজলভ করে ফেলে — অর্থাৎ ",[94,3367,3368],{},"bg-surface"," কম্পাইল হয়ে একটা fixed hex-এ পরিণত হয়। থিম অ্যাট্রিবিউট বদলালে ভেরিয়েবল বদলায়, কিন্তু ক্লাসটা আর ভেরিয়েবল পড়ছেই না। ",[94,3371,3372],{},"inline"," কি-ওয়ার্ডটা রেফারেন্সটা রানটাইম পর্যন্ত টিকিয়ে রাখে।",[42,3375,3376],{},"লক্ষণটা বিভ্রান্তিকর: থিম টগল \"কাজ করে না\", অথচ ভেরিয়েবলগুলো DevTools-এ ঠিকঠাক বদলাচ্ছে।",[54,3378,3380],{"id":3379},"ভুল-৩-অনেক-বেশি-টোকেন","ভুল ৩ — অনেক বেশি টোকেন",[42,3382,3383],{},"একটা সিস্টেমে ২০০টা স্পেসিং টোকেন থাকলে সেটা সিস্টেম নয়, সেটা একটা অভিধান। কেউ মুখস্থ করবে না, সবাই কাছাকাছি একটা বেছে নেবে, আর ফলাফল হবে ইনকনসিস্টেন্সি — ঠিক যেটা ঠেকাতে সিস্টেমটা বানানো।",[42,3385,3386],{},"কম টোকেন, কড়া নিয়ম। যদি একটা মান বছরে একবার লাগে, সেটা টোকেন নয় — সেটা ওই এক জায়গার একটা মান।",[54,3388,3390],{"id":3389},"ভুল-৪-কম্পোনেন্ট-api-টা-লিখে-না-রাখা","ভুল ৪ — কম্পোনেন্ট API-টা লিখে না রাখা",[42,3392,3393],{},"টোকেন ঠিক থাকলেও কম্পোনেন্ট যদি যা খুশি ক্লাস নেয়, সিস্টেমটা ফাঁকা। প্রতিটা ভ্যারিয়েন্ট এক জায়গায় ঘোষিত থাকা দরকার:",[87,3395,3397],{"className":1947,"code":3396,"language":1949,"meta":85,"style":85},"const button = tv({\n  base: 'inline-flex items-center justify-center rounded-lg',\n  variants: {\n    variant: {\n      primary: 'bg-primary text-on-primary',\n      ghost: 'bg-transparent hover:bg-surface-hover',\n    },\n    size: { sm: 'h-8 px-3', md: 'h-10 px-4' },\n  },\n})\n",[94,3398,3399,3414,3424,3429,3434,3444,3454,3459,3475,3480],{"__ignoreMap":85},[551,3400,3401,3403,3406,3408,3411],{"class":553,"line":554},[551,3402,2590],{"class":1279},[551,3404,3405],{"class":573}," button",[551,3407,2596],{"class":1279},[551,3409,3410],{"class":2550}," tv",[551,3412,3413],{"class":561},"({\n",[551,3415,3416,3419,3422],{"class":553,"line":184},[551,3417,3418],{"class":561},"  base: ",[551,3420,3421],{"class":592},"'inline-flex items-center justify-center rounded-lg'",[551,3423,2020],{"class":561},[551,3425,3426],{"class":553,"line":181},[551,3427,3428],{"class":561},"  variants: {\n",[551,3430,3431],{"class":553,"line":584},[551,3432,3433],{"class":561},"    variant: {\n",[551,3435,3436,3439,3442],{"class":553,"line":596},[551,3437,3438],{"class":561},"      primary: ",[551,3440,3441],{"class":592},"'bg-primary text-on-primary'",[551,3443,2020],{"class":561},[551,3445,3446,3449,3452],{"class":553,"line":604},[551,3447,3448],{"class":561},"      ghost: ",[551,3450,3451],{"class":592},"'bg-transparent hover:bg-surface-hover'",[551,3453,2020],{"class":561},[551,3455,3456],{"class":553,"line":446},[551,3457,3458],{"class":561},"    },\n",[551,3460,3461,3464,3467,3470,3473],{"class":553,"line":197},[551,3462,3463],{"class":561},"    size: { sm: ",[551,3465,3466],{"class":592},"'h-8 px-3'",[551,3468,3469],{"class":561},", md: ",[551,3471,3472],{"class":592},"'h-10 px-4'",[551,3474,2004],{"class":561},[551,3476,3477],{"class":553,"line":1271},[551,3478,3479],{"class":561},"  },\n",[551,3481,3482],{"class":553,"line":1401},[551,3483,3484],{"class":561},"})\n",[42,3486,3487,3488,3491],{},"টেবিলে না থাকলে ভ্যারিয়েন্টটা ",[49,3489,3490],{},"নেই","। এটাই একমাত্র নিয়ম যেটা সিস্টেমকে দুই বছর পরেও সিস্টেম রাখে।",[54,3493,3495],{"id":3494},"যাচাই-করার-উপায়","যাচাই করার উপায়",[42,3497,3498,3499],{},"সিস্টেমটা টিকবে কি না, তার একটাই সৎ পরীক্ষা: ",[49,3500,3501],{},"প্রাইমারি রঙটা বদলে দিন।",[42,3503,3504],{},"একটা ফাইলে একটা লাইন বদলে যদি পুরো প্রোডাক্ট বদলে যায় — দুই থিমেই, কনট্রাস্ট ভেঙে না গিয়ে — তাহলে তিনটা লেয়ার ঠিক আছে। যদি খুঁজে খুঁজে বদলাতে হয়, তাহলে এখনো দুইটা লেয়ার, আর প্রথম রিব্র্যান্ডেই এটা ভাঙবে।",[42,3506,3507],{},"এই পরীক্ষাটা করতে এক দিন লাগে। রিব্র্যান্ডের পর করতে হলে এক কোয়ার্টার লাগে।",[800,3509,3510],{},"html pre.shiki code .sQdni, html code.shiki .sQdni{--shiki-default:#6CB6FF;--shiki-dark:#6CB6FF}html pre.shiki code .sM9_K, html code.shiki .sM9_K{--shiki-default:#ADBAC7;--shiki-dark:#ADBAC7}html pre.shiki code .siJwO, html code.shiki .siJwO{--shiki-default:#F69D50;--shiki-dark:#F69D50}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s0RzX, html code.shiki .s0RzX{--shiki-default:#768390;--shiki-dark:#768390}html pre.shiki code .sEYkB, html code.shiki .sEYkB{--shiki-default:#F47067;--shiki-dark:#F47067}html pre.shiki code .szYpP, html code.shiki .szYpP{--shiki-default:#96D0FF;--shiki-dark:#96D0FF}html pre.shiki code .s-wk_, html code.shiki .s-wk_{--shiki-default:#DCBDFB;--shiki-dark:#DCBDFB}",{"title":85,"searchDepth":181,"depth":181,"links":3512},[3513,3514,3515,3516,3517,3518,3519],{"id":2856,"depth":184,"text":2857},{"id":2996,"depth":184,"text":2997},{"id":3280,"depth":184,"text":3281},{"id":3305,"depth":184,"text":3306},{"id":3379,"depth":184,"text":3380},{"id":3389,"depth":184,"text":3390},{"id":3494,"depth":184,"text":3495},"design-systems","\u002Fcovers\u002Fblog\u002Fbn\u002Fdesign-system-mistakes.webp","2026-07-04","বেশিরভাগ টোকেন সিস্টেম প্রথম রিব্র্যান্ডেই ভেঙে পড়ে। কারণটা প্রায় সবসময় এক — দুইটা লেয়ার আছে, দরকার ছিল তিনটা।",{},"\u002Fblog\u002Fbn\u002Fdesign-system-mistakes",{"title":2847,"description":3523},"blog\u002Fbn\u002Fdesign-system-mistakes",[3529,3530,3531],"ডিজাইন সিস্টেম","টোকেন","Tailwind","_n6iSi6OyccjJuAUoxuUKw9Z6ppo9Cirh56iFPRlryc",{"id":3534,"title":3535,"author":3536,"body":3537,"category":1534,"cover":4252,"coverAlt":3535,"date":4253,"description":4254,"draft":6,"extension":193,"featured":6,"lang":194,"meta":4255,"navigation":24,"path":4256,"readingTime":446,"seo":4257,"seoTitle":190,"stem":4258,"tags":4259,"__hash__":4263},"blog\u002Fblog\u002Fbn\u002Fevent-loop-settimeout-zero.md","setTimeout(fn, 0) সাথে সাথে চলে না কেন",{"name":1133,"role":1134},{"type":39,"value":3538,"toc":4244},[3539,3542,3645,3654,3657,3661,3664,3678,3681,3727,3730,3734,3737,3742,3772,3778,3799,3802,3811,3822,3826,3833,3880,3887,3893,3931,3934,3938,3947,4034,4048,4053,4057,4060,4066,4069,4075,4205,4217,4221,4231,4241],[42,3540,3541],{},"এই কোডটার আউটপুট কী হবে?",[87,3543,3547],{"className":3544,"code":3545,"language":3546,"meta":85,"style":85},"language-js shiki shiki-themes github-dark-dimmed github-dark-dimmed","console.log('১')\n\nsetTimeout(() => console.log('২'), 0)\n\nPromise.resolve().then(() => console.log('৩'))\n\nconsole.log('৪')\n","js",[94,3548,3549,3563,3567,3593,3597,3629,3633],{"__ignoreMap":85},[551,3550,3551,3554,3557,3559,3561],{"class":553,"line":554},[551,3552,3553],{"class":561},"console.",[551,3555,3556],{"class":2550},"log",[551,3558,2088],{"class":561},[551,3560,2607],{"class":592},[551,3562,2570],{"class":561},[551,3564,3565],{"class":553,"line":184},[551,3566,1263],{"emptyLinePlaceholder":24},[551,3568,3569,3572,3575,3577,3580,3582,3584,3586,3589,3591],{"class":553,"line":181},[551,3570,3571],{"class":2550},"setTimeout",[551,3573,3574],{"class":561},"(() ",[551,3576,2745],{"class":1279},[551,3578,3579],{"class":561}," console.",[551,3581,3556],{"class":2550},[551,3583,2088],{"class":561},[551,3585,2612],{"class":592},[551,3587,3588],{"class":561},"), ",[551,3590,530],{"class":573},[551,3592,2570],{"class":561},[551,3594,3595],{"class":553,"line":584},[551,3596,1263],{"emptyLinePlaceholder":24},[551,3598,3599,3602,3605,3608,3611,3614,3616,3618,3620,3622,3624,3626],{"class":553,"line":596},[551,3600,3601],{"class":573},"Promise",[551,3603,3604],{"class":561},".",[551,3606,3607],{"class":2550},"resolve",[551,3609,3610],{"class":561},"().",[551,3612,3613],{"class":2550},"then",[551,3615,3574],{"class":561},[551,3617,2745],{"class":1279},[551,3619,3579],{"class":561},[551,3621,3556],{"class":2550},[551,3623,2088],{"class":561},[551,3625,2617],{"class":592},[551,3627,3628],{"class":561},"))\n",[551,3630,3631],{"class":553,"line":604},[551,3632,1263],{"emptyLinePlaceholder":24},[551,3634,3635,3637,3639,3641,3643],{"class":553,"line":446},[551,3636,3553],{"class":561},[551,3638,3556],{"class":2550},[551,3640,2088],{"class":561},[551,3642,2622],{"class":592},[551,3644,2570],{"class":561},[42,3646,3647,3648,863,3651,3653],{},"উত্তর ",[94,3649,3650],{},"১ ৪ ৩ ২",[94,3652,3571],{},"-এ ০ মিলিসেকেন্ড দেওয়া সত্ত্বেও সেটা সবার শেষে চলে, এমনকি এমন একটা প্রমিসের পরেও যেটা তার পরে লেখা হয়েছে।",[42,3655,3656],{},"\"০ মানে এখনই নয়\" — এইটুকু মনে রাখলে কাজ চলে যায়, কিন্তু কেন নয় সেটা জানলে আর মুখস্থ করতে হয় না।",[54,3658,3660],{"id":3659},"কল-স্ট্যাক-আগে-শেষ-হয়","কল স্ট্যাক আগে শেষ হয়",[42,3662,3663],{},"জাভাস্ক্রিপ্ট সিঙ্গল-থ্রেডেড। যেকোনো মুহূর্তে একটাই জিনিস চলে, আর সেটা কল স্ট্যাকের উপরের ফাংশনটা।",[42,3665,3666,3667,3670,3671,407,3674,3677],{},"ইভেন্ট লুপ কোনো কিছু তুলে নেওয়ার আগে ",[49,3668,3669],{},"স্ট্যাক পুরো খালি হওয়া লাগে","। তাই উপরের কোডে ",[94,3672,3673],{},"console.log('১')",[94,3675,3676],{},"console.log('৪')"," — যেগুলো সিঙ্ক্রোনাস — আগে চলবেই। বাকি সবকিছু সারিতে অপেক্ষা করে।",[42,3679,3680],{},"এখান থেকেই সবচেয়ে সাধারণ বাগটা আসে:",[87,3682,3684],{"className":3544,"code":3683,"language":3546,"meta":85,"style":85},"\u002F\u002F ব্রাউজার এই পুরো লুপটা শেষ না হওয়া পর্যন্ত জমে থাকে\nfor (let i = 0; i \u003C 1e9; i++) {}\n",[94,3685,3686,3691],{"__ignoreMap":85},[551,3687,3688],{"class":553,"line":554},[551,3689,3690],{"class":1196},"\u002F\u002F ব্রাউজার এই পুরো লুপটা শেষ না হওয়া পর্যন্ত জমে থাকে\n",[551,3692,3693,3696,3699,3702,3705,3707,3710,3713,3715,3718,3721,3724],{"class":553,"line":184},[551,3694,3695],{"class":1279},"for",[551,3697,3698],{"class":561}," (",[551,3700,3701],{"class":1279},"let",[551,3703,3704],{"class":561}," i ",[551,3706,1221],{"class":1279},[551,3708,3709],{"class":573}," 0",[551,3711,3712],{"class":561},"; i ",[551,3714,1202],{"class":1279},[551,3716,3717],{"class":573}," 1e9",[551,3719,3720],{"class":561},"; i",[551,3722,3723],{"class":1279},"++",[551,3725,3726],{"class":561},") {}\n",[42,3728,3729],{},"স্ট্যাক খালি না হলে ইভেন্ট লুপ কিছুই করতে পারে না — ক্লিক হ্যান্ডলার চলবে না, রেন্ডারও হবে না। \"পেজ হ্যাং করে আছে\" মানে বেশিরভাগ সময় \"স্ট্যাক খালি হচ্ছে না\"।",[54,3731,3733],{"id":3732},"দুইটা-আলাদা-সারি","দুইটা আলাদা সারি",[42,3735,3736],{},"স্ট্যাক খালি হলে ইভেন্ট লুপ যা দেখে, তা একটা সারি নয় — দুইটা, আর তাদের অগ্রাধিকার আলাদা।",[42,3738,3739],{},[49,3740,3741],{},"মাইক্রোটাস্ক সারি",[876,3743,3744,3756,3762,3767],{},[879,3745,3746,3749,3750,3749,3753],{},[94,3747,3748],{},"Promise.then"," \u002F ",[94,3751,3752],{},".catch",[94,3754,3755],{},".finally",[879,3757,3758,3761],{},[94,3759,3760],{},"await","-এর পরের অংশ",[879,3763,3764],{},[94,3765,3766],{},"queueMicrotask",[879,3768,3769],{},[94,3770,3771],{},"MutationObserver",[42,3773,3774,3777],{},[49,3775,3776],{},"ম্যাক্রোটাস্ক সারি"," (স্পেকে \"টাস্ক\")",[876,3779,3780,3787,3790,3793],{},[879,3781,3782,1505,3784],{},[94,3783,3571],{},[94,3785,3786],{},"setInterval",[879,3788,3789],{},"DOM ইভেন্ট (click, input)",[879,3791,3792],{},"নেটওয়ার্ক কলব্যাক",[879,3794,3795,3798],{},[94,3796,3797],{},"requestAnimationFrame"," (আলাদা ধাপে, রেন্ডারের আগে)",[42,3800,3801],{},"নিয়মটা এক লাইনে:",[2237,3803,3804],{},[42,3805,3806,3807,3810],{},"প্রতিটা ম্যাক্রোটাস্কের পর, ",[49,3808,3809],{},"পুরো"," মাইক্রোটাস্ক সারি খালি করা হয় — তারপর পরের ম্যাক্রোটাস্ক।",[42,3812,3813,3814,3817,3818,3821],{},"তাই ",[94,3815,3816],{},"৩"," (প্রমিস, মাইক্রোটাস্ক) ",[94,3819,3820],{},"২","-এর (টাইমআউট, ম্যাক্রোটাস্ক) আগে চলে। ০ মিলিসেকেন্ড লেখা থাকলেও সেটা অন্য সারিতে, আর ওই সারির পালা পরে।",[54,3823,3825],{"id":3824},"পুরো-শব্দটা-গুরুত্বপূর্ণ","\"পুরো\" শব্দটা গুরুত্বপূর্ণ",[42,3827,3828,3829,3832],{},"মাইক্রোটাস্ক সারি খালি করার সময় নতুন মাইক্রোটাস্ক যোগ হলে সেগুলোও ",[49,3830,3831],{},"একই দফায়"," চলে। এটা সুবিধা, আবার ফাঁদও:",[87,3834,3836],{"className":3544,"code":3835,"language":3546,"meta":85,"style":85},"function loop() {\n  Promise.resolve().then(loop)\n}\nloop() \u002F\u002F পেজ জমে যায়\n",[94,3837,3838,3849,3865,3869],{"__ignoreMap":85},[551,3839,3840,3843,3846],{"class":553,"line":554},[551,3841,3842],{"class":1279},"function",[551,3844,3845],{"class":2550}," loop",[551,3847,3848],{"class":561},"() {\n",[551,3850,3851,3854,3856,3858,3860,3862],{"class":553,"line":184},[551,3852,3853],{"class":573},"  Promise",[551,3855,3604],{"class":561},[551,3857,3607],{"class":2550},[551,3859,3610],{"class":561},[551,3861,3613],{"class":2550},[551,3863,3864],{"class":561},"(loop)\n",[551,3866,3867],{"class":553,"line":181},[551,3868,1937],{"class":561},[551,3870,3871,3874,3877],{"class":553,"line":584},[551,3872,3873],{"class":2550},"loop",[551,3875,3876],{"class":561},"() ",[551,3878,3879],{"class":1196},"\u002F\u002F পেজ জমে যায়\n",[42,3881,3882,3883,3886],{},"এখানে কোনো ইনফিনিট ",[94,3884,3885],{},"while"," নেই, তবু ব্রাউজার আর কিছু করতে পারে না — সারিটা কখনো খালি হয় না, তাই লুপ কখনো পরের ধাপে যায় না।",[42,3888,3889,3890,3892],{},"একই কোড ",[94,3891,3571],{}," দিয়ে লিখলে পেজ সচল থাকে:",[87,3894,3896],{"className":3544,"code":3895,"language":3546,"meta":85,"style":85},"function loop() {\n  setTimeout(loop, 0)\n}\nloop() \u002F\u002F চলতেই থাকে, কিন্তু পেজ ব্যবহারযোগ্য\n",[94,3897,3898,3906,3918,3922],{"__ignoreMap":85},[551,3899,3900,3902,3904],{"class":553,"line":554},[551,3901,3842],{"class":1279},[551,3903,3845],{"class":2550},[551,3905,3848],{"class":561},[551,3907,3908,3911,3914,3916],{"class":553,"line":184},[551,3909,3910],{"class":2550},"  setTimeout",[551,3912,3913],{"class":561},"(loop, ",[551,3915,530],{"class":573},[551,3917,2570],{"class":561},[551,3919,3920],{"class":553,"line":181},[551,3921,1937],{"class":561},[551,3923,3924,3926,3928],{"class":553,"line":584},[551,3925,3873],{"class":2550},[551,3927,3876],{"class":561},[551,3929,3930],{"class":1196},"\u002F\u002F চলতেই থাকে, কিন্তু পেজ ব্যবহারযোগ্য\n",[42,3932,3933],{},"কারণ প্রতিটা ম্যাক্রোটাস্কের মাঝে ব্রাউজার রেন্ডার করার সুযোগ পায়।",[54,3935,3937],{"id":3936},"await-আসলে-কী","await আসলে কী",[42,3939,3940,3942,3943,3946],{},[94,3941,3760],{}," নতুন কিছু নয় — এটা ",[94,3944,3945],{},".then","-এর সিনট্যাক্স।",[87,3948,3950],{"className":3544,"code":3949,"language":3546,"meta":85,"style":85},"async function run() {\n  console.log('ক')\n  await null \u002F\u002F ← এখানেই ফাংশনটা থামে\n  console.log('খ') \u002F\u002F ← এই অংশটা মাইক্রোটাস্ক\n}\n\nrun()\nconsole.log('গ')\n",[94,3951,3952,3964,3978,3989,4005,4009,4013,4021],{"__ignoreMap":85},[551,3953,3954,3957,3959,3962],{"class":553,"line":554},[551,3955,3956],{"class":1279},"async",[551,3958,2662],{"class":1279},[551,3960,3961],{"class":2550}," run",[551,3963,3848],{"class":561},[551,3965,3966,3969,3971,3973,3976],{"class":553,"line":184},[551,3967,3968],{"class":561},"  console.",[551,3970,3556],{"class":2550},[551,3972,2088],{"class":561},[551,3974,3975],{"class":592},"'ক'",[551,3977,2570],{"class":561},[551,3979,3980,3983,3986],{"class":553,"line":181},[551,3981,3982],{"class":1279},"  await",[551,3984,3985],{"class":573}," null",[551,3987,3988],{"class":1196}," \u002F\u002F ← এখানেই ফাংশনটা থামে\n",[551,3990,3991,3993,3995,3997,4000,4002],{"class":553,"line":584},[551,3992,3968],{"class":561},[551,3994,3556],{"class":2550},[551,3996,2088],{"class":561},[551,3998,3999],{"class":592},"'খ'",[551,4001,2142],{"class":561},[551,4003,4004],{"class":1196},"\u002F\u002F ← এই অংশটা মাইক্রোটাস্ক\n",[551,4006,4007],{"class":553,"line":596},[551,4008,1937],{"class":561},[551,4010,4011],{"class":553,"line":604},[551,4012,1263],{"emptyLinePlaceholder":24},[551,4014,4015,4018],{"class":553,"line":446},[551,4016,4017],{"class":2550},"run",[551,4019,4020],{"class":561},"()\n",[551,4022,4023,4025,4027,4029,4032],{"class":553,"line":197},[551,4024,3553],{"class":561},[551,4026,3556],{"class":2550},[551,4028,2088],{"class":561},[551,4030,4031],{"class":592},"'গ'",[551,4033,2570],{"class":561},[42,4035,4036,4037,863,4040,4043,4044,4047],{},"আউটপুট ",[94,4038,4039],{},"ক গ খ",[94,4041,4042],{},"await null"," — যেখানে অপেক্ষা করার মতো কিছুই নেই — তবু ফাংশনটা থামে, বাকিটা মাইক্রোটাস্ক হিসেবে সারিতে যায়, আর ",[94,4045,4046],{},"গ"," আগে চলে।",[42,4049,3813,4050,4052],{},[94,4051,3760],{},"-এর পরের প্রতিটা লাইন কার্যত একটা কলব্যাকের ভেতরে। সিরিয়ালি লেখা যায় বলে এটা ভুলে যাওয়া সহজ।",[54,4054,4056],{"id":4055},"রেন্ডারিং-কোথায়","রেন্ডারিং কোথায়",[42,4058,4059],{},"ব্রাউজার সাধারণত প্রতি ফ্রেমে একবার রেন্ডার করে — মোটামুটি ১৬.৭ms পরপর, ৬০Hz-এ। ধাপটা এরকম:",[87,4061,4064],{"className":4062,"code":4063,"language":92},[90],"ম্যাক্রোটাস্ক → মাইক্রোটাস্ক (সব) → rAF কলব্যাক → স্টাইল → লেআউট → পেইন্ট\n",[94,4065,4063],{"__ignoreMap":85},[42,4067,4068],{},"দুইটা ব্যবহারিক ফল:",[42,4070,4071,4074],{},[49,4072,4073],{},"এক"," — একই টিকে DOM বদলে আবার পড়লে ব্রাউজার জোর করে লেআউট হিসাব করে (layout thrashing):",[87,4076,4078],{"className":3544,"code":4077,"language":3546,"meta":85,"style":85},"\u002F\u002F খারাপ — প্রতি ধাপে জোর করে reflow\nfor (const el of items) {\n  el.style.height = el.offsetHeight + 10 + 'px'\n}\n\n\u002F\u002F ভালো — আগে সব পড়ুন, তারপর সব লিখুন\nconst heights = items.map((el) => el.offsetHeight)\nitems.forEach((el, i) => (el.style.height = heights[i] + 10 + 'px'))\n",[94,4079,4080,4085,4102,4124,4128,4132,4137,4165],{"__ignoreMap":85},[551,4081,4082],{"class":553,"line":554},[551,4083,4084],{"class":1196},"\u002F\u002F খারাপ — প্রতি ধাপে জোর করে reflow\n",[551,4086,4087,4089,4091,4093,4096,4099],{"class":553,"line":184},[551,4088,3695],{"class":1279},[551,4090,3698],{"class":561},[551,4092,2590],{"class":1279},[551,4094,4095],{"class":573}," el",[551,4097,4098],{"class":1279}," of",[551,4100,4101],{"class":561}," items) {\n",[551,4103,4104,4107,4109,4112,4115,4118,4121],{"class":553,"line":181},[551,4105,4106],{"class":561},"  el.style.height ",[551,4108,1221],{"class":1279},[551,4110,4111],{"class":561}," el.offsetHeight ",[551,4113,4114],{"class":1279},"+",[551,4116,4117],{"class":573}," 10",[551,4119,4120],{"class":1279}," +",[551,4122,4123],{"class":592}," 'px'\n",[551,4125,4126],{"class":553,"line":584},[551,4127,1937],{"class":561},[551,4129,4130],{"class":553,"line":596},[551,4131,1263],{"emptyLinePlaceholder":24},[551,4133,4134],{"class":553,"line":604},[551,4135,4136],{"class":1196},"\u002F\u002F ভালো — আগে সব পড়ুন, তারপর সব লিখুন\n",[551,4138,4139,4141,4144,4146,4149,4152,4155,4158,4160,4162],{"class":553,"line":446},[551,4140,2590],{"class":1279},[551,4142,4143],{"class":573}," heights",[551,4145,2596],{"class":1279},[551,4147,4148],{"class":561}," items.",[551,4150,4151],{"class":2550},"map",[551,4153,4154],{"class":561},"((",[551,4156,4157],{"class":1956},"el",[551,4159,2142],{"class":561},[551,4161,2745],{"class":1279},[551,4163,4164],{"class":561}," el.offsetHeight)\n",[551,4166,4167,4170,4173,4175,4177,4179,4182,4184,4186,4189,4191,4194,4196,4198,4200,4203],{"class":553,"line":197},[551,4168,4169],{"class":561},"items.",[551,4171,4172],{"class":2550},"forEach",[551,4174,4154],{"class":561},[551,4176,4157],{"class":1956},[551,4178,1505],{"class":561},[551,4180,4181],{"class":1956},"i",[551,4183,2142],{"class":561},[551,4185,2745],{"class":1279},[551,4187,4188],{"class":561}," (el.style.height ",[551,4190,1221],{"class":1279},[551,4192,4193],{"class":561}," heights[i] ",[551,4195,4114],{"class":1279},[551,4197,4117],{"class":573},[551,4199,4120],{"class":1279},[551,4201,4202],{"class":592}," 'px'",[551,4204,3628],{"class":561},[42,4206,4207,4210,4211,4213,4214,4216],{},[49,4208,4209],{},"দুই"," — অ্যানিমেশন ",[94,4212,3571],{}," দিয়ে নয়, ",[94,4215,3797],{}," দিয়ে। rAF রেন্ডার ধাপের ঠিক আগে চলে, তাই ফ্রেম মিস হয় না।",[54,4218,4220],{"id":4219},"০-আসলে-০-নয়","০ আসলে ০ নয়",[42,4222,4223,4224,4226,4227,4230],{},"শেষ একটা খুঁটিনাটি: HTML স্পেক অনুযায়ী নেস্টেড ",[94,4225,3571],{}," পাঁচ স্তরের পর সর্বনিম্ন ",[49,4228,4229],{},"৪ মিলিসেকেন্ড"," ক্ল্যাম্প হয়। ব্যাকগ্রাউন্ড ট্যাবে ব্রাউজার এটা আরও বাড়িয়ে ১০০০ms-ও করে দিতে পারে।",[42,4232,4233,4234,4237,4238,4240],{},"অর্থাৎ ",[94,4235,4236],{},"setTimeout(fn, 0)"," মানে \"যত দ্রুত সম্ভব\" নয়, মানে \"পরের টাস্ক হিসেবে, সুবিধামতো\"। এখনই দরকার হলে ",[94,4239,3766],{}," আছে — কিন্তু তাতে ব্রাউজার রেন্ডার করার সুযোগ পায় না, যেটা প্রায়ই আপনি চাইছিলেন।",[800,4242,4243],{},"html pre.shiki code .sM9_K, html code.shiki .sM9_K{--shiki-default:#ADBAC7;--shiki-dark:#ADBAC7}html pre.shiki code .s-wk_, html code.shiki .s-wk_{--shiki-default:#DCBDFB;--shiki-dark:#DCBDFB}html pre.shiki code .szYpP, html code.shiki .szYpP{--shiki-default:#96D0FF;--shiki-dark:#96D0FF}html pre.shiki code .sEYkB, html code.shiki .sEYkB{--shiki-default:#F47067;--shiki-dark:#F47067}html pre.shiki code .sQdni, html code.shiki .sQdni{--shiki-default:#6CB6FF;--shiki-dark:#6CB6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .s0RzX, html code.shiki .s0RzX{--shiki-default:#768390;--shiki-dark:#768390}html pre.shiki code .siJwO, html code.shiki .siJwO{--shiki-default:#F69D50;--shiki-dark:#F69D50}",{"title":85,"searchDepth":181,"depth":181,"links":4245},[4246,4247,4248,4249,4250,4251],{"id":3659,"depth":184,"text":3660},{"id":3732,"depth":184,"text":3733},{"id":3824,"depth":184,"text":3825},{"id":3936,"depth":184,"text":3937},{"id":4055,"depth":184,"text":4056},{"id":4219,"depth":184,"text":4220},"\u002Fcovers\u002Fblog\u002Fbn\u002Fevent-loop-settimeout-zero.webp","2026-06-11","ম্যাক্রোটাস্ক, মাইক্রোটাস্ক আর রেন্ডারিং — ইভেন্ট লুপের ধাপগুলো জানলে অ্যাসিঙ্ক কোডের ক্রম আর অনুমান করতে হয় না।",{},"\u002Fblog\u002Fbn\u002Fevent-loop-settimeout-zero",{"title":3535,"description":4254},"blog\u002Fbn\u002Fevent-loop-settimeout-zero",[4260,4261,4262],"JavaScript","ইভেন্ট লুপ","অ্যাসিঙ্ক","sDSuoRwr_XRySGJ1RlFuI9K5Bb1TEKO_ZDlQkE38918",{"id":4265,"title":4266,"author":4267,"body":4268,"category":4421,"cover":4422,"coverAlt":4266,"date":4423,"description":4424,"draft":6,"extension":193,"featured":6,"lang":194,"meta":4425,"navigation":24,"path":177,"readingTime":604,"seo":4426,"seoTitle":190,"stem":4427,"tags":4428,"__hash__":4432},"blog\u002Fblog\u002Fbn\u002Ffreelance-rate-setting.md","ফ্রিল্যান্সিংয়ে রেট ঠিক করা — ঘণ্টার হিসাব থেকে বেরোনোর উপায়",{"name":1878,"role":1879},{"type":39,"value":4269,"toc":4413},[4270,4273,4276,4279,4283,4286,4289,4297,4300,4304,4307,4339,4342,4346,4349,4352,4357,4360,4364,4367,4373,4384,4387,4391,4394,4399,4402,4406],[42,4271,4272],{},"ঘণ্টায় দাম নেওয়ার একটা কাঠামোগত সমস্যা আছে, আর সেটা রেট কম না বেশি তার সাথে সম্পর্কিত নয়।",[42,4274,4275],{},"আপনি যত ভালো হবেন, একই কাজ তত দ্রুত করবেন। ঘণ্টায় বিল করলে দক্ষতা বাড়ার সরাসরি ফল হলো আয় কমা। পাঁচ বছরের অভিজ্ঞতা দিয়ে যে কাজটা তিন ঘণ্টায় করছেন, নতুন কেউ সেটা বারো ঘণ্টায় করবে — এবং চারগুণ বেশি পাবে।",[42,4277,4278],{},"এটা কোনো নৈতিক সমস্যা নয়, হিসাবের সমস্যা। আর সমাধানটা রেট বাড়ানো নয়, ইউনিট বদলানো।",[54,4280,4282],{"id":4281},"ঘণ্টা-নয়-ফল","ঘণ্টা নয়, ফল",[42,4284,4285],{},"ক্লায়েন্ট ঘণ্টা কিনছে না। সে কিনছে একটা কাজ হয়ে যাওয়া — একটা ল্যান্ডিং পেজ যেটা কনভার্ট করে, একটা ড্যাশবোর্ড যেটা তার টিম বুঝতে পারে।",[42,4287,4288],{},"তাই প্রস্তাবটা এভাবে লেখা:",[2237,4290,4291],{},[42,4292,4293,4296],{},[49,4294,4295],{},"ল্যান্ডিং পেজ ডিজাইন ও বিল্ড"," — ৪টি সেকশন, রেসপন্সিভ, দুই রাউন্ড রিভিশন। ডেলিভারি ১২ কর্মদিবস। ৳XX,XXX।",[42,4298,4299],{},"\"৪০ ঘণ্টা × ৳X\" নয়। প্রথমটায় ঝুঁকি আপনার, দ্বিতীয়টায় ঝুঁকি ক্লায়েন্টের — আর ক্লায়েন্ট ঝুঁকি নিতে চায় বলেই আপনাকে ডেকেছে।",[54,4301,4303],{"id":4302},"সংখ্যা-বলার-আগে-যে-প্রশ্নগুলো","সংখ্যা বলার আগে যে প্রশ্নগুলো",[42,4305,4306],{},"দাম বলার আগে অন্তত এই কয়টার উত্তর দরকার। উত্তরগুলো না জেনে দেওয়া প্রতিটা কোটই আসলে একটা অনুমান:",[876,4308,4309,4315,4321,4327,4333],{},[879,4310,4311,4314],{},[49,4312,4313],{},"কে সিদ্ধান্ত নেবে?"," একজন, না কমিটি? অনুমোদনকারীর সংখ্যার সাথে রিভিশনের সংখ্যা প্রায় রৈখিকভাবে বাড়ে।",[879,4316,4317,4320],{},[49,4318,4319],{},"কনটেন্ট কে দেবে?"," \"আপনি লিখে দিন\" একটা আলাদা প্রজেক্ট, এবং সেটাই সবচেয়ে বেশি সময় খায়।",[879,4322,4323,4326],{},[49,4324,4325],{},"কীসের সাথে যুক্ত হবে?"," একটা বিদ্যমান কোডবেস, নাকি নতুন? পুরোনো কোডে ঢোকার সময়টা কেউ হিসাব করে না।",[879,4328,4329,4332],{},[49,4330,4331],{},"ডেডলাইনটা কার?"," কোনো ইভেন্ট বা লঞ্চের সাথে বাঁধা থাকলে বাফার বাড়াতে হবে।",[879,4334,4335,4338],{},[49,4336,4337],{},"\"শেষ\" মানে কী?"," ডিজাইন ফাইল, নাকি ডিপ্লয় করা সাইট? এই একটা প্রশ্নে প্রজেক্টের আকার দ্বিগুণ হতে পারে।",[42,4340,4341],{},"শেষ প্রশ্নটাই সবচেয়ে বেশি টাকা বাঁচায়।",[54,4343,4345],{"id":4344},"বাফারটা-লুকিয়ে-রাখবেন-না","বাফারটা লুকিয়ে রাখবেন না",[42,4347,4348],{},"সবাই বাফার রাখে। বেশিরভাগ মানুষ সেটা রেটের ভেতর লুকিয়ে রাখে, তারপর স্কোপ বাড়লে অস্বস্তিতে পড়ে।",[42,4350,4351],{},"ভালো উপায় হলো সীমাটা লিখে রাখা:",[2237,4353,4354],{},[42,4355,4356],{},"দুই রাউন্ড রিভিশন অন্তর্ভুক্ত। এর পরের প্রতিটি রাউন্ড ৳X,XXX।",[42,4358,4359],{},"এটা ক্লায়েন্টের বিরুদ্ধে নয় — এটা তাকে তথ্য দেয়। এখন সে জানে তৃতীয় রাউন্ডের দাম কত, আর সিদ্ধান্তটা তার হাতে। যেসব প্রজেক্ট তিক্ত হয়, সেগুলোর প্রায় সবগুলোতেই এই লাইনটা ছিল না।",[54,4361,4363],{"id":4362},"প্রথম-সংখ্যাটা-কীভাবে-বের-করবেন","প্রথম সংখ্যাটা কীভাবে বের করবেন",[42,4365,4366],{},"একটা কাজ করা যায়: বছরে যত টাকা দরকার, সেটা থেকে পিছিয়ে হিসাব করুন।",[87,4368,4371],{"className":4369,"code":4370,"language":92},[90],"বার্ষিক লক্ষ্য              ৳১২,০০,০০০\n+ খরচ (সফটওয়্যার, ডিভাইস)     ৳১,০০,০০০\n+ কর ও অনিশ্চয়তা (~২৫%)       ৳৩,২৫,০০০\n────────────────────────────────────────\nমোট দরকার                   ৳১৬,২৫,০০০\n\nবিলযোগ্য সপ্তাহ (ছুটি ও ফাঁকা বাদে)      ৪০\nসপ্তাহে বিলযোগ্য দিন (বাকিটা সেলস, শেখা)  ৩\n────────────────────────────────────────\nবিলযোগ্য দিন                 ১২০\nদৈনিক হার                    ~৳১৩,৫০০\n",[94,4372,4370],{"__ignoreMap":85},[42,4374,4375,4376,4379,4380,4383],{},"গুরুত্বপূর্ণ সংখ্যাটা ",[49,4377,4378],{},"৫২ সপ্তাহ নয়, ৪০"," এবং ",[49,4381,4382],{},"৫ দিন নয়, ৩","। প্রস্তাব লেখা, ইমেইল, ইনভয়েস, নতুন কিছু শেখা — এগুলো কাজের অংশ, কিন্তু কেউ এর বিল দেয় না। ৫ দিন ধরে হিসাব করলে আপনি সপ্তাহে সাত দিন কাজ করেও লক্ষ্যে পৌঁছাবেন না।",[42,4385,4386],{},"এই দৈনিক হারটা ক্লায়েন্টকে বলার জন্য নয়। এটা আপনার নিজের জন্য — একটা ফিক্সড প্রাইস দেওয়ার পর যাচাই করার মাপকাঠি।",[54,4388,4390],{"id":4389},"কম-রেটে-পোর্টফোলিওর-জন্য-কাজ","কম রেটে \"পোর্টফোলিওর জন্য\" কাজ",[42,4392,4393],{},"মাঝে মাঝে যুক্তিসঙ্গত — শুরুতে, বা এমন একটা কাজ যেটা সত্যিই দেখানোর মতো হবে। কিন্তু তখনও ছাড়টা লিখে রাখুন:",[2237,4395,4396],{},[42,4397,4398],{},"স্বাভাবিক মূল্য ৳XX,XXX। এই প্রজেক্টে ৳XX,XXX — কেস স্টাডি হিসেবে প্রকাশের অনুমতির বিনিময়ে।",[42,4400,4401],{},"কারণ ছাড়টা অদৃশ্য হলে সেটাই আপনার রেট হয়ে যায়। ওই ক্লায়েন্ট পরের প্রজেক্টে একই সংখ্যা আশা করবে, আর সে যাকে রেফার করবে সেও তাই করবে।",[54,4403,4405],{"id":4404},"শেষ-কথা","শেষ কথা",[42,4407,4408,4409,4412],{},"রেট নিয়ে সবচেয়ে কাজের পরিবর্তনটা আসলে সংখ্যায় নয় — সেটা হলো ",[49,4410,4411],{},"দাম বলার আগে প্রশ্ন করার অভ্যাস","। যে প্রজেক্টগুলোতে লোকসান হয়, সেগুলো কম রেটের কারণে হয় না; হয় এমন একটা স্কোপের কারণে যেটা কেউ শুরুতে লিখে রাখেনি।",{"title":85,"searchDepth":181,"depth":181,"links":4414},[4415,4416,4417,4418,4419,4420],{"id":4281,"depth":184,"text":4282},{"id":4302,"depth":184,"text":4303},{"id":4344,"depth":184,"text":4345},{"id":4362,"depth":184,"text":4363},{"id":4389,"depth":184,"text":4390},{"id":4404,"depth":184,"text":4405},"career","\u002Fcovers\u002Fblog\u002Fbn\u002Ffreelance-rate-setting.webp","2026-05-19","ঘণ্টায় দাম দিলে আপনি দ্রুত কাজ শেখার জন্য শাস্তি পান। স্কোপ, বাফার আর কীভাবে একটা সংখ্যা বলার আগে প্রশ্নগুলো করতে হয়।",{},{"title":4266,"description":4424},"blog\u002Fbn\u002Ffreelance-rate-setting",[4429,4430,4431],"ফ্রিল্যান্সিং","ক্লায়েন্ট","স্কোপ","8yxqaXSQGybjghhynEf4A_gg6gLhYWP0K74rRs2CbZw",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4434},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4436},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M13.4 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2v-7.4M2 6h4m-4 4h4m-4 4h4m-4 4h4\"\u002F>\u003Cpath d=\"M21.378 5.626a1 1 0 1 0-3.004-3.004l-5.01 5.012a2 2 0 0 0-.506.854l-.837 2.87a.5.5 0 0 0 .62.62l2.87-.837a2 2 0 0 0 .854-.506z\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4438},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m5 8l6 6m-7 0l6-6l2-3M2 5h12M7 2h1m14 20l-5-10l-5 10m2-4h6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4440},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m15 18l-6-6l6-6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4442},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"m9 18l6-6l-6-6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4444},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M15.536 11.293a1 1 0 0 0 0 1.414l2.376 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0zm-13.239 0a1 1 0 0 0 0 1.414l2.377 2.377a1 1 0 0 0 1.414 0l2.377-2.377a1 1 0 0 0 0-1.414L6.088 8.916a1 1 0 0 0-1.414 0zm6.619 6.619a1 1 0 0 0 0 1.415l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.415l-2.377-2.376a1 1 0 0 0-1.414 0zm0-13.238a1 1 0 0 0 0 1.414l2.377 2.376a1 1 0 0 0 1.414 0l2.377-2.376a1 1 0 0 0 0-1.414l-2.377-2.377a1 1 0 0 0-1.414 0z\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4446},"\u003Cpath fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\" d=\"M12 4v16M4 7V5a1 1 0 0 1 1-1h14a1 1 0 0 1 1 1v2M9 20h6\"\u002F>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4448},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M21.54 15H17a2 2 0 0 0-2 2v4.54M7 3.34V5a3 3 0 0 0 3 3a2 2 0 0 1 2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.1.9-2 2-2h3.17M11 21.95V18a2 2 0 0 0-2-2a2 2 0 0 1-2-2v-1a2 2 0 0 0-2-2H2.05\"\u002F>\u003Ccircle cx=\"12\" cy=\"12\" r=\"10\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4450},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M16 20V4a2 2 0 0 0-2-2h-4a2 2 0 0 0-2 2v16\"\u002F>\u003Crect width=\"20\" height=\"14\" x=\"2\" y=\"6\" rx=\"2\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4452},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Crect width=\"20\" height=\"8\" x=\"2\" y=\"2\" rx=\"2\" ry=\"2\"\u002F>\u003Crect width=\"20\" height=\"8\" x=\"2\" y=\"14\" rx=\"2\" ry=\"2\"\u002F>\u003Cpath d=\"M6 6h.01M6 18h.01\"\u002F>\u003C\u002Fg>",{"left":4,"top":4,"width":5,"height":5,"rotate":4,"vFlip":6,"hFlip":6,"body":4454},"\u003Cg fill=\"none\" stroke=\"currentColor\" stroke-linecap=\"round\" stroke-linejoin=\"round\" stroke-width=\"2\">\u003Cpath d=\"M16 7h6v6\"\u002F>\u003Cpath d=\"m22 7l-8.5 8.5l-5-5L2 17\"\u002F>\u003C\u002Fg>",1791741957457]