JUGBD https://jugbd.org Java User Group Bangladesh Fri, 02 Jan 2026 18:54:18 +0000 en-US hourly 1 https://wordpress.org/?v=6.9.4 https://i0.wp.com/jugbd.org/wp-content/uploads/2022/03/cropped-DukeFavicon.webp?fit=32%2C32&ssl=1 JUGBD https://jugbd.org 32 32 135712794 Java Developers’ Conference, 2025 | The Recap https://jugbd.org/java-developers-conference-2025-the-recap/ https://jugbd.org/java-developers-conference-2025-the-recap/#respond Fri, 02 Jan 2026 17:36:41 +0000 https://jugbd.org/?p=68938 For months, JDC 2025 lived in spreadsheets, late-night meetings, and endless planning sessions. But on December 6, standing at the KIB Conference Center and watching the auditorium fill up, it finally became real.

A Day Rooted in Community

 

The Java Developers’ Conference has always been about people. JDC 2025 showed us that this is still true.

From early morning, the venue was buzzing. Developers were meeting friends and welcoming new people. We saw everyone there: students starting out, professionals, and seniors sharing their knowledge.

Throughout the day, the sessions covered the real challenges we face in software today. We explored what’s new in Modern Java (from version 21 to 25) and how to build resilient systems that don’t crash under pressure. Speakers shared lessons on DevOps and platform engineering, and showed us how to handle legacy code without fear. We even looked at the future of AI and context engineering, while others reminded us of the power of core Java without heavy frameworks. The questions you asked and the discussions in the hallways showed how much everyone wants to learn.

Gratitude to Those Who Made It Possible

An event like JDC 2025 is never the effort of a single individual or a small group.

We are sincerely thankful to our speakers, who prepared and delivered thoughtful sessions with clarity and passion. Their willingness to share knowledge and experience continues to be one of the strongest pillars of the Java community.


Our volunteers played a vital role in ensuring the conference ran smoothly. From managing registrations to coordinating sessions and handling on-ground logistics, their dedication and teamwork were evident throughout the day.

We are also grateful to our sponsor, DSi, for supporting the conference. Their contribution helped us bring this edition of JDC to life and allowed us to take a step forward in the scale and ambition of the event.

Looking Ahead

JDC is more than just a one-day event. It is part of a journey to help the Java community in Bangladesh learn and grow.

JDC 2025 showed us that this community is ready for more. We hope this energy continues. We want to see more of you getting involved not just as attendees, but as speakers, volunteers, and organizers.

Thank You

Finally, a heartfelt thanks to everyone who came to JDC 2025. Your presence and trust are what make this event matter.

We appreciate your support and can’t wait to see you at future JUGBD events.

 

Regards,

Tanvir Anjum Rifat
Organizer

]]>
https://jugbd.org/java-developers-conference-2025-the-recap/feed/ 0 68938
JUGBD Nominated for JCP Education Award! https://jugbd.org/jugbd-nominated-for-jcp-education-award/ https://jugbd.org/jugbd-nominated-for-jcp-education-award/#respond Mon, 17 Mar 2025 15:13:14 +0000 https://jugbd.org/?p=65773 JUGBD Nominated for JCP Education Award!

We are beyond thrilled to share some exciting news—Java User Group Bangladesh has been nominated for the Java in Education Community Award at the 22nd Annual Java Community Process (JCP) Awards! This recognition is a testament to our collective efforts in making Java education more accessible and impactful for aspiring developers in Bangladesh.

At its core, the Java in Education initiative is about empowerment—providing students and educators with the tools, resources, and support needed to build a strong foundation in Java programming. It’s about more than just learning a language; it’s about opening doors to opportunities in software development, innovation, and global collaboration.

This nomination isn’t just for us—it belongs to every student who wrote their first System.out.println(“Hello, World!”);, every mentor who guided a newcomer through the nuances of Java, and every community member who contributed to workshops, coding sessions, and knowledge-sharing events.

We are honored to be part of this global movement in advancing Java education and will continue our mission to inspire, teach, and uplift the next generation of developers in Bangladesh. Let’s keep building, learning, and growing—together!

]]>
https://jugbd.org/jugbd-nominated-for-jcp-education-award/feed/ 0 65773
ডিপসিক: নতুন এআই মডেল যা বিশ্ব প্রযুক্তি জগতকে নাড়িয়ে দিচ্ছে https://jugbd.org/deepseek-new-model-impacting-ai-world/ https://jugbd.org/deepseek-new-model-impacting-ai-world/#respond Sun, 09 Feb 2025 06:08:15 +0000 https://jugbd.org/?p=65520

একটি চাইনিজ কোম্পানির রিলিজ করা এআই মডেল ডিপসিক (DeepSeek) হুট করেই প্রযুক্তি বিশ্বে আলোড়ন সৃষ্টি করেছে। জানুয়ারি ২৭ তারিখে এক দিনে NVIDIA’র ভ্যালুয়েশন $৩.৫ ট্রিলিয়ন ডলার থেকে $৬০০ বিলিয়ন কমে $২.৯ ট্রিলিয়ন ডলার হয়ে গেছে! কিন্তু কেন? মনে হতে পারে এআই এর তো অনেক কোম্পানিই আছে ChatGPT এর পাশাপাশি। আর অনেক আগে থেকেই তো যেকোনো প্রযুক্তিতে চাইনিজরা ওয়েস্টের টেকনোলজি ক্লোন বানিয়ে সস্তা মডেল বাজারে আনে—তাহলে ডিপসিক এমন কী আনলো যে, অনেক কিছু উলটপালট হয়ে গেল বা হতে যাচ্ছে বলে ধারণা করা হচ্ছে? শুধু চাইনিজ ‘সস্তা কপি’ বলে? সেটা বোঝার চেষ্টা করছি এই লেখায়।

শীর্ষ এআই মডেল এবং সোর্সকোডের কন্ট্রোল 

মার্কেটে শীর্ষ এআই মডেল বললে অবধারিত ভাবে চলে আসে ওপেনএআই এর চ্যাটজিপিটি। সেপ্টেম্বর ২০২২ এ রিলিজ পাওয়া এই এআই চ্যাটবট দুনিয়ায় হইচই ফেলে দিয়েছিল কৃত্রিম বুদ্ধিমত্তাকে সাধারণ মানুষের ব্যবহার উপযোগী করে সেটাকে ফ্রিতে এক্সেস করতে দিয়ে। পরবর্তিতে কয়েকটা এআই মডেল মার্কেটে আসে। মার্কেটে শীর্ষ তিনটা এআই মডেল বললে বলতে হয় OpenAI এর ‘ChatGPT’, Google এর ‘Gemini’ এবং Anthropic এর ‘Claude’। একটা জিনিস বোঝা ইম্পরট্যান্ট – এরা সবাই “ক্লোজ-সোর্সড”। তার মানে, এরা যে মডেল (Large Language Model সংক্ষেপে – LLM) বানিয়েছে, ইন্টারনেট-স্কেল ডাটা দিয়ে মডেলকে ফাইন-টিউন করেছে, তারপর পাবলিককে ব্যবহার করার সুযোগ দিয়েছে,  কিন্তু সোর্স কোড বা মডেলের নিয়ন্ত্রণ ওই কোম্পানিগুলোর হাতেই রেখে দিয়েছে “ক্লোজ-সোর্সড” করে। তার মানে ইউজাররা তাদের সাইটে যাবে অথবা তাদের API কল করবে, ইউজার ইনপুট দিয়ে ব্যবহার করতে পারবে। এটা ফ্রি বা পেইড, যাই হোক না কেন, কিন্তু দিন শেষে ডাটার সব কন্ট্রোল তাদের হাতেই। কেউ চাইলে লোকাল মেশিনে ডাউনলোড করে বাইরে ইন্টারনেট বন্ধ করে এইসব এআই মডেল চালাতে পারবে না।

এইটা বড় একটা লিমিটেশন। অনেক দিক দিয়ে। শুধু প্রাইভেসি এর দিকটা যদি দেখি – একটা ফাইন্যান্সিয়াল কোম্পানি বা কোনো সরকার বা আর্মি যদি তাদের ডাটা নিয়ে এআই মডেল ট্রেন আপ করিয়ে সেটা কোনো কাজে ব্যবহার করতে চায়—তাহলে সেগুলো যেতে হবে OpenAI, Google বা Anthropic এর সার্ভারে… যা স্বাভাবিকভাবেই বিশাল প্রাইভেসি কনসার্ন এবং জিও-পলিটিক্যাল কারণে বেশিরভাগ সেন্সেটিভ অর্গানাইজেশন, specially যারা US এর বাইরে, এটা করতে চাইবে না।

প্রশ্ন আসবে –  এআই এর ওপেন-সোর্স মডেল কি নেই? উত্তর – আছে। সবচেয়ে জনপ্রিয় হলো (ছিলো বলা যায় এখন!) ফেসবুক/মেটার ‘Llama’, যা জুলাই ২০২৩ এ রিলিজ করা হয়েছিল। আরেকটি আছে Mistral AI, যা একটি ফ্রেঞ্চ কোম্পানির । এর মানে,  এই ওপেন-সোর্স মডেল গুলা যে কেউ locally চালাতে পারবে, বাণিজ্যিকভাবে ব্যবহার করতে পারবে (যদিও মেটার Llama তে কিছু রেস্ট্রিকশন আছে)। সমস্যা হলো, Mistral লাইটওয়েট মডেল হিসেবে ভালো, কিন্তু এর সক্ষমতা কম। মেটার সক্ষমতা Mistral এর চেয়ে বেশি।

