গেট সেট ডার্ট: জেসন
প্রোগ্রামার কিন্তু জেসন (JSON) কী তা জানে না এমন পাওয়া দুষ্কর। মাল্টিপ্লাটফর্ম অ্যাপ্লিকেশনের যুগে, যখন সার্ভার ও একাধিক ক্লায়েন্ট সবাই আলাদা আলাদা জায়গা থেকে যোগাযোগ করে তখন পুরাতন মার্কআপের বদলে জেসনই এখন অধিকাংশের পছন্দ। জেসনের জন্ম (নামেই বোঝা যায়) জাভাস্ক্রিপ্টের জগতে। সকল জেসন ভ্যালিড জাভাস্ক্রিপ্ট ডাটা। তাছাড়াও সব বহুব্যবহৃত প্রোগ্রামিং ল্যাঙ্গুয়েজেই জেসন ব্যবহারের সুযোগ থাকে।
ডার্টে জেসন
সত্যি বলতে কি, ডার্টে জেসন ব্যবহার করা পাইথনের মতই সোজা।
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | // Importing necessary library to convert string to JSON. import 'dart:convert'; String jsonString = """ { "id": 1, "greeting": "বন্ধুগণ ও স্নেহের হিজিবিজবিজ", "user": { "first_name": "ব্যাকরণ", "last_name": "শিং", "alive": true, "bicep": 26, "height": 26, "ear_infection": false } } """; var jsonData = json.decode(jsonString); |
এতই যদি সহজ, তবে…
আসলেই এত সহজ। তবে, এখন প্রশ্ন হলো, ডার্টে আমরা ডাটা কীভাবে, বা আরো ভালোভাবে বললে, কী টাইপে পাচ্ছি? jsonDecode
, যেটা আসলে json.decode
ফাংশনের শর্টহ্যান্ড তার ডেফিনিশনটা এরকম:
1 2 3 4 5 6 7 | dynamic jsonDecode ( String source, { Object reviver( Object key, Object value ) }) |
অর্থাৎ, আমরা আসলে ডায়নামিক (dynamic) টাইপের ডাটা পাচ্ছি। ডায়নামিক ডাটা মানে যেকোনো কিছু হতে পারে। ল্যাঙ্গুয়েজটা পাইথন বা জাভাস্ক্রিপ্ট হলে আসলে কোনো সমস্যাই ছিল না এতে। এই ল্যাঙ্গুয়েজগুলো যে ডায়নামিক্যালি টাইপড্! ডার্টের দর্শনের সাথে এমন ডায়নামিক্যালি টাইপড্ ছন্নছাড়া ডাটা ব্যাপারটা যায় না। বলা যায়, রীতিমত কাউন্টার-প্রোডাক্টিভ। অনেক ডাটা যদি থাকে আপনি আসলে শিওর না সবসময় কোথায় কেমন ডাটা পাচ্ছেন। আপনার এডিটর আপনাকে ভালোভাবে টাইপহিন্ট দিতে পারবে না। অনেক তুচ্ছ কিন্তু ক্ষতিকর বাগ আপনার চোখ এড়িয়ে যাবে।
অতএব,
আমাদের উচিত জেসন ডাটাটিকে ক্লাস অবজেক্টে রূপান্তরিত করা। কেন? কেননা:
- আপনি পাচ্ছেন চমৎকার টাইপ-হিন্ট।
- ক্লাস-অবজেক্টের সকল সুবিধা।
- ফলাফলে, মনের প্রশান্তি এবং চমৎকার প্রোগ্রাম।
কিন্তু, কীভাবে?
প্রথম ধাপ হচ্ছে, প্রয়োজনীয় ক্লাস তৈরী করা। লক্ষ্য করুন, আমাদের jsonString
ডাটায় নেস্টেড user
অবজেক্ট আছে। অর্থাৎ, মূল ক্লাসের বাদেও এই ডাটার জন্য আরেকটি ক্লাস করলে ভালো হয়। আমরা এই ক্লাসটি দিয়েই শুরু করবো:
1 2 3 4 5 6 7 8 9 10 11 | class User { String firstName; String lastName; int bicep; int height: bool alive; bool earInfection; User({this.firstName, this.lastName, this.bicep, this.height, this.alive=true, this.earInfection=false}); } |
একদম সাধারণ ক্লাস। শুধুমাত্র কনস্ট্রাক্টরে আমি পজিশনাল আর্গুমেন্টের বদলে কীওয়ার্ড আর্গুমেন্ট নিচ্ছি, এবং alive
ও earInfection
ফিল্ড দুটির জন্য ডিফল্ট ট্রু ও ফলস্ ভ্যালু দিচ্ছি।
এপর্যন্ত আসলে জেসনের কোনো ব্যাপার নেই। এবার আমরা আরেকটি কন্সট্রাক্টর লিখবো, যেটি আসলে জেসন ডাটা নিয়ে সেটা থেকে User
অবজেক্ট বানাবে।
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | class User { String firstName; String lastName; int bicep; int height; bool alive; bool earInfection; User({this.firstName, this.lastName, this.bicep, this.height, this.alive=true, this.earInfection=false}); User.fromJSON(Map<String, dynamic> data) : firstName = data['first_name'], lastName = data['last_name'], bicep = data['bicep'], height = data['height'], alive = data['alive'] ?? true, earInfection = data['ear_infection'] ?? false; } |
আমাদের User.fromJSON
কন্সট্রাক্টরটির একটি প্যারামিটার আছে data
নামে। আর্গুমেন্ট হিসেবে আমরা দিতে পারবো একটি Map
যেটির key সবসময় String
হবে (জেসনের key সবসময় স্ট্রিং হয়), এবং value যেকোনোকিছু হতে পারে। আমরা এই আর্গুমেন্ট থেকে ডাটা নিয়ে যথাযথ ফিল্ডে অ্যাসাইন করছি। লক্ষ্য করুন, আমরা alive
ও earInfection
এর জন্য চেক করছি যেন ডাটার ভেতর এ দুটি ফিল্ড না থাকলেও ডিফল্ট ভ্যালু অ্যাসাইনড্ হয়।
একইভাবে আমরা মূল ডাটার একটি ক্লাস বানাবো:
1 2 3 4 5 6 7 8 9 10 11 12 | class Greeting { int id; String greeting; User user; Greeting({this.id, this.greeting, this.user}); Greeting.fromJSON(Map<String, dynamic> data): id = data['id'], greeting = data['greeting'], user = User.fromJSON(data['user']); } |
লক্ষ্য করুন, আমরা user
ফিল্ডের জন্য ইউজার ক্লাসের একটা ইন্সট্যান্স বানিয়েছি fromJSON
কন্সট্রাক্টর দিয়ে। এভাবে আমরা যত ধাপে প্রয়োজন নেস্টেড ডাটা হ্যান্ডেল করতে পারি। পুরোটা সময় আমরা যথাযথ টাইপ-হিন্ট পাবো।
তাছাড়াও আমরা পাচ্ছি ক্লাসের সকল সুযোগ সুবিধা। আমরা প্রয়োজন মত কাস্টম গেটার্স ও মেথডস্ ডিক্লিয়ার করতে পারি যেগুলো হয়ত আমরা আমাদের ডাটা সোর্স থেকে পাচ্ছিই না।
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | class User { String firstName; String lastName; int bicep; int height; bool alive; bool earInfection; // A getter to get Full Name from first and last name String get fullName => "$firstName $lastName"; User({this.firstName, this.lastName, this.bicep, this.height, this.alive=true, this.earInfection=false}); User.fromJSON(Map<String, dynamic> data) : firstName = data['first_name'], lastName = data['last_name'], bicep = data['bicep'], height = data['height'], alive = data['alive'] ?? true, earInfection = data['ear_infection'] ?? false; } class Greeting { int id; String greeting; User user; Greeting({this.id, this.greeting, this.user}); Greeting.fromJSON(Map<String, dynamic> data): id = data['id'], greeting = data['greeting'], user = User.fromJSON(data['user']); // A method to greet and introduce. void greet(){ print(greeting); print("আমি, ${user.fullName}।"); } } |
আমরা এবার সহজেই জেসন থেকে ডিকোড করা ডাটা থেকে অবজেক্ট বানাতে ও ব্যবহার করতে পারি:
1 2 3 4 5 6 7 8 | void main(){ var data = json.decode(jsonString); var greeting = new Greeting.fromJSON(data); greeting.greet(); } // বন্ধুগণ ও স্নেহের হিজিবিজবিজ // আমি, ব্যাকরণ শিং। |
কিন্তু, কেন এত কষ্ট করবো?
আসলে, ছোটখাটো কাজে, এক-আধবার অল্প একটু জেসনের জন্য এতকিছু না করলেও চলে। কিন্তু তারচেয়ে বেশি হলে বরং ভালো মানের প্রোগ্রাম লিখতে এটুকু করতেই হবে। ভালো বড় প্রোগ্রামে অনেককিছু পুনঃব্যবহৃত হয়, বা একই স্ট্যান্ডার্ড বজায় রাখে। পুনঃব্যবহারের ক্ষেত্রে আসলে একই ক্লাস বারবার ব্যবহার করা যায়। স্ট্যান্ডার্ড বজায় রাখলে অ্যাবস্ট্রাক্ট ক্লাসও ব্যবহার করা যেতে পারে কখনো কখনো। এবং এই সবকিছু প্রোডাক্টিভিটি ও সফটওয়্যারের গুণগত মানের ওপর সুদূরপ্রসারী প্রভাব ফেলে।