Tuesday, May 23, 2017

ცხოვრება როგორც სახლის აშენება

   რამდენიმე დღის წინ ფიქრის დრო მქონდა და მივხვდი, რომ თითოეული ადამიანის ცხოვრება სახლის აშენებას ჰგავს. აი ზუსტად იმ პროცესს ჰგავს, როცა აგურს აგურზე, ან თუნდაც ბლოკს ბლოკზე აწყობ. ცხადია, სახლის აშენება არის პროცესი, რომელშიც შენს გარდა ბევრი ადამიანი მონაწილეობს, იგივე შეიძლება ვთქვათ ცხოვრებაზეც (ან თუნდაც შეგიძლიათ კარიერა იგულისხმოთ). გვერდში გყავს ხალხი, რომლებიც აგურების ერთმანეთზე დაწყობაში გეხმარება, მაგრამ ზოგჯერ გამოერევიან ხოლმე ისეთებიც, რომლებიც იმის ნაცვლად რომ ეს აგურები სწორად დააწყონ, ან საერთოდ არ აწყობენ და მიზნის მიღწევას გიხანგრძლივებენ, ან ძალიან ცუდად აწყობენ და როცა ამას მიხვდები, გიწევს მათი დაწყობილი აგურების მოხსნა (მოშორება) და სხვა ხალხთან ან თუნდაც უკვე მარტოს პროცესის სწორი მიმართულებით გაგრძელება. სწორედ ასეა ცხოვრებაშიც, გვხვდება ხალხი, რომლებიც გვეხმარებიან და ხელს გვიწყობენ იმაში, რომ ვიყოთ ბედნიერები, წარმატებულები და პროფესიონალები, თუმცა ამავე დროს, დროის კონკრეტულ მომენტში, გვერდში გვყავს ხალხი, რომლებიც ან უბრალოდ გვაფერხებენ, ან უარეს შემთხვევაში ხელს გვიშლიან და გვაზარალებენ, რაც რამდენიმე ნაბიჯით უკან გვწევს. ასეთების იდენტიფიცირება ადრე თუ გვიან ხდება ხოლმე და მათ გვერდიდან ვიშორებთ, ისევე როგორც ცუდ "მშენებლებს".

Tuesday, May 9, 2017

Java StreamAPI Examples

 სანამ უშუალოდ მაგალითების განხილვაზე გადავიდოდეთ, მოდით ორი სიტყვით შევეხოთ იმას თუ რა არის Stream-ები ჯავაში და რატომ არის მისი გამოყენება უკეთესი. Stream-ის ცნება ჯავაში მე-8 ვერსიიდან გამოჩნდა და თავიდანვე საკმაოდ პოპულარული გახდა დეველოპერებში. Stream არის ობიექტების მიმდევრობა, რომელზეც შეგვიძლია განვახორციელოთ აგრეგაციული ოპერაციები და ასევე ფილტრები, დაჯგუფებები, გარდაქმნები, სტატისტიკური შეჯამებები.  მოდით ორი სიტყვით შევეხოთ Stream-ის თვისებებს:


  • Sequence of Elements  - Stream გვაძლევს კონკრეტული ტიპის ელემენტების მიმდევრობას და მას შეუძლია ელემენტის ამოღება და გამოთვლა მოთხოვნების შესაბამისად. ის არასდროს ინახავს ელემენტს.
  • Source - Stream იღებს კოლექციებს, მასივებს, I/O რესურსებს, როგორც მისი input.
  • Aggregate Operations - Stream-ს შეუძლია განახორციელოს ისეთი აგრეგაციული ოპერაციები, როგორებიცაა: filter, map, limit, reduce, find, match და ა.შ. 
  • Pipelining - უმრავლესობა Stream-ის ოპერაციებისა, აბრუნებს ისევ Stream-ს, ასე რომ ისინი შეიძლება გამოყენებული იყოს როგორც pipeline. ასეთ ოპერაციებს შუალედური ოპერაციები ეწოდება და მათი ფუნქციაა მიიღოს input, დაამუშავოს და დააბრუნოს output თავის ადრესატთან, target-თან. collect() მეთოდი არის ტერმინალური ოპერაცია რომელიც როგორც წესი pipelining-ის ბოლოში გამოიყენება და აღნიშნავს stream-ის დასრულებას. 
  • Automatic iterations - Stream ოპერაციები იტერაციას აკეთებს ავტომატურად source ელემენტებზე, რაც კოლექციების შემთხვევაში შეუძლებელი იყო.
Stream-ის მიღება ჯავაში ორი მეთოდით შეიძლება, ესენია : Stream კლასის სტატიკური მეთოდებით, ან Collection Framework-ში განსაზღვრული მეთოდებით.

ახლა განვიხილოთ Stream-ებზე, რამდენიმე მაგალითი და აგრეგაციული ფუნქცია:

forEach
Stream გვთავაზობს forEach მეთოდს, რომელიც მისი თითოეული ელემენტის გადავლას ახორციელებს.  forEach მეთოდს არგუმენტად გადაეცემა ბრძანება, რომელიც გვეუბნება რა უნდა მოხდეს თითოეული ელემენტისთვის. 

map
map მეთოდის გამოიყენება თითოეული ელემენტის შესაბამის რეზულტატთან დასაკავშირებლად (დასა-map-ად). კოდის ფრაგმენტი, რომელიც ქვემოთ არის მოყვანილი ბეჭდავს უნიკალურ კვადრატებს რიცხვებისა. map პარამეტრად იღებს Producer-ის ტიპს