এআই মডেল এর সক্ষমতা এবং জিপিউ ব্যবহার

এআই  মডেল গুলোর সক্ষমতা পরিমাপ করার একটা পদ্ধতি হচ্ছে—প্যারামিটার (বা টোকেন) ধারণ করার মান দিয়ে। প্যারামিটার কী? প্যারামিটার অনেকটা ব্রেইন সেলের মতো এআই মডেলে—এগুলো দিয়ে মডেল শেখে, মনে রাখে এবং টেক্সট জেনারেট করে। যত বেশি প্যারামিটার হ্যান্ডেল করতে পারে, আউটপুট সাধারণত তত ভালো হয়। কিন্তু বড় মানেই কি সবসময় ভালো? তা না। এখানে ফাস্ট প্রসেসিং এবং কার্যকর হ্যান্ডলিংও গুরুত্বপূর্ণ। আর বড় মডেলগুলো অনেক বেশি রিসোর্স নেয়, মানে প্রচুর কম্পুটেশন পাওয়ার এবং মেমোরি লাগে এগুলো রান করতে। ওপেন-সোর্স মডেলের মধ্যে Mistral হ্যান্ডেল করতে পারে ৭ বিলিয়ন প্যারামিটার, Meta’র Llama হ্যান্ডেল করতে পারে ৭০ বিলিয়ন প্যারামিটার। ওপেনএআই এর চ্যাটজিপিটি এর মডেল  GPT-3 ১৭৫ বিলিয়ন প্যারামিটার প্রসেস করতে পারে – যা ফ্রি ইউজাররা ব্যবহার করতে পারে। আর পেইড ইউজাররা ওপেনএআই যে মডেলটা ব্যবহার করতে পারে – GPT-4 সেটার সংখ্যা প্রকাশ করা হয়নি, তবে ধারণা করা হয় GPT-4 এক ট্রিলিয়ন প্যারামিটার প্রসেস করতে পারে!

ব্যাপার হচ্ছে, এই মডেলগুলো যত শক্তিশালী, তত উন্নত জিপিউ (GPU) হার্ডওয়্যার লাগে এগুলো চালাতে। জিপিউ শুনে প্রথমে একটু খটকা লাগতে পারে। সবসময় তো কম্পুটেশন এর জন্য সিপিইউ (CPU বা Central Processing Unit) ব্যবহার এর কথা শুনে আসছি আমরা। তাহলে জিপিউ আসলো কেমনে? আসলে GPU বা Graphics Processing Unit বানানো হয়েছিলো specialized গ্রাফিক্স এর কাজের জন্য – যেমন গেমিং। এই জিপিউ দিয়ে অনেক বেশি কম্পিউটেশন একই সময়ে প্রসেস (parallel processing) করা যায় – যেটা এআই এর জন্য খুবই গুরুত্বপূর্ণ। ওপেনএআই সহ সব এআই কোম্পানি তাই  প্রচুর অর্থ ঢালছে শুধু এই জিপিউ কেনার পেছনে। এগুলো অনেক ব্যয়বহুল। যত ফ্রি অ্যাক্সেস দেখা যায়—ChatGPT বা Gemini দিচ্ছে, সবাই মূলত money burn করছে এই ব্যয়বহুল রিসোর্স চালাতে গিয়ে। আর এর পুরো সুবিধা পাচ্ছিল NVIDIA, কারণ তারা প্রয়োজনীয় শক্তিশালী জিপিউ সরবরাহ করতে পারছিলো। আর এজন্যই তাদের স্টক আকাশচুম্বী হয়ে যাচ্ছিলো গত দুই বছর ধরে।আগে প্রসেসর এর কথা বললে সবসময় ইন্টেল সামনে আসতো। কিন্তু এই এআই এর যুগে এসে এআই প্রসেসরের শক্তিমত্তার  প্রতিযোগিতায় অনেক পিছিয়ে পরেছে। অনেকটা মোবাইল ওয়ার্ল্ডে এককালের প্রতাপশালী নকিয়া যেমন স্মার্টফোন এর প্রতিযোগিতায় সামসাং এর কাছে টিকতে পারে নাই। এনভিডিয়ার জিপিউ এর বিশাল প্রভাব এখন এআই এর ডেভেলপমেন্ট এর উপর। যখন এই ধারণা শক্ত হচ্ছিল যে – যত শক্তিশালী মডেল, তত শক্তিশালী জিপিউ প্রসেসর লাগবে, ঠিক তখনই পুরো ঘটনাপ্রবাহ উল্টে দিল এই চাইনিজ কোম্পানি ডিপসিক। কিভাবে, সেটা বলার আগে, চ্যাটজিপিটি এর সবচেয়ে নতুন উন্নত মডেল “o1” সম্পর্কে জেনে নেই। 

ওপেনএআই সেপ্টেম্বর ২০২৪-এ o1 মডেল উন্মোচন করে। ওপেনএআই এর ঘোষণা অনুসারে o1 সিরিজের মডেলগুলো রিইনফোর্সমেন্ট লার্নিং ব্যবহার করে জটিল বিশ্লেষণ করতে পারে। তাদের website এ বলা আছে:

The o1 series of models are trained with reinforcement learning to perform complex reasoning. o1 models think before they answer, producing a long internal chain of thought before responding to the user.

সোজা কথায়, এটাকে বলা যায় “থিংকিং মডেল”। এটি চ্যাটজিপিটি এর বর্তমান GPT-4 মডেলের তুলনায় অনেক ভালো। যেখানে GPT-4 ম্যাথেমেটিক্স অলিম্পিয়াড (IMO) এর মাত্র ১৩% সমস্যা সমাধান করতে পারে, সেখানে এই “o1” মডেল ৮৩% স্কোর করতে পেরেছে। এখানে গুরুত্বপূর্ণ বিষয় হলো, “o1” মডেলটি চ্যাটজিপিটি এর ফ্রি ইউজারদের জন্য উন্মুক্ত নয়। প্লাস ক্যাটাগরির ইউজাররা $২০ ডলার প্রতি মাসে দিয়ে প্রতিদিন কিছু লিমিটেড অ্যাক্সেস পায়, আর $২০০ ডলার দিয়ে প্রো ইউজাররা আনলিমিটেড অ্যাক্সেস পায়। o1 এর  রিসোর্স ব্যবহারের হার অনেক বেশি এবং উচ্চক্ষমতাসম্পন্ন জিপিউ লাগে, যার অপারেশনাল খরচ প্রচুর। ওপেনএআই এর সিইও Sam Altman টুইটারে অভিযোগ করেছেন যে, প্রো সাবস্ক্রিপশনে $২০০ চার্জ করার পরও ওপেনএআই নাকি প্রতি সাবস্ক্রিপশনে “টাকা হারাচ্ছে”!

ডিপসিক – সক্ষমতা এবং প্রভাব

চাইনিজ স্টার্টআপ ডিপসিক এই বছর জানুয়ারির ২০ তারিখে তাদের R1 মডেলটা সাধারণ ব্যবহারকারীদের জন্য উন্মুক্ত করেছে। ডিপসিক এর দুটি এআই মডেল তৈরি আছে, V3 এবং R1। ডিপসিক V3 মডেলটা  ৬৭১ বিলিয়ন প্যারামিটার ব্যবহার করে (বলা যায় মেটার ওপেন-সোর্স মডেল থেকে দশ গুন বেশি), তবে এই মডেলে একটি বিশেষ অপটিমাইজেশন কৌশল ব্যবহার করা হয়েছে যার মাধ্যমে একই সময়ে সর্বাধিক ৩৭ বিলিয়ন টোকেন ব্যবহার করে এটি কাজ করে। এই কৌশলের মাধ্যমে, মডেলটি অপ্রয়োজনীয় ডেটা ব্যবহার করা থেকে বিরত থাকে এবং সবচেয়ে গুরুত্বপূর্ণ তথ্যের ওপর মনোযোগ দিতে পারে। ফলে ডিপসিক মডেল কম রিসোর্স ব্যবহার করে অনেক বেশি কম্পিউটেশনাল দক্ষতা অর্জন করেছে। অন্যদিকে ডিপসিক R1 মডেলটি অন্যভাবে কার্যকরী, যা “রিইনফোর্সমেন্ট লার্নিং” ব্যবহার করে ৭০ বিলিয়ন প্যারামিটার প্রসেস করতে পারে এবং অনেক ফাস্ট এবং এটি চ্যাটজিপিটি o1 মডেলের মতোই “থিংকিং মডেল”। আর সবচেয়ে বড় বিষয় হলো, এটি চালানোর জন্য NVIDIA’র উচ্চক্ষমতাসম্পন্ন জিপিউ লাগবে না।

