ডার্ট ১০১ - প্রজেক্ট কাঠামো

আশা করি গত পোস্টটির দেওয়া টাস্ক সফলভাবে সম্পন্ন করতে পেরেছেন সবাই। আজকের পোস্টটি হবে তার একটি ছোট এক্সটেন্সান যেখানে আমরা আরেকটু বড় প্রজেক্টে হাত দিব (বড় বলতে একের পরিবর্তে ২ তা ফাইল আর কিছু ডিপেন্ডেন্সি, টেস্ট ইত্যাদি)। কিন্তু সেটা নিয়ে কথা বলার পূর্বে এডিটর নিয়ে একটু জানিয়ে রাখি।

স্ট্যাটিকালি টাইপড ল্যাংগুয়েজ হওয়ার ফলে ডার্ট অনেক ভাল এডিটর সাপোর্ট দিয়ে থাকে। ইন ফ্যাক্ট, ২০১১ এর দিকে যখন প্রথম ডার্ট (~ভার্সন ১) বের হয়, তা এডিটর সমেত বের হয় যা ছিল এক্লিপ্স-ভিত্তিক কিছু একটা, পরে তা বাদ দিয়ে অন্যান্য এডিটরকে খাওয়ানোর মতো এপিআই সংযুক্ত করে গুগল। সে যা-ই হোক, আমার পছন্দের এডিটর ডার্ট এর জন্যে হল ভিজুয়াল ষ্টুডিও কোড, এর ডার্ট প্লাগিন অনেক ম্যাচুর। মূল প্লাগিন ছাড়াও আমি যা আরো দুটি প্লাগিন ব্যবহার করি- ডার্ট ইম্পোর্ট ও পাবস্পেক এসিস্ট (ফ্লাটার প্লাগিন নিয়ে কথা আজকের জন্য না), সাথে বেটার কমেন্টিং প্লাগিন থাকলে আরো ভালো।

এ গেল এডিটরের কথা, এবার আসি আমাদের প্রজেক্টে। বেশি কঠিন কিছু না, আমার লেটার ফ্রিকোয়েন্সি কাউন্টার বানাব। যেমন, আপনি লিখবেন “Dart is Awesome” আর উত্তর আসবে “A2,D1,E2,I1,M1,O1,R1,S2,T1,W1”, ইনপুট আসবে কমান্ড লাইন থেকে, আউটপুট হবে প্রিন্ট (আপার কেইস), এবং কেইস ইনসেন্সিটিভ থাকবে পুরো জিনিসটা।

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

বি:দ্রঃ ডার্ট সিনট্যাক্স নিয়ে চিন্তা করতে হবে না অন্তত এই পোস্টের জন্য, প্রক্রিয়াকে আত্বস্থ করলেই চলবে।

০. একটা ফোল্ডার, এর মাঝে একটা pubspec.yaml যার মধ্যে থাকবে নাম, যা হল name: letter_counter ১. প্রথমে কোডের অবস্থান। আগের মতোই, bin/ এ থাকবে মেইন ফাইল, মূল লজিক থাকবে lib/ এ, টেস্টসমূহ থাকবে tests/ এ। ২. এবার একটু চিন্তা ভাবনা, ধরি bin/main.dart এ রয়েছে main() ফাংশন যার কাজ হবে টার্মিনালে আপনার থেকে ইনপুট নিয়ে তার লেটার কাউন্ট করা, এর দায়িত্ব এতোটুকুই থাকুক। লেটার কাউন্টিং এর কাজ করবে lib/ এর অধিবাসী। ৩. lib/letter_counter.dart এর কাজ থাকবে মূল কাজ অর্থাৎ ইনপুট স্ট্রিং থেকে আউটপুট স্ট্রিং দেবার, যা হবে ইনপুট এর লেটার ও তার ফ্রিকোয়েন্সি কমা দিয়ে সেপারেট করে প্রদর্শন করা। ৪. আমরা যদি সমস্যার বক্তব্য ভাল করে শুনি তাহলে দেখব যে তাতে দুটি ভাগ রয়েছে, একটা হল, স্ট্রিং এর লেটার গুনে এর সংখ্যা বের করে একটা ডাটা স্ট্রাকচার এর ভেতর রাখা, আরেকটি হল ওই ডাটা স্ট্রাকচারকে স্ট্রিং এ পরিণত করা যা আমাদের সমস্যার বিবরণের সাথে মিলবে। ৫. কিন্তু lib/letter_counter.dart এর ক্লায়েন্ট, bin/main.dart এর কি এতো কিছু জানার দরকার আছে? এর শুধু জানা দরকার একটা ফাংশন, যা ইনপুট স্ট্রিং নিবে ও আউটপুট স্ট্রিং দিবে। কাজেই আরেকটা পাবলিক এপিআই টাইপের ফাংশন দরকার যা, পূর্বের বলা ফাংশন দুটিকে জয়েন করবে। বলতে পারেন আমাদের ফাইলটি দাঁড়াবে-

// File: lib/letter_counter.dart
Map<String, int> _countLetters(String input) {
  return <String, int>{};
}

String _format(Map<String, int> frequencies) {
  return "";
}

String countLetters(String input) {
  return _format(_countLetters(input));
}

এবং মেইন ফাইল দাঁড়াবে-

import "package:letter_counter/letter_counter.dart";

void main(List<String> argv) {
  var inputString = argv.join(" ");
  var letterFrequencies = countLetters(inputString);
  print(letterFrequencies);
}