filter


filter მეთოდი აკეთებს ელემენტების გამოხშირვას stream-დან გაკრვეული კრიტერიუმის მიხედვით.  ქვემოთ მოცემული ფრაგმენტი დათვლის ცარიელი სტრიქონების რაოდენობას. filter პარამეტრად იღებს პრედიკატს. 

parallel processing
ქვემოთ მოყვანილი კოდის ფრაგმენტი დაითვლის ცარიელი სტრიქონების რაოდენობას ოღონდ parallelStream-ის მეშვეობით, რომელიც არის stream-ის ალტერნატივა პარალელურ პროცესინგში.

Collectors
კოლექტორები გამოიყენება რეზულტატების კომბინირებისთვის/შეერთებისთვის. კოლექტორები გამოიყენება List-ის ან String-ის დასაბრუნებლად.


Monday, May 8, 2017

SOLID - პირველი 5 პრინციპი ობიექტზე ორიენტირებულ პროგრამირებაში

S.O.L.I.D არის აკრონიმი პირველი 5 პრინციპისა ობიექტზე ორიენტირებულ პროგრამირებაში. ამ პრინციპების კომბინირებით, პროგრამისტს შეუძლია ადვილად განავითაროს თავისი პროგრამული უზრუნველყოფა და მომავალში დაამატოს სხვა ფუნქციონალი.

ამ პოსტში მოკლედ მიმოვიხილავ, თუ რას გულისხმობს ეს 5 პრინციპი. თუ აკრონიმს გავშიფრავთ მივიღებთ :
S – Single-responsibility principle
O – Open-closed principle
L – Liskov substitution principle
I – Interface segregation principle
D – Dependency Inversion principle
ახლა სათითაოდ განვიხილოთ თითოეული მათგანი.
Single-responsibility Principle (S.R.P) - კლასს უნდა ჰქონდეს ერთი და მხოლოდ ერთი მიზეზი იმისთვის, რომ შეიცვალოს, ანუ ეს გულისხმობს, რომ კლასი უნდა ასრულებდეს მხოლოდ და მხოლოდ ერთ დავალებას.

Open-closed principle გულისხმობს, რომ ობიექტები (ან Entity-ები) უნდა იყოს ღია გაფართოებისთვის მიზნებისთვის, მაგრამ დახურული ცვლილებების მიმართ. ანუ სხვა სიტყვებით რომ ვთქვათ, კლასი  ადვილად უნდა ფართოვდებოდეს ამ კლასშივე ცვილებების გარეშე.

Liskov substitution principle - ყველა ქვეკლასი/შვილი კლასი უნდა იყოს შემცვლელი მისი base/მშობელი კლასის.

Interface Segregation principle (ISP) - გულისხმობს იმას, რომ არცერთ კლასს არ უნდა ჰქონდეს ვალდებულება დააიპლმენეტიროს მეთოდი, რომელიც არ სჭირდება მას, ანუ არცერთი კლასი არ უნდა იყოს დამოკიდებული მისთვის არასასურველ მეთოდზე. მაგალითად, გვაქვს ShapeCalculator კლასი, რომელიც სხვადასხვა სახის ფიგურების ფართობების ჯამს ითვლის და გვაქვს ShapeInter ინტერფეისი, რომელსაც აქვს area() მეთოდი. Square კლასი, რომელიც აიმპლემენტირებს ShapeInter ინტერფეისს თავისთვის განსაზღვრავს area() მეთოდს და მისი გამოთვლის წესს. ახლა ვთქვათ გვინდა მოცულობების ჯამის გამოთვლაც. ჩვენ თუ ShapeInter ინტერფეისში დავამატეთ volume() მეთოდი, მაშინ გამოვა, რომ Square-ს არ აქვს მოცულობა, რადგან ორგანზომილებიანი ფიგურაა და ტყუილად მოგვიწევს ამ კლასში არასასრუველი მეთოდის იმპლემენტირება. ამისთვის, ჩვენ უნდა შევქმნათ სხვა ინტერფეისი, მაგალითად ThreeDimShapeInter და იქ გვქონდეს volume() მეთოდი.


Dependency Inversion principle  გვეუბნება, რომ Entity-ები უნდა იყვნენ დამოკიდებულები აბსტრაქციებზე და არა კონკრეტიკებზე. High Level მოდული არ უნდა იყოს დამოკიდებული Low Level მოდულზე, მაგრამ ორივე შეიძლება დამოკიდებული იყოს აბსტრაქციებზე. მაგალითად, გვაქვს PasswordReminder კლასი და მას აქვს property სახელად connection, რომელიც მონაცემთა ბაზასთან კავშირისთვის გამოიყენება. რადგან Connection არის low level და  PasswordReminder არის high level, ასეთი სტრუქტურა დაარღვევს Dependency Inversion პრინციპს. თუ მოგვიწევს სხვა მონაცემთა ბაზასთან კავშირი, მოგვიწევს PasswordReminder კლასსის ცვლილებაც, როცა მას სულ არ უნდა აინტერესებდეს რომელ მონაცემთა ბაზას ვიყენებთ. ანუ უნდა გავაკეთოთ ინტერფეისი DBConnection და მისი იმპლემენტატორი კლასი, რომელშიც ეწერება ის ლოგიკა, რომელიც დაგვეხმარება მონაცემთა ბაზასთან კავშირში, ხოლო PasswordReminder კლასში connection property იქნება ინტერფეისის ტიპის.