এখানে একটি বড়  geo-political ওয়ার এর কথা চলে আসে। ২০২২ সালে আমেরিকা NVIDIA’র উচ্চক্ষমতাসম্পন্ন জিপিউ চীনে রপ্তানি নিষিদ্ধ করে দেয়। কিন্তু ডিপসিক এর প্রতিষ্ঠাতা লিয়াং ওয়েনফেং সেই নিষেধাজ্ঞার ঠিক আগেই দশ হাজার NVIDIA’র cutting-edge জিপিউ H100 অর্ডার দিয়ে মজুদ করে ফেলেছিলেন। এই চিপগুলো দিয়েই ডিপসিক তাদের মডেলগুলো ট্রেনিং করেছে, উন্নত করেছে। এমনভাবে অপ্টিমাইজ করেছে, যে, এখন সেটা চালাতে উচ্চক্ষমতাসম্পন্ন জিপিউ লাগবে না, তাই আমেরিকার নিষেধাজ্ঞা কার্যত কোনো বাধা সৃষ্টি করতে পারবে না ডিপসিক প্রডাকশন এ চালাতে। পাশাপাশি, রিসোর্সের খরচ দশ-বিশ গুণের মত কমে গেছে। তাই ডিপসিক অলরেডি চ্যাটজিপিটি থেকে অনেক কম খরচে API বিক্রি করা শুরু করে দিয়েছে।

কিন্তু সবচেয়ে বড় ব্যাপার হলো—তারা এই এআই মডেল গুলো পুরোপুরি ওপেনসোর্স করে ছেড়ে দিয়েছে, এমআইটি ওপেনসোর্স লাইসেন্সের অধীনে। এর মানে, কাউকে ব্যক্তিগত অথবা বাণিজ্যিক ব্যবহারের জন্য ডিপসিক কে টাকা দিতে হবে না। যে কেউ এই এআই মডেল তাদের মেশিনে নামিয়ে অ্যাপ্লিকেশনে ব্যবহার করতে পারবে। এবং এটি চালানোর জন্য উচ্চক্ষমতাসম্পন্ন জিপিউও লাগবে না। ওপেন-সোর্স হওয়ার ফলে এর কার্যকারিতা ও দক্ষতা অনেক দ্রুত বাড়তে থাকবে, কারণ সারা বিশ্বের গবেষকরা এটি ব্যবহার করবে, ট্রেনিং করে আরও উন্নত বানাবে। ডিপসিক তাদের রিসার্চ গুলোও উন্মুক্ত করেছে যেখানে তারা ব্যাখ্যা করেছে যে কীভাবে মডেল অপটিমাইজ করা হয়েছে। সেই রিসার্চ পেপার পড়ে ওপেনএআই এর চিফ রিসার্চ অফিসার পর্যন্ত ডিপসিক-কে অভিনন্দন জানিয়েছেন এবং স্বীকার করেছেন যে, ওপেনএআইও তাদের ক্লোজ-সোর্স o1 মডেলে একই ধরনের পদ্ধতি ব্যবহার করেছে।

মৌলিকতা নাকি কপি-পেস্ট

এখন স্বাভাবিকভাবেই প্রশ্ন আসে—ডিপসিক এর কাজ এর কি টেকনিক্যাল ব্রেকথ্রু বা মৌলিকতা (novelty)  আছে? যেকোনো প্রযুক্তি আসলে সময়ের সাথে আরও দক্ষ, সস্তা এবং সহজলভ্য হয়—এটাই স্বাভাবিক এবং ডিপসিক তো সেটাই করেছে। তাহলে মৌলিকতা প্রশ্নে তাদের কাজের অবস্থান কোথায়? সম্ভবত উত্তর—তেমন মৌলিকতা নেই। 

কিন্তু এটি অত্যন্ত ইম্প্যাক্টফুল এবং গেম-চেঞ্জার। কেন – সেটা বুঝতে হলে কম্পিউটারের এভালুয়েশন ইতিহাসে একটু দৃষ্টি দেওয়া যেতে পারে। আগে কম্পিউটার বিশাল আকৃতির ছিল, অনেক রিসোর্স লাগত, বড় রুম লাগত, অনেক খরচ লাগত চালাতে। তাই কেবল গবেষক বা বিজ্ঞানীরা বড় কোম্পানি বা প্রতিষ্ঠানে এটি ব্যবহার করতে পারতেন। সময়ের সাথে কম্পিউটার ছোট হতে লাগলো, ডেস্কটপ কম্পিউটার হলো, সস্তা হলো, তখন সাধারণ মানুষ এটি কিনে ব্যবহার করতে পারলো। এরপর এটি আরও ছোট হলো, ল্যাপটপ হলো, তারপর স্মার্টফোনে একই ধরনের ক্ষমতা চলে এলো। এখন বিলিয়ন মানুষ হাতের মুঠোয় কম্পিউটারের শক্তি ব্যবহার করছে। এর ফলে আমাদের সমাজ গত কয়েক যুগে কীভাবে বদলে গেছে, সেটা তো আমরা সবাই দেখতে পাচ্ছি। বড় সাইজ কম্পিউটার থেকে ছোট বানানো কি মৌলিক আবিষ্কার? – না হয়তো। কিন্তু অনেক ইম্প্যাক্টফুল

ঠিক একইভাবে, এই সক্ষম AI মডেলগুলো ক্লোজ-সোর্স ছিল, কোম্পানির নিয়ন্ত্রণে ছিল, ওপেনসোর্সগুলো ততটা সক্ষম ছিল না। কিন্তু ডিপসিক এখন একই সক্ষমতার মডেল ওপেনসোর্স করে, কম রিসোর্স ব্যবহার করে চালানোর সুযোগ করে দিয়ে AI এর ব্যাপক বিস্তার বাড়াতে সাহায্য করবে।  এটি হয়তো ‘নভেলটি অফ ইনোভেশন’ নয়, কিন্তু অত্যন্ত প্রভাবশালী।

অনেকে ভাবতে পারে—ডিপসিক শুধুই একটা কপি-পেস্ট কাজ। এটা ভুল। ওপেনএআই বা গুগলের কোনো মডেলই তো ওপেনসোর্স ছিল না, তাই মডেল/অ্যালগোরিদম কপি করার প্রশ্নই আসে না। মেটার ওপেনসোর্স মডেল Llama অনেক কম সক্ষম। তাই তাদেরটাও কপি-পেস্ট করে এরকম পারফরম্যান্স বানাতে পারার কথা না। তবে ডিপসিক মডেল বানানোর পর কিছু ‘ডাটা ট্রেনিং’ চ্যাটজিপিটি এর কাছ থেকে করিয়েছে। কিন্তু মনে রাখতে হবে, চ্যাটজিপিটি নিজেও তো বেশিরভাগ ডাটা নিজে তৈরি করেনি। ইন্টারনেট থেকে, এমনকি কপিরাইটেড কনটেন্ট থেকে স্ক্র্যাপিং করে ডাটা নিয়ে মডেল বানিয়েছে, যার জন্য কারও অনুমতি নেয়নি। তাই বলা যায়, ডিপসিক একই প্যাটার্ন অনুসরণ করছে।

শেষকথা

সারাংশ বললে বলতে হয়, ডিপসিক ইতোমধ্যেই একটি বড় disruptor হয়ে গেছে। এখন যে কেউ যেকোনো ক্লাউডে, বা সেলফ-হোস্টেড মেশিনে ডিপসিক চালাতে পারছে। অনেক আপ্লিক্যাশন আগে যারা বেশি খরচে সার্ভিস দিত, কারণ তাদের চ্যাটজিপিটি API ব্যবহার করতে হতো উচ্চ মূল্যে, তারা এখন হয় ডিপসিক-এর API তে শিফট করছে অথবা সেলফ-হোস্টেড মডেল ব্যবহার করছে। সবচেয়ে গুরুত্বপূর্ণ বিষয় হলো – এখন আর সেন্ট্রালাইজড কন্ট্রোল নেই যেখানে ওপেনএআই বা গুগল-এর হাতে সবকিছু থাকবে। অন্যভাবে বললে, আমেরিকা আগে হয়তো NVDIA কে দিয়ে চিপ সাপ্লাই বন্ধ করে, কিংবা ওপেনএআই  বা গুগলকে চাপ দিয়ে API এক্সেস বন্ধ করে দিয়ে এআই এর উপর এক ধরনের কন্ট্রোল করতে পারতো অন্যদের ব্যবহারে। এখন একই সক্ষমতার ওপেনসোর্স মডেল থাকার কারণে যে কেউ নিজের মতো এটি ম্যানেজ করতে পারবে। তাই এআই এর ক্ষমতা এখন আর মুষ্টিমেয় কিছু প্রতিষ্ঠানের হাতে নেই, বরং এটি আরও বেশি মানুষের কাছে পৌঁছে যাবে। এই পরিবর্তন ভূ-রাজনৈতিক ক্ষমতার ভারসাম্যে গুরুত্বপূর্ণ ভূমিকা রাখবে।