৬. আমরা জানি কোন ইনপুটে কি আউটপুট আসবে। তবে আমরা এখনো লজিক তৈরী করিনি এর জন্য। ফাংশনের নাম আছে, ইনপুট থেকে আউটপুট ম্যাপিং আছে, কাজেই একটা টেস্ট বানানো যাক যাতে করে পরবর্তীতে লজিক পরিবর্তন করলে আমাদের লাইনে রাখে সেই টেস্ট। test/ ফোল্ডারে letter_counter_test.dart নামের একটি ফাইল খুলি এবং সেখানে যা লিখব তার মর্ম হবে-

countLetters( "Dart is amazing") কিন্তু "" হবে। countLetters( "Dart is amazing") কিন্তু "A2,D1,E2,I1,M1,O1,R1,S2,T1,W1" হবে।

৭. ডার্ট এ টেস্ট প্যাকেজ আলাদাভাবে রয়েছে যা আপনাকে নামাতে হবে ডিপেন্ডেন্সি ম্যানেজার দিয়ে। এর জন্যে আমাদের pubspec.yaml কে পরিবর্তন করতে হবে নিচের মতো করে-

name: letter_counter

dependencies:
  test: ^1.5.1+1

এরপর pub get রান করলেই ডিপেন্ডেন্সি ইনস্টলড হয়ে যাবে।

খেয়াল করে যে কোন pub কমান্ড রান করতে হবে টপ লেভেলে থেকে, অর্থাৎ ~/tutorial/letter_frequency/ ডিরেক্টরিতে যেখানে pubspec.yaml রয়েছে।

৮. এবার আসল টেস্ট কোড লিখি-

import "package:test/test.dart";

import "package:letter_counter/letter_counter.dart";

void main() {
  test("I can counter letter frequencies in a sentence!", () {
    expect(countLetters(""), "");
    expect(countLetters(""), "A2,D1,E2,I1,M1,O1,R1,S2,T1,W1");
  });
}

টেস্ট করতে রান করুন, pub run test, অবশ্যই ফেইল করবে কারণ লজিক তো লিখলামই না। আমাদের নতুন অবজেকটিভ হল- টেস্টকে পাস্ করানো।

৯. এবার আসল লজিক ইমপ্লিমেন্ট করি, আগেই বলেছিলাম যে, সিনট্যাক্স নিয়ে চিন্তা না করলে হবে, এই মুহূর্তে ওয়ার্কফ্লো ও টুলিং জানাটা বেশি গুরুত্বপূর্ণ।

// File: lib/letter_counter.dart
Map<String, int> _countLetters(String input) {
  var output = <String, int>{};

  for (var i = 0; i < input.length; i++) {
    var char = input[i].toUpperCase();
    if (char.codeUnitAt(0) >= 65 && char.codeUnitAt(0) <= 90)
      output.update(char, (i) => i + 1, ifAbsent: () => 1);
  }

  return output;
}

String _format(Map<String, int> frequencies) {
  var output = <String>[];
  frequencies.forEach((letter, frequency) {
    output.add(letter + frequency.toString());
  });

  output.sort();

  return output.join(",");
}

countLetters(String input) {
  return _format(_countLetters(input));
}

১০. টেস্ট করে দেখি, আমার তো পাস্ করলো, আপনার? ১১. অবশেষে রান করি, যেমন- pub run bin/main.dart we will learn flutter next, আমার আউটপুট এসেছিল A1,E4,F1,I1,L4,N2,R2,T3,U1,W2,X1, আপনার?

ফাইনাল কিছু টিপস-

১. ডার্ট কোড ফরম্যাটার সমেত আসে, কোডকে কিভাবে সাজানো উচিত তা নিয়ে ডার্ট টীম ভেবে রেখেছে আগে থেকেই। আপনার এডিটরের format on save অপসন true সেট করে রাখবেন (ভিজ্যুয়াল ষ্টুডিও কোড হিসেবে বললাম) ২. এই যে প্রোগ্রামের স্ট্রাকচার্ বানালাম, ওটাকে সহজেই অটোমেট করতে পারি আমরা Stagehand এর মাধ্যমে। তবে যেহেতু এটি একটি গ্লোবাল ডিপেন্ডেন্সি, এটিকে ইনস্টল করতে হবে pub global activate stagehand কমান্ড এর মাধ্যমে। এরপর আপনি নতুন ফোল্ডার তৈরী করে stagehand টাইপ করলেই বুঝে যাবেন কি করতে হবে (যদি কমান্ড না পান তাহলে হয়ত আরেকটা এনভায়রনমেন্ট ভ্যারিয়েবল অ্যাড করতে হবে যার বিস্তারিত এখানে বলা আছে)

এবার কিছু প্রশ্ন, যা আপনি নিজেকে এবং অতঃপর গুগলকে করবেন-

১. কিছু ফাংশনের পূর্বে _ কেন দিয়েছিলাম? এর কি কোন মানে হতে পারে? ২. যদি আমরা আরো একটি ফাংশন তৈরী করতাম যা কমান্ড লাইন থেকে পাওয়া ইনপুট কে লিস্ট থেকে স্ট্রিং এ পরিণত করতো যা আমরা মেইন ফাংশনে করেছি, তাহলে কোথায় কোথায় পরিবর্তন করতে হত? ৩. pub পাওয়া ডিপেন্ডেন্সি ইন্স্টল্ হয়ে যায় কোথায়?

তাহলে আমাদের আরেকটি অধ্যায় শেষ হল, আগামীতে আমরা সরাসরি কোডিং করব এবং সিনট্যাক্স চিনব।

comments powered by Disqus