আমরা এখন অত্যন্ত ইন্টারেস্টিং একটি সময়ে বসবাস করছি। এআই প্রযুক্তির ভবিষ্যৎ কোন দিকে যায়, তা আমরা খুব কাছ থেকে দেখার সুযোগ পাচ্ছি!

]]>
https://jugbd.org/deepseek-new-model-impacting-ai-world/feed/ 0 65520
Exciting Announcement: JDC Bangladesh 2024! https://jugbd.org/exciting-announcement-jdc-bangladesh-2024/ https://jugbd.org/exciting-announcement-jdc-bangladesh-2024/#respond Sat, 30 Nov 2024 16:05:28 +0000 https://jugbd.org/?p=65005 Mark your calendars for the Java Developer Conference (JDC) Bangladesh 2024, happening in person on 21st December! This half-day event will be packed with inspiring sessions, amazing speakers, and plenty of opportunities to connect with the Java community.


Registration Opens Soon!
Stay tuned for updates on our official website: jdc.jugbd.org

Interested in Speaking?
We’re now accepting session proposals! Share your expertise and ideas by submitting your talk here:
sessionize.com/java-developers-conference-2024

A Special Thanks to SELISE
We sincerely thank SELISE for their generous sponsorship, setting the stage for an exceptional event that promises to inspire and unite the Java community.


Let’s come together to learn, share, and celebrate the power of Java! Stay tuned for more details—this is an event you won’t want to miss!

#JDC2024 #Java #JUGBD

]]>
https://jugbd.org/exciting-announcement-jdc-bangladesh-2024/feed/ 0 65005
Tracing in Spring Boot3 https://jugbd.org/tracing-in-spring-boot3/ https://jugbd.org/tracing-in-spring-boot3/#respond Mon, 18 Mar 2024 10:59:51 +0000 https://jugbd.org/?p=63758 Looking back on my early professional years, I’m somewhat startled by how I troubleshooted production issues. I was working on a project where I handled everything — from interfacing with customers to coding, deployment, and, naturally, resolving issues. Whenever an issue arose and I lacked a clear solution, my approach was to take a dump of the production database, run the application on my machine with that database, then engage in a call with the customer and attempt to replicate what they were doing, using necessary debug pointers and print statements to pinpoint the problem. This method proved effective for me at the time. The application was small, with a limited user base, and entirely manageable for a single developer. However, I had yet to grasp the importance of logging.

Fast forward a few years, and now I work on projects involving multiple developers, a product owner, a scrum master, an operations team, an infrastructure team, and, of course, millions of users. Importantly, the production environment is mostly inaccessible to us developers. Additionally, customers cannot directly communicate with developers, as that would drive us crazy.

The operations team served as a bridge between these two realms. Their primary task was to investigate issues by examining the system, application logs, and the database if necessary. If they couldn’t find a solution or had insights for improvement, they would then approach developers with the relevant data.

Working in this environment, I began to appreciate the importance of logs. Logs help us trace back through the events in the life of an application or a transaction. With proper analysis, they help derive patterns and even forecast anomalies.

However, I still didn’t know much about distributed tracing (I still know very little). I used to include different identifiers like phone numbers, user IDs, etc., so that our ops team could properly investigate issues for a customer.

But this approach had its problems too. The same customer might have engaged in various interactions with the system, generating multiple streams of logs with their identifier. So pinpointing the exact logs for the issue was still cumbersome. And don’t even start with me about what a nightmare it was when multiple applications were involved. I used to manually add UUIDs in the payloads between service calls and log them.

Eventually, it became evident that my current approach was inadequate. Some of my applications served as middlewares between other applications maintained by different teams. Why would they tolerate my inconvenience?

Then, I discovered Sleuth. It was amazing; adding just one dependency and configuring logging would enable application-wide tracing. Even with multiple microservices in play, there was no need for additional measures to propagate the trace ID among services.

Before Spring Boot 3, whenever I started a project, I always included Spring Cloud Sleuth to enable distributed tracing.

Then came Spring Boot 3, and Sleuth was migrated to Micrometer. In this article, we’ll explore how to achieve Sleuth-like functionality in Spring Boot 3 with Micrometer tracing.

Right now I have a controller and a service with some logs. If I hit the controller endpoint with postman, I get logs like this:

2024-02-23T23:28:18.043+06:00  INFO 14443 --- [rest-api] [nio-8080-exec-2] x.r.t.restapi.web.MessageController   : Received message: Message(header=some header, content=some content)
2024-02-23T23:28:18.046+06:00  INFO 14443 --- [rest-api] [nio-8080-exec-2] x.r.t.r.service.MessageServiceImpl    : Handling message Message(header=some header, content=some content)

It’s clearly discernible that there is no tracing. Now I will add the following dependency:

<dependency>
      <groupId>io.micrometer</groupId>
      <artifactId>micrometer-tracing-bridge-brave</artifactId>
      <scope>compile</scope>
</dependency>

Just hit the same endpoint once again, but still no luck or log!

A bit of internet searching revealed you also need to add actuator to make it work.

It contains an ObservationAutoConfiguration that provides an injectable instance of ObservationRegistry (if it doesn’t already exist), and configures ObservationHandlers for collecting metrics and traces. baeldung.com .

<dependency>
     <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-actuator</artifactId>
     <scope>compile</scope>
</dependency>

Hitting the same endpoint again produces logs like this:

2024-02-24T00:11:06.050+06:00  INFO 18463 --- [rest-api] [nio-8080-exec-1] [65d8dfb96a137925ba56091d26f33e80-ba56091d26f33e80] x.r.t.restapi.web.MessageController   : Received message: Message(header=some header, content=some content)
2024-02-24T00:11:06.053+06:00  INFO 18463 --- [rest-api] [nio-8080-exec-1] [65d8dfb96a137925ba56091d26f33e80-ba56091d26f33e80] x.r.t.r.service.MessageServiceImpl    : Handling message Message(header=some header, content=some content)

See? [65d8dfb96a137925ba56091d26f33e80-ba56091d26f33e80] this part here contains the trace id and span id.

Now let’s see If we can call another service and if traceId gets propagated there.

I have created another service rest-api-2 , which has the necessary controller, service as well as required dependencies.

Now we will use the shiny new rest-client to make an http call from rest-api to rest-api-2.

I have modified the MessageServiceImpl in rest-api to look like this:

@Service
@Slf4j
public class MessageServiceImpl implements MessageService {

 private final RestClient restClient;
 public MessageServiceImpl(@Value("${rest-api-2.url}") String restApi2Url) {
     this.restClient  = RestClient.builder().baseUrl(restApi2Url)
         .defaultHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE).build();

 }

 @Override
 public void handleMessage(Message message) {
     log.info("Handling message {}", message);
     this.restClient.post().uri( "/process-message").body(message).retrieve();

 }

}

Here, In the constructor, I have declared an instance of rest client. Then, in the service I made the call to rest-api-2.

Log for rest-api:

2024-02-24T14:31:13.060+06:00  INFO 29880 --- [rest-api] [nio-8080-exec-5] [65d9a95114390c055da56f5c4e138be3-5da56f5c4e138be3] x.r.t.restapi.web.MessageController   : Received message: Message(header=some header, content=some content)
2024-02-24T14:31:13.061+06:00  INFO 29880 --- [rest-api] [nio-8080-exec-5] [65d9a95114390c055da56f5c4e138be3-5da56f5c4e138be3] x.r.t.r.service.MessageServiceImpl    : Handling message Message(header=some header, content=some content)

Log for rest-api-2:

2024-02-24T14:31:13.072+06:00  INFO 29563 --- [rest-api-2] [nio-8081-exec-7] [65d9a9513ed86cb5ea2477e08166b9d2-ea2477e08166b9d2] x.r.t.r.web.MessageProcessorController   : Received message for processing Message(header=some header, content=some content)
2024-02-24T14:31:13.072+06:00  INFO 29563 --- [rest-api-2] [nio-8081-exec-7] [65d9a9513ed86cb5ea2477e08166b9d2-ea2477e08166b9d2] x.r.t.r.s.MessageProcessorServiceImpl : Processing Message Message(header=some header, content=some content)

We can see that though rest-api-2 has traceId and spanId. But, these doesn’t match! Because it’s starting new trace context for each requests.

This means traceId from first application is not propagating to the second application.

Let’s verify this.

I have stopped the rest-api-2 application, and started listening to the port it was running with a tool called netcat:

Now If it hit the endpoint , I get the following:

We can see, though there supposed to be some header containing traceId, it’s not there. We need to make sure the proper headers with trace context are present in the request.

This is not that tough. We need to use the default restClient builder that spring boot auto-configured for use. Which has necessary knowledge for propagating traceId. We can do this like this:

public MessageServiceImpl(@Value("${rest-api-2.url}") String restApi2Url, RestClient.Builder restClientBuilder) {
     this.restClient  = restClientBuilder.baseUrl(restApi2Url)
         .defaultHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE).build();

 }

We received the default RestClient.Builder through the constructor in the service where we want it to use. Rest of the code is simple. Now if we initiate a request we can see something like this:

Now we have a header called traceparent, and it seems to have the traceId from the log. Now we will stop the netcat and start the rest-api-2 application.

Log from first application:

Log from second application:

And bingo!

We can see the trace id between two applications matches. Though spanId doesn’t match, which is expected.

I think this is a good time to refactor the service. Instead of declaring the rest-client here, we will declare it as a reusable bean in a config class.

Rest client config class looks like this:

@Configuration
public class RestClientConfig {
 @Bean("restApi2Client")
 RestClient restApi2Client(@Value("${rest-api-2.url}") String restApi2Url, RestClient.Builder restClientBuilder) {
     return restClientBuilder.baseUrl(restApi2Url)
         .defaultHeader("Content-Type", MediaType.APPLICATION_JSON_VALUE).build();
 }

}

And refactored MessageServiceImpl class:

@Service
@Slf4j
public class MessageServiceImpl implements MessageService {

 private final RestClient restClient;

 public MessageServiceImpl(@Qualifier("restApi2Client") RestClient restClient) {
     this.restClient = restClient;
 }


 @Override
 public void handleMessage(Message message) {
     log.info("Handling message {}", message);
     this.restClient.post().uri( "/process-message").body(message).retrieve();

 }

}

Cleaner right ?

This is just a basic demo. I plan to write more on how to leverage micrometer for other observability use cases.

Here is the repo for all the codes.

Happy coding!

]]>
https://jugbd.org/tracing-in-spring-boot3/feed/ 0 63758
Working with Old Code: Opportunities for New Programmers https://jugbd.org/working-with-old-code-opportunities-for-new-programmers/ https://jugbd.org/working-with-old-code-opportunities-for-new-programmers/#respond Sun, 20 Aug 2023 03:05:45 +0000 https://jugbd.org/?p=63108 Introduction

New software developers often feel a bit put off by the idea of working with old code. It might not seem very interesting compared to creating something brand new. But this view misses the chances to learn and grow that come with understanding and updating old code. This article looks at the good things that can come from working with existing systems.

The Challenge and Chance to Learn

When starting in software development, many people want to make something new. It’s a normal feeling, but it’s good to know there’s much to gain from working with existing code. It might seem like a limitation, but being able to understand old code is a skill that many people need.

Why Look at More Code Than You Make?

In the real world, programmers often read more code than they create. Getting good at understanding old code can help you stand out. Just like a new writer learns from reading books by great authors, understanding old code enables you to become a better programmer. Looking at code, getting what it does, and fixing it up can turn you into an expert.

Developing the Virtue of Code Reading

In programming, reading code isn’t just a job to do; it’s a skill that needs practice. The article “Read Code Like a Ninja” tells us that we often read code more than we write it. This isn’t just something we do without thinking; it’s more like studying a complex subject. By learning how our minds work and finding ways to read code that fits with that, we can get better at it without wasting time. There are tools and practices to make reading code easier, and just like any skill, the more we do it, the better we get. This way of looking at old code makes it more than just a tedious task. It’s a chance to grow and get better at something that’s at the heart of what programmers do.

Here is a must-read article on this subject that would help you learn to acquire code reading skills: 7 Ways to Improve Your Code Reading Skill.

Fixing and Finding Problems in Code

Learning how to fix up code and find issues is a crucial skill. It’s about more than just stopping code from worsening; it’s about improving it over time. Books like “Refactoring” by Martin Fowler can help you learn these skills. They show you how to keep code working well.

Learning Through Side Projects

Along with working on old code, trying outside projects and looking into new technology helps you learn different skills. This way, you’re not just stuck with old code but are also trying out new things. These projects keep you up to date with what’s new in the field.

Conclusion

Being a software developer isn’t just about working on the latest projects. As software grows and gets older, it turns into what’s called “legacy code.” But that’s where your expertise can shine. Rather than shying away from this aspect of the profession, embracing it can lead to a rewarding and fulfilling career. Remember, knowing all parts of software development and constantly learning is critical to doing well in this field. With an open mind and the right help, even tough old code can be a chance to grow and succeed.

Here are some resources that might help you:

 

]]>
https://jugbd.org/working-with-old-code-opportunities-for-new-programmers/feed/ 0 63108
The Journey of Learning to Code: A Guide to Conquer Your Goals https://jugbd.org/the-journey-of-learning-to-code-a-guide-to-conquer-your-goals/ https://jugbd.org/the-journey-of-learning-to-code-a-guide-to-conquer-your-goals/#respond Sat, 15 Jul 2023 06:13:22 +0000 https://jugbd.org/?p=63019 Learning something new, like coding, can be tough. Sometimes, things can feel boring or too hard to understand. That’s okay. Just keep going. If something feels too hard, skip it for now, finish the rest, and then try it again later.

Our brain tries to save energy and doesn’t want to learn things that it doesn’t think are important. The trick is to convince your brain that coding is important. The best way to do this is to set a time for learning each day. Even if it’s just 25 minutes, make sure you do it every day for the next few months. Soon, your brain will realize that this is something you do a lot, and it’ll start to make it easier for you to learn.

Here’s what you can do to start learning:

  1. Finish the Course: Learn a little bit every day. Don’t just watch the lessons from YouTube or Udemy, but also type out the code yourself. This helps you learn better.

  2. Read a Coding Book: Read a whole book about coding and do the coding exercises in it. This will give you more practice.

Once you’ve done these two things, you can start doing your own projects. This could be a small task or a big project, whatever you like. The idea is to think of something you want to make and then try to code it. If you get stuck, don’t worry. You can always look up ideas on Google, StackOverflow, or GitHub.

GitHub is a really good place to learn from. There are thousands of coding projects on there that you can look at. Try reading some of the code on GitHub. You might not understand everything at first, but that’s okay. The more you do it, the more you’ll learn.

Just like a writer needs to read lots of books to become great, a coder needs to read lots of code. That’s why reading code on GitHub is so important.

This might seem like a lot to take in, but don’t worry. If you have any questions, just ask. The more specific your questions are, the better help you can get.

Remember, learning to code takes time and practice, but if you stick with it, you’ll get there. Keep trying, keep asking questions, and keep coding!

]]>
https://jugbd.org/the-journey-of-learning-to-code-a-guide-to-conquer-your-goals/feed/ 0 63019
SQS With SpringBoot: Some hiccups and their remedies https://jugbd.org/sqs-with-springboot-some-hiccups-and-their-remedies/ https://jugbd.org/sqs-with-springboot-some-hiccups-and-their-remedies/#respond Mon, 03 Jul 2023 07:04:32 +0000 https://jugbd.org/?p=62986

On a rainy day, when the pitter-patter of raindrops orchestrates a symphony against the windowpane, I find solace in the realm of coding. I have embarked on countless coding journeys, each accompanied by its own set of challenges and triumphs. Just like the rain that occasionally dances unpredictably, coding too can have its share of unpredictable moments, where hiccups arise, and we must seek remedies to navigate through them.

In the vast landscape of software development, Spring Boot emerges as a beacon of hope, bringing forth a refreshing breeze of simplicity and efficiency. Like the gentle arrival of spring, it offers a renewed sense of enthusiasm, making the development process more enjoyable and manageable. Spring Boot empowers us to focus on crafting remarkable applications, while it handles the tedious and repetitive configuration tasks behind the scenes.

Now, let’s delve into a fascinating aspect of Spring Boot that has proven to be a valuable ally in building resilient and scalable systems — SQS, or Simple Queue Service. SQS, offered by Amazon Web Services (AWS), is a fully managed message queuing service that allows applications to communicate asynchronously by decoupling the sender and receiver. It acts as a reliable intermediary, ensuring messages are safely delivered between components, even when there are fluctuations in demand or potential failures in the system.

Working with spring boot and SQS is not new for me. Few years ago I worked on a spring boot project where I used SQS. Recently, I got the chance to start a green field project. Having witnessed the proven merits of SQS in the past, I eagerly chose to incorporate it into this new endeavor. However, to my surprise, I found myself stumbling upon unforeseen challenges that I couldn’t recall encountering before. Perhaps in my previous project, I joined the team when it had reached a certain level of maturity, and the configurations were already in place, skillfully handled by another team member. This time, however, my expectation of smooth sailing with minimal configuration for basic use cases was met with unexpected roadblocks.

In this write-up I’ll share the challenges I’ve faced and what I did to overcome those challenges.

At first I created a new spring boot project with spring initializer. I’m using spring boot version 2.7.7. As now I have bootstrapped the project now need an SQS instance to test our development. I don’t want to spin up a real sqs instance. To save some bucks, rather I prefer to deploy a local sqs with docker. Here is the docker compose:

version: "3"

services:
  sqs:
    image: roribio16/alpine-sqs
    ports:
      - '9334:9324'
      - '9335:9325'
    volumes:
      - my-datavolume:/sqs-data
volumes:
  my-datavolume:

Just for this demo I picked this roribio16/alpine-sqs image. It is lightweight, and also has an UI. Whereas localstack is a bit heavy.

Now a docker compose up should bring us an sqs up and running.

So here is the Idea. I’ll have a dto Task like this:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Task {
   private String id;
   private String name;
   private String description;
}

And a controller like this:

@PostMapping("/task")
public void createTask(@RequestBody Task task){
   log.info("Received task {}", task.toString());
   queueService.publishTask(task);
}

So that I can POST tasks in this endpoint and this endpoint will call a method in queueService, that will have the necessary codes to publish the tasks to the sqs.

Later we will create a listener class that will receive the tasks from queue and do some heavy(!!) computation.. Nah, just some logs but should be able to convey the idea.

With spring-cloud-starter-aws-messaging we get QueueMessagingTemplate. It is an abstraction to easily publish/receive messages to queue. It also provides apis to configure various converters.

So, we are going to create a Bean of QueueMessagingTemplate. To construct functional QueuMessagingTemplate we will also need an instance of SqsClient. We will create both of them in a class named SQSConfig.

@Configuration
public class SqsConfig {
 private final int BATCH_SIZE = 10;
 private final String queueEndpoint;

 public SqsConfig(@Value("${queue.endpoint}") String queueEndpoint) {
     this.queueEndpoint = queueEndpoint;
 }

 @Bean
 @Primary
 public AmazonSQSAsync amazonSQSAsync(@Value("${spring.profiles.active}") String profile){
     if(profile.equals("dev")){
         return AmazonSQSAsyncClientBuilder
                 .standard()
                 .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(queueEndpoint,
                         Region.AP_SOUTHEAST_1.id()))
                 .build();
     }
     else{
         return AmazonSQSAsyncClientBuilder
                 .standard()
                 .withRegion(Region.AP_SOUTHEAST_1.id())
                 .build();
     }
 }

 @Bean
 public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSQSAsync) {
     return new QueueMessagingTemplate(amazonSQSAsync);

 }

As in my dev environment I have my own sqs running at http://127.0.0.1:9334 which is not the usual sqs endpoint that’s why I instantiated with AmazonSQSAsyncClientBuilder mentioning the endpoint for the dev profile.

Now it’s time to create an implementation of the QueueService. We will take queueMessagingTemplate in the constructor and use it’s convertAndSend method to publish a message to our queue.

@Slf4j
@Service
public class QueueServiceImpl implements QueueService {
 private final QueueMessagingTemplate queueMessagingTemplate;
 private final String taskQueue;

 public QueueServiceImpl(QueueMessagingTemplate queueMessagingTemplate,
                         @Value("${queue.task}") String taskQueue) {
     this.queueMessagingTemplate = queueMessagingTemplate;
     this.taskQueue = taskQueue;
 }

 @Override
 public void publishTask(Task task) {

     task.setId(UUID.randomUUID().toString());
     log.info("Publishing task to queue {}", task);

     queueMessagingTemplate.convertAndSend(taskQueue, task);
     
 }
}

Let’s restart the server and hope everything compiles. Then run the following curl:

curl --location 'http://localhost:8080/task' \
--header 'Content-Type: application/json' \
--data '{
 "name":"Task 1",
 "description": "save the world"
}'

Now if we go to http://localhost:9335/ in our browser and click on the tab of our queue we will be able to see the message.

Message will be there unless a consumer receives the message and deletes it.

(For brevity I skipped the part of creating the queue. You can use an utility script or aws cli to do this.)

First Hiccup: Time module

So far, so good. Now I will change the Dto. I want to add an Instant field called arrivedAt. I will populate the field just before publishing to the queue. I have now updated the dto and publishTask method.

@Override
public void publishTask(Task task) {

    task.setId(UUID.randomUUID().toString());
    task.setArrivedAt(Instant.now());
    log.info("Publishing task to queue {}", task);

    queueMessagingTemplate.convertAndSend(taskQueue, task);

}

After restarting the application if we hit the curl again then …boom!

From this error message, I could determine that somewhere it is using ObjectMapper. An old friend of all Java developers and we all know when we use Instant, we have to instantiate ObjectMapper a bit differently. Which is easy. But the question is, how do we configure QueueMessageTemplate to use this custom ObjectMapper.

With some googling and reading the documentation, I found that by default it’s using SimpleMessageConverter. Found the source code here , I’ll be adding my own message converter like this. But before that, I’ll create a bean for ObjectMapper:

@Configuration
public class ObjectMapperConfig {
 @Bean
 ObjectMapper getObjectMapper(){
     return new ObjectMapper().registerModule(new JavaTimeModule());
 }
}

Now I’ll write my own message converter and there I’ll use the object mapper to convert the payload into string before giving the Message object to sqs.

My message converter implements a MessageConveter interface that has two methods fromMessage and toMessage. Right now, I am only publishing message to sqs. So I will add my custom implementation in toMessage method, and for fromMessage I’ll just copy the implementation from SimpleMessageConverter.

public class MyMessageConverter implements MessageConverter {
 private final ObjectMapper objectMapper;

 public MyMessageConverter(ObjectMapper objectMapper) {
     this.objectMapper = objectMapper;
 }

 @Override
 public Object fromMessage(Message<?> message, Class<?> targetClass) {
     return null;
 }

 @Override
 public Message<?> toMessage(Object payload, MessageHeaders headers) {
     if (headers != null) {
         MessageHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(headers, MessageHeaderAccessor.class);
         if (accessor != null && accessor.isMutable()) {
             return MessageBuilder.createMessage(getStringPayload(payload), accessor.getMessageHeaders());
         }
     }

     return MessageBuilder.withPayload(getStringPayload(payload)).copyHeaders(headers).build();
 }

 private String getStringPayload(Object payload){
     try {
         return objectMapper.writeValueAsString(payload);
     } catch (JsonProcessingException e) {
         throw new RuntimeException(e);
     }
 }
}

Here actually, toMessage is also a copy from SimpleMessageConverter, the deviation is in the converting of the payload to string inside MessageBuilder’s withPayload method.

Finally plug in MyMessageConverter with QueueMessagingTemplate:

@Bean
public QueueMessagingTemplate queueMessagingTemplate(AmazonSQSAsync amazonSQSAsync, MyMessageConverter myMessageConverter) {
   QueueMessagingTemplate queueMessagingTemplate = new QueueMessagingTemplate(amazonSQSAsync);
   queueMessagingTemplate.setMessageConverter(myMessageConverter);
   return queueMessagingTemplate;

}

Now if I restart the server and hit the cURL, the error should go away, and in the sqs’s web interface I should be able to see the published message with the new arrivedAt field:

Second Hiccup: Listener Not Receiving Object

So far we managed to publish the message from the controller to the queue. This is a good time to start listening to the queue for messages. So we add a service and annotate a method with @SqsListener:

@Service
@Slf4j
public class TaskProcessorImpl implements TaskProcessor {
 @Override
 @SqsListener(value = "dev-task.std",deletionPolicy = SqsMessageDeletionPolicy.ON_SUCCESS)
 public void process(String task) {
     log.info("Processing task {}", task);
 }
}

This is enough for receiving messages as string payload. If we restart the application we can see the logs like this:

2023-06-28 12:44:21.522  INFO 10804 --- [enerContainer-2] x.r.sqsdemo.service.TaskProcessorImpl : Processing task {"id":"2813920f-589e-44ff-a38a-aeb87fd2b021","name":"Task 1","description":"save the world","arrivedAt":1687934661.470700713}

 

That means we are able to receive messages. We can now parse the string to object and do whatever we want.

But, can we receive the object in the method annotated with SqsListener?

Probably we can, let’s change the type from String to Task.

@Service
@Slf4j
public class TaskProcessorImpl implements TaskProcessor {
 @Override
 @SqsListener(value = "dev-task.std",deletionPolicy = SqsMessageDeletionPolicy.ALWAYS)
 @MessageMapping
 public void process(Task task) {
     log.info("Processing task {}", task);
 }
}

Now, restart the application and try to publish the message, you’ll see the console is again flooded with errors.
Because, we need to let sqs know how it could convert the receiving strings to object. So we add a bean of QueueMessageHandlerFactory.

@Bean
public QueueMessageHandlerFactory queueMessageHandlerFactory(ObjectMapper objectMapper, 
  AmazonSQSAsync amazonSQSAsync) {
     MappingJackson2MessageConverter messageConverter = new MappingJackson2MessageConverter();
     messageConverter.setObjectMapper(objectMapper);
     messageConverter.setStrictContentTypeMatch(false);

     QueueMessageHandlerFactory factory = new QueueMessageHandlerFactory();
     factory.setAmazonSqs(amazonSQSAsync);

     List<HandlerMethodArgumentResolver> resolvers = List.of(
             new PayloadMethodArgumentResolver(messageConverter,null, false));
     factory.setArgumentResolvers(resolvers);

     return factory;
 }

Next we will also need to annotate the first parameter of the process method as @Payload.

Now, we can receive objects directly from the listener.

Third Hiccup: Sleuth traceId not propagating

This was kind of surprising for me. Because, over the last few years. I never had to handle the propagation of sleuth ids in logs. As we are using sqs with clients or libraries from the spring eco-system, I expected that it would work out of the box.

But it didn’t. To achieve this, I had to read traceId, spanId from current span and add them in the headers before publishing the queue.

And on the listener side I have to start a new span after reading those ids from the message’s header then injecting it into a new trace context.

At first, let’s work on passing the traceId and spanId in the messages we publishing.

In QueueServiceImpl we add the following method:

private Map<String, Object> headers() {
     return Map.of(
             "SleuthTraceId",tracer.currentSpan().context().traceId(),
             "SleuthSpanId", tracer.currentSpan().context().spanId());
 }

Then pass the headers with convertAndSend like this:

queueMessagingTemplate.convertAndSend(taskQueue, task, headers());

Now, we are also going to need to capture the headers in the listener so that we can use them.

This is not hard. Just need to add a new argument which is a Map<String, Object> and annotate the parameter with @Headers annotation.

@Override
@SqsListener(value = "dev-task.std",deletionPolicy = SqsMessageDeletionPolicy.ALWAYS)
@MessageMapping
public void process(@Payload Task task, @Headers Map<String, Object> headers) {
   log.info("Processing task {}", task);
}

If we restart the application, publish a new message and put a debug pointer in the body of process method and try to see what does headers is containing we’ll find something like this:

Hmm, both traceId and spanId are now in the headers.

Let’s separate them and create a new traceContext with them, so that all the subsequent logs prints them.

So our modified process method looks like this now:

@Override
@SqsListener(value = "dev-task.std",deletionPolicy = SqsMessageDeletionPolicy.ALWAYS)
@MessageMapping
public void process(@Payload Task task, @Headers Map<String, Object> headers) {

   var traceId = headers.get("SleuthTraceId");
   var spanId = headers.get("SleuthSpanId");

   TraceContext traceContext = TraceContext.newBuilder()
           .traceId((Long) traceId)
           .spanId((Long) spanId)
           .build();

   Span span = tracer.nextSpan(TraceContextOrSamplingFlags.create(traceContext));

   try(Tracer.SpanInScope scope = tracer.withSpanInScope(span)){
       log.info("Processing task {}", task);
   } catch (Throwable e) {
       throw new RuntimeException(e);
   } finally {
       span.finish();
   }

}

Now logs will look like this:

2023-07-02 | 13:17:59.237 | http-nio-8080-exec-6 |  INFO | xyz.ruhshan.sqsdemo.web.TaskController   |9e0e13588a8f5aeb,9e0e13588a8f5aeb| Received task Task(id=null, name=Task 1, description=save the world, arrivedAt=null)
2023-07-02 | 13:17:59.237 | http-nio-8080-exec-6 |  INFO | x.r.sqsdemo.service.QueueServiceImpl  |9e0e13588a8f5aeb,9e0e13588a8f5aeb| Publishing task to queue Task(id=919e794e-ad48-4cc7-8102-6527ba98d4cd, name=Task 1, description=save the world, arrivedAt=2023-07-02T07:17:59.237655Z)
2023-07-02 | 13:17:59.245 | eListenerContainer-2 |  INFO | x.r.sqsdemo.service.TaskProcessorImpl |9e0e13588a8f5aeb,9d462662007f81cd| Processing task Task(id=919e794e-ad48-4cc7-8102-6527ba98d4cd, name=Task 1, description=save the world, arrivedAt=2023-07-02T07:17:59.237655Z)

Yay! same traceId is present in the logs before publishing to queue and after receiving from queue.

Yeah, I know you are frowning.

Though it works. But it’s not clean. If we have multiple queues, we could have multiple listeners. And putting the same extract/construct/start span-code chunk in multiple places breaks the DRY principle.

What can we do?

There should be many ways. I’m sharing what I did.

I just made the following changes:

@Override
@SqsListener(value = "dev-task.std",deletionPolicy = SqsMessageDeletionPolicy.ALWAYS)
@MessageMapping
@InjectSleuthIds
public void process(@Payload Task task, @Headers Map<String, Object> headers) {

   log.info("Processing task {}", task);

}

Yes, just added another annotation @InjectSleuthIds . But where did it come from? Unfortunately I had to create it. Then also used our old friend AOP to add the whole functionality of reading sleuthIds from sqs headers and spawn a new span with them.

It’s done in a separate class. But this is the most interesting method on that class:

@Around("@annotation(xyz.ruhshan.sqsdemo.aop.InjectSleuthIds)")
public Object injectSleuthIdsAroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {

   SleuthIds sleuthIds = getSleuthIdsFromPjp(proceedingJoinPoint);

   TraceContext traceContext = TraceContext.newBuilder()
           .traceId(sleuthIds.traceId)
           .spanId(sleuthIds.spanId)
           .build();

   Span span = tracer.nextSpan(TraceContextOrSamplingFlags.create(traceContext));

   try (var scope = tracer.withSpanInScope(span)) {
       return proceedingJoinPoint.proceed();
   } catch (Throwable e) {
       log.error("Caught exception during proceeding join-point {}", e.getMessage());
       throw new RuntimeException(e);
   } finally {
       span.finish();
   }
}

Everything is pretty obvious for you if you know about aspect oriented programming. But if you do not. Here are my 2 cents for you:

  1. Making the method annotated with @Around(“@annotation(xyz.ruhshan.sqsdemo.aop.InjectSleuthIds)”) does a very special thing. Part of this method will be executed before the actual method execution which is annotated with @InjectSleuthIds, and part of the method will be executed after.
  2. ProceedingJoinPoint is an interface that gives us access to the arguments that our target annotated method is receiving and also methods to invoke the target method.

Using the helper method getSleuthIdsFromPjp I extracted traceId and spanId from the proceedingJoinPoint.

Then create the spanContext.

Then start the next span.

proceedingJoinPoint.proceed() is the invocation of our annotated target method. Wrapping this using try with resource statement and in the resource part running tracer.withSpanInScope(span) does the magic of printing the sleuth Ids in logs.

Don’t get me wrong. This will not only add sleuth ids for methods annotated with InjectSleuthIds annotation, but also all the subsequent methods in the invocation chain which could start from an annotated method.

I hope you have enjoyed this write-up. If you know better ways to deal with the issues I have faced, I’ll be very much obliged to know about them. Feel free to provide any kind of feedback.

Here is the complete source code of this demo.

]]>
https://jugbd.org/sqs-with-springboot-some-hiccups-and-their-remedies/feed/ 0 62986
How Byte codes are interpreted by JVM? https://jugbd.org/how-byte-codes-are-interpreted-by-jvm/ https://jugbd.org/how-byte-codes-are-interpreted-by-jvm/#respond Sun, 21 May 2023 18:08:56 +0000 https://jugbd.org/?p=62862 High-level language like Java requires the compiler to translate source code to highly optimized byte code, then byte code is interpreted by the JVM interpreter. Bytecode is generated by the javac compiler when source code is compiled, and produced as a .class file.

Did you have the question in your mind that is .class file contains nothing but hexadecimal code? but which code is used for which purpose? if then you are in the right place to go through!

let’s write code for subtract operation, and we will generate bytecode through compile.

public class AddToValue {
  public static void main(String[] args) {
    long maxLong = Long.MAX_VALUE;
    long secondMinimumPositiveLong = 1;
    long secondMaxLong = maxLong - secondMinimumPositiveLong;
    System.out.println(secondMaxLong);
  }
}

This high-level language hides the complexity of how JVM or theoperating system will read this code. Suppose we have declared the max long value, this is a simple instruction to us but how the value of maxLong variable is loaded to the CPU register is not our headache. we have to be relayed on the abstract layer.

although high-level code must be converted to instruction machine code-named as bytecode.

let’s compile this program.

javac AddToValue.java

we will get output like this

cafe babe 0000 0037 001f 0a00 0800 1107
0012 057f ffff ffff ffff ff09 0013 0014
0a00 1500 1607 0017 0700 1801 0006 3c69
6e69 743e 0100 0328 2956 0100 0443 6f64
6501 000f 4c69 6e65 4e75 6d62 6572 5461
626c 6501 0004 6d61 696e 0100 1628 5b4c
6a61 7661 2f6c 616e 672f 5374 7269 6e67
3b29 5601 000a 536f 7572 6365 4669 6c65
0100 0f41 6464 546f 5661 6c75 652e 6a61
7661 0c00 0900 0a01 000e 6a61 7661 2f6c
616e 672f 4c6f 6e67 0700 190c 001a 001b
0700 1c0c 001d 001e 0100 0a41 6464 546f
5661 6c75 6501 0010 6a61 7661 2f6c 616e
672f 4f62 6a65 6374 0100 106a 6176 612f
6c61 6e67 2f53 7973 7465 6d01 0003 6f75
7401 0015 4c6a 6176 612f 696f 2f50 7269
6e74 5374 7265 616d 3b01 0013 6a61 7661
2f69 6f2f 5072 696e 7453 7472 6561 6d01
0007 7072 696e 746c 6e01 0004 284a 2956
0021 0007 0008 0000 0000 0002 0001 0009
000a 0001 000b 0000 001d 0001 0001 0000
0005 2ab7 0001 b100 0000 0100 0c00 0000
0600 0100 0000 0100 0900 0d00 0e00 0100
0b00 0000 3c00 0400 0700 0000 1414 0003
400a 421f 2165 3705 b200 0516 05b6 0006
b100 0000 0100 0c00 0000 1600 0500 0000
0300 0400 0400 0600 0500 0b00 0600 1300
0700 0100 0f00 0000 0200 10

According to The Java Virtual Machine Instruction Set there are 256 possible bytecode instructions. generated bytecode contains instructions among them, we will find out which instruction is used for which bytecode down the line. this instructions set vary x86 to x64 another reason is that JVM tries to use a specific register for an instruction, if the processor does not have this register or is not compatible then used a stack for that operation.

let’s disassemble this class and we will print the instructions from the bytecode.

javap -c AddToValue.class

Compiled from "AddToValue.java"
public class AddToValue {
  public AddToValue();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: ldc2_w        #3                  // long 9223372036854775807l
       3: lstore_1
       4: lconst_1
       5: lstore_3
       6: lload_1
       7: lload_3
       8: lsub
       9: lstore        5
      11: getstatic     #5                  // Field java/lang/System.out:Ljava/io/PrintStream;
      14: lload         5
      16: invokevirtual #6                  // Method java/io/PrintStream.println:(J)V
      19: return
}

We will map bytecode with these printed instructions, first, we have to understand some term 

opcode: opcode is operation code, also known as instruction machine code, that specifies the operation to be performed. ex:

operand stack: The operand stack is a 32-bit, used to store value and return once instructions are invoked.

mnemonic: Short description of the instruction ex: istore_1

theorem: the mnemonic form of opcode => mnemonic = opcode

now we will subtract operation instructions

long maxLong = Long.MAX_VALUE;
long secondMinimumPositiveLong = 1;
long secondMaxLong = maxLong - secondMinimumPositiveLong;

for these human-readable instructions, we got 8 opcode instructions

0: ldc2_w        #3                  // long 9223372036854775807l
3: lstore_1
4: lconst_1
5: lstore_3
6: lload_1
7: lload_3
8: lsub
9: lstore        5

opcode instructions corresponding hexadecimal value

Mnemonic Opcode
ldc2_w 14
lstore_1 40
lconst_1 0a
lstore_3 42
lload_1 1f
lload_3 21
lsub 65
lstore 37

this series of hexadecimal codes will exist within this .class file.

Bytecode
cafe babe 0000 0037 001f 0a00 0800 1107
0012 057f ffff ffff ffff ff09 0013 0014
0a00 1500 1607 0017 0700 1801 0006 3c69
6e69 743e 0100 0328 2956 0100 0443 6f64
6501 000f 4c69 6e65 4e75 6d62 6572 5461
626c 6501 0004 6d61 696e 0100 1628 5b4c
6a61 7661 2f6c 616e 672f 5374 7269 6e67
3b29 5601 000a 536f 7572 6365 4669 6c65
0100 0f41 6464 546f 5661 6c75 652e 6a61
7661 0c00 0900 0a01 000e 6a61 7661 2f6c
616e 672f 4c6f 6e67 0700 190c 001a 001b
0700 1c0c 001d 001e 0100 0a41 6464 546f
5661 6c75 6501 0010 6a61 7661 2f6c 616e
672f 4f62 6a65 6374 0100 106a 6176 612f
6c61 6e67 2f53 7973 7465 6d01 0003 6f75
7401 0015 4c6a 6176 612f 696f 2f50 7269
6e74 5374 7265 616d 3b01 0013 6a61 7661
2f69 6f2f 5072 696e 7453 7472 6561 6d01
0007 7072 696e 746c 6e01 0004 284a 2956
0021 0007 0008 0000 0000 0002 0001 0009
000a 0001 000b 0000 001d 0001 0001 0000
0005 2ab7 0001 b100 0000 0100 0c00 0000
0600 0100 0000 0100 0900 0d00 0e00 0100
0b00 0000 3c00 0400 0700 0000 1414 0003
400a 421f 2165 3705 b200 0516 05b6 0006 (40 0a 42 1f 21 65 37 05 -> lstore_1 lconst_1 lstore_3 lload_1 lload_3 lsub lstore)
b100 0000 0100 0c00 0000 1600 0500 0000
0300 0400 0400 0600 0500 0b00 0600 1300
0700 0100 0f00 0000 0200 10

Operand Stack Preparation from these instructions:

Mnemonic Description
ldc2_w push 9223372036854775807l to stack from constant pool
lstore_1 store 9223372036854775807l in a local variable 1
lconst_1 push 1l onto the stack
lstore_3 store 1l in a local variable 3
lload_1 load 9223372036854775807l from a local variable 1
lload_3 load 1l from a local variable 3
lsub subtract 9223372036854775807l – 1l
lstore store 9223372036854775806l in a local variable #index

In summary, we have seen how byte code holds the instruction need to be executed by JVM also mapping is made between Mnemonic and opcode in hexadecimal form.

ref:

  1. List of Java bytecode instructions
  2. The Java Virtual Machine Instruction Set
  3. The Java Virtual Machine
]]>
https://jugbd.org/how-byte-codes-are-interpreted-by-jvm/feed/ 0 62862
Kickstarting Your Coding Journey: Backend-Focused Project Ideas for Beginners Incorporating Basic Frontend Skills https://jugbd.org/kickstarting-your-coding-journey-backend-focused-project-ideas-for-beginners-incorporating-basic-frontend-skills/ https://jugbd.org/kickstarting-your-coding-journey-backend-focused-project-ideas-for-beginners-incorporating-basic-frontend-skills/#respond Wed, 10 May 2023 22:38:15 +0000 https://jugbd.org/?p=62928 Question: Could you provide some beginner-level project ideas, especially with a backend focus, but also incorporating some basic frontend aspects? I have completed training in Spring Core and MVC and am aiming to utilize these skills in my project.

 

Since you’ve finished learning Spring Core and MVC, and are focusing more on backend development, here are some ideas that involve backend logic and can also incorporate some frontend basic skills:

  1. Restful Bookstore: Build a RESTful API for a bookstore using Spring Boot and Spring MVC. It should allow users to add, delete, update, and retrieve books. A book could have attributes like ISBN, title, author, and publication date.
  2. Online Voting System: Create a secure system where users can register and vote for different candidates in various categories. This will help you understand how to handle secure user authentication and prevent vote tampering.
  3. Fitness Tracker API: This could manage user profiles, track workouts or exercises, calculate calories burned, and provide health and fitness reports. This would help you learn about complex business logic and data handling.
  4. Student Management System: This system would allow users to create, update, delete, and view students. Students can have fields like ID, name, course, and age. Implement different roles like students and admin, where admin has more rights.
  5. E-Commerce Backend: Create a backend for an e-commerce platform. This should include product management, user management, shopping cart functionality, and order processing. You can use Spring Security for handling user authentication and authorization.
  6. Blog Platform: Build a blogging platform where users can create an account, write blogs, read blogs by others, like, comment, and share. This will help you learn about handling complex relationships in databases.
  7. Hotel Booking: Develop a backend system where users can view room availability, book a room, view their bookings, and cancel bookings. Implement features like different room types, date ranges for booking, and price calculation.
  8. Task Tracker: A task tracker or a to-do list where users can add tasks, mark tasks as completed or incomplete, and delete tasks. This can be a good starting point to understand the basics of CRUD operations in Spring.
  9. Social Media: Design a simple version of a social media backend. Users should be able to create posts, follow other users, and see a feed of posts from users they follow.
  10. Online Quiz Application: A simple application where users can take quizzes on various topics and get their scores immediately. Admins can add, update, or delete questions.
  11. Inventory Management System: Create a system that keeps track of product inventory for a small store. It should allow adding new products, updating product details, and adjusting stock levels.
  12. Food Delivery App Backend: Users can see a list of restaurants in their area, view a restaurant’s menu, place an order, and check the status of their order.
  13. Forum or Message Board: Users can create threads, post messages in different threads, and reply to other users’ messages.
  14. Ride-Sharing App Backend: Simulate a basic ride-sharing app backend. Users can book a ride, see the details of their driver, and pay for the ride.
  15. Event Management System: Design an API to create and manage events. Users should be able to create an event, specify its location, date and time, and other users should be able to RSVP, post comments, and rate the event. This can introduce you to concepts like handling date and time and complex business logic.
  16. Appointment Scheduler: Design an API for an appointment booking system for a service-based business like a salon or clinic. Users should be able to book, cancel, and reschedule appointments. Employees should be able to view their schedule.
  17. Survey System: Build a system where users can create surveys, share them, and collect responses. The system should allow for data aggregation and simple analytics of the responses.
  18. Weather Application: Build an application that fetches weather data from an API like OpenWeatherMap and displays it to the user. Users can search for weather by city.
  19. Recipe Application: A system where users can add, edit, and delete recipes. Other users can view these recipes, rate them, and comment on them.
  20. Job Portal: A system where employers can post job vacancies and job seekers can apply. Include features like user registration, job posting, job applications, and job search.

All these projects involve handling HTTP requests, performing CRUD operations with a database, and implementing business logic – core backend development aspects. You can use Thymeleaf or JSP for a basic frontend, or you can integrate these backends with a simple frontend developed using HTML, CSS, and JavaScript.

Remember, it’s essential to grasp the basics and the underlying concepts, so don’t worry if you’re not able to implement complex features at first. Start small and gradually add more features as you learn. Good luck with your projects!

All credit goes to ChatGPT for coming up with ideas; I just picked a few I find appropriate for you. 

 

]]>
https://jugbd.org/kickstarting-your-coding-journey-backend-focused-project-ideas-for-beginners-incorporating-basic-frontend-skills/feed/ 0 62928