2016-12-26

Castle Windsor Part 2 - Array configuration, dictionary configuration

Xem original

Part 2 – Array Configuration
Part 3 – Dictionary configuration

Array configuration

Đầu tiên là config array.

Ví dụ holiday service có code như sau:
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using System;

namespace ConsoleApp
{
    public class HolidayService
    {
        private DateTime[] holidays;

        public DateTime[] Holidays
        {
            get { return holidays; }
            set { holidays = value; }
        }

        public bool IsHoliday(DateTime date)
        {
            if (holidays != null)
            {
                DateTime matchDate = date.Date;
                foreach (DateTime dt in Holidays)
                {
                    if (dt.Date.Equals(matchDate))
                    {
                        return true;
                    }
                }
            }

            return false;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            WindsorContainer container = new WindsorContainer(new XmlInterpreter());

            HolidayService holidayService = container.Resolve<HolidayService>();

            DateTime xmas = new DateTime(2016, 12, 25);
            DateTime newYears = new DateTime(2017, 1, 1);

            if (holidayService.IsHoliday(xmas))
            {
                Console.WriteLine("Merry X'mas!");
            }
            else
            {
                Console.WriteLine("X'mas is only for management!");
            }

            if (holidayService.IsHoliday(newYears))
            {
                Console.WriteLine("Happy new year!");
            }
            else
            {
                Console.WriteLine("New year, you haven't done all the work for last year!");
            }

            Console.ReadLine();
        }
    }
}
Config trong App.config như sau:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component type="ConsoleApp.HolidayService, ConsoleApp">
        <parameters>
          <holidays>
            <array>
              <item>2016-12-24</item>
              <item>2016-12-25</item>
              <item>2017-1-1</item>
            </array>
          </holidays>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Có thể dùng <Holidays> hoặc <holidays> đều được vì Windsor đủ smart để inject. Nếu muốn resolve trực tiếp ra IList (hoặc IList, IEnumerable ... nói chung là generic collection)
static void Main(string[] args)
{
    WindsorContainer container = new WindsorContainer(new XmlInterpreter());
    var holidays = container.Resolve<IList<DateTime>>("holidays");
    Console.WriteLine(string.Join("\r\n", holidays));
    Console.ReadLine();
}
File config tương ứng như sau:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component id="holidays" type="System.Collections.Generic.List`1[System.DateTime]">
        <parameters>
          <collection>
            <array>
              <item>2016-12-24</item>
              <item>2016-12-25</item>
              <item>2017-1-1</item>
            </array>
          </collection>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>

Cần nhớ ở dạng config này là thực hiện theo <parameters><collection><array><item>. Nếu đầy đủ hơn thì type chỉ định có cả assembly là <component id="holidays" type="System.Collections.Generic.List`1[[System.DateTime, mscorlib]], mscorlib">.

Dictionary configuration

Tương tự như array, dictionary configuration thực hiện với <parameters><dictionary><dictionary><entry>. Ví dụ AliasService như sau:
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using System;
using System.Collections.Generic;

namespace ConsoleApp
{
    public class AliasService
    {
        private Dictionary<string, string> dict;

        public Dictionary<string, string> Aliases
        {
            get { return dict; }
            set { dict = value; }
        }

        public string Evaluate(string term)
        {
            if (dict == null)
            {
                return term;
            }

            while (dict.ContainsKey(term))
            {
                term = dict[term];
            }

            return term;
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            WindsorContainer container = new WindsorContainer(new XmlInterpreter());

            AliasService aliasService = container.Resolve<AliasService>();
            string sentence = "A dog ate my homework";

            foreach (string word in sentence.Split(new char[] { ' ' }, 
                StringSplitOptions.RemoveEmptyEntries))
            {
                Console.Write("{0} ", aliasService.Evaluate(word));
            }

            Console.ReadLine();
        }
    }
}
App.config cấu hình dictionary:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component type="ConsoleApp.AliasService, ConsoleApp">
        <parameters>
          <Aliases>
            <dictionary>
              <entry key="dog">duck</entry>
              <entry key="ate">broke</entry>
              <entry key="homework">code</entry>
            </dictionary>
          </Aliases>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Để resolve trực tiếp ra IDictionary
static void Main(string[] args)
{
    WindsorContainer container = new WindsorContainer(new XmlInterpreter());
    var states = container.Resolve<IDictionary<string, string>>("states");
    Console.WriteLine(string.Join("\r\n", states.Keys));
    Console.ReadLine();
}
File config tương ứng như sau:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component id="states" type="System.Collections.Generic.Dictionary`2[System.String, System.String]">
        <parameters>
          <dictionary>
            <dictionary>
              <entry key="VN-CT">Cần Thơ</entry>
              <entry key="VN-DN">Đà Nẵng</entry>
              <entry key="VN-HN">Hà Nội</entry>
              <entry key="VN-HP">Hải Phòng</entry>
              <entry key="VN-SG">Hồ Chí Minh</entry>
            </dictionary>
          </dictionary>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Tới đây là xong part 2. Về type convertor có thể tham khảo thêm phần Configuration with type converters trong series của Mike Hadlow '10 Advanced Windsor tricks'.

Container tutorials ... example with Castle Windsor. Part 1 - Configuration parameters.

Mình dùng Castle Windsor từ lâu. Cũng có note nhưng rồi để đâu mất. Mình đã tính viết 1 series làm sao đủ để xài Windsor từ cái thời còn dùng CAB/SCSF, sau đó là Prism nhưng rồi chẳng biết sao lúc đó bỏ nửa chừng.

Inversion of Control (IoC), Dependency Inversion Principle (DIP) và Dependency Injection (DI), CAB&SCSF cũng chỉ viết tới Part 03: Dependency Injection

Gần đây coi lại và thấy lần này nên note kỹ. Nói chung đầu tiên là lược dịch từ những tutorials trên NET bắt đầu từ series trên BitterCoder (đã rất lâu rồi từ tận 2007). Có thể đọc thêm hướng dẫn từ project chính thức trên Github castleproject/Windsor.

Gần đây có nhiều lựa chọn IoC container cho .NET gồm có Autofac, StructureMap, Unity. Một vài container có vẻ dần chiếm được nhiều quan tâm hơn như Autofac với simple API, dễ sử dụng và performance tốt. Tuy nhiên Windsor nói chung vẫn đáp ứng được yêu cầu đặt ra với nhiều module (facilities) từ logging, NHibernate, ASP.NET MVC ...

Configuration parameters

Part đầu tiên là configuration parameters. Windsor cho phép cấu hình component với parameters run-time. Mặc dù có thể configuration với .NET qua app.config bình thường nhưng sử dụng với Windsor khá là đơn giản và tiện dụng.

Tạo một Project ConsoleApp, dùng NuGet install Castle Windsor. Tạo file app.config.


Giả sử có một class là Tax, mặc định tax rate là 10%. Có thể config rate thông qua app.config.
public class Tax
{
    private decimal rate = 0.10m;

    public decimal Rate
    {
        set { rate = value; }
        get { return rate; }
    }

    public decimal Calculate(decimal gross)
    {
        return Math.Round(rate * gross, 2);
    }
}
Sau khi tạo class Tax, thực hiện dùng với Windsor như sau:
using Castle.Windsor;
using Castle.Windsor.Configuration.Interpreters;
using System;

namespace ConsoleApp
{
    public class Tax
    {
        private decimal rate = 0.10m;

        public decimal Rate
        {
            set { rate = value; }
            get { return rate; }
        }

        public decimal Calculate(decimal gross)
        {
            return Math.Round(rate * gross, 2);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            WindsorContainer container = new WindsorContainer(new XmlInterpreter());

            // Resolve
            Tax calculator = container.Resolve<Tax>();

            decimal gross = 100;
            decimal tax = calculator.Calculate(gross);

            Console.WriteLine("Gross: {0}, Tax: {1}", gross, tax);
            Console.ReadLine();
        }
    }
}
Container được tạo với XmlInterpreter() sẽ đọc configuration từ file app.config (hoặc web.config với web app), instance calculator được tạo bởi container thông qua Resolve().

Thực hiện Build và Run sẽ ra báo lỗi không có config section 'castle'.
Thực hiện thêm config section vào App.config. Giả sử App.config không có cấu hình component sẽ gây exception ComponentNotFoundException
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Thực hiện config component nhưng không set tax rate như sau
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component id="tax" type="ConsoleApp.Tax, ConsoleApp">
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Type có thể không cần dùng AssemblyQualifiedName mà để đơn giản là Tax hoặc ConsoleApp.Tax cũng OK. Kết quả trả ra 'Gross: 100, Tax: 10.00'.

Thực hiện setup rate bằng parameters như sau:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component id="tax" type="ConsoleApp.Tax, ConsoleApp">
        <parameters>
          <rate>0.25</rate>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
Kết quả trả ra 'Gross: 100, Tax: 25.00'.

Với id="tax" có thể dùng để resolve component khác nhau, ví dụ:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="castle" type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor"/>
  </configSections>
  <castle>
    <components>
      <component id="tax1" type="ConsoleApp.Tax, ConsoleApp">
        <parameters>
          <rate>0.25</rate>
        </parameters>
      </component>
      <component id="tax2" type="ConsoleApp.Tax, ConsoleApp">
        <parameters>
          <rate>0.05</rate>
        </parameters>
      </component>
    </components>
  </castle>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2" />
  </startup>
</configuration>
và code
WindsorContainer container = new WindsorContainer(new XmlInterpreter());
decimal gross = 100;

// Resolve tax #1
Tax calculator1 = container.Resolve<Tax>("tax1");
decimal tax1 = calculator1.Calculate(gross);
Console.WriteLine("Gross: {0}, Tax: {1}", gross, tax1);

// Resolve tax #2
Tax calculator2 = container.Resolve<Tax>("tax2");
decimal tax2 = calculator2.Calculate(gross);
Console.WriteLine("Gross: {0}, Tax: {1}", gross, tax2);

Console.ReadLine();
Như vậy coi như là đủ cho part 1. Phần tiếp theo sẽ thực hiện config arrays, dictionary ...

2016-12-24

How to integrate SyntaxHighlighter to Blogger, Blogspot

Dạo gần đây post nhiều code, nhìn lại mới thấy blogger của mình post code rất ẹ. Vì vậy phải chuyển qua một dạng OK cho đồng nhất. Search một vòng và mình chọn Syntax Highlighter vì thấy nó đơn giản và nhìn rõ ràng. Hướng dẫn integrate vào Blogger/Blogspot thì có nhiều ngay tại trang chính SyntaxHighlighter.

Nói sơ qua một chút như sau. Thông thường khi viết code có thể đơn giản dùng tag blockquote được hỗ trợ sẵn <blockquote></blockquote> và post source vào đó. Tuy nhiên source sẽ không được highlight syntax và sẽ khó đọc 1 chút. Hay vẫn có thể dùng http://hilite.me/ như trước đây. Nhưng nói chung là vẫn cảm thấy không được tốt lắm.

Một cách khác là embbeded gist trên Github. Có thể tham khảo tại đây
Embedding Github code into your Blogger blog
SyntaxHighlighter là một các embedded trực tiếp dùng Javascript,  có thể download và dùng dễ dàng với bất kỳ website nào, không loại trừ Blogger/Blogspot. Nó giống như dạng MathJax.

Cơ bản như sau:
1. Download và put tại host/web server

2. Thực hiện theo các bước hướng dẫn tại http://alexgorbatchev.com/SyntaxHighlighter/manual/installation.html

3. Dùng config và brush alias tương ứng với language của source code http://alexgorbatchev.com/SyntaxHighlighter/manual/configuration/

Với Blogger/Blogspot, vào Template
1. Để chắc ăn thực hiện backup Template » Backup/Restore » Download template

2. Vào Edit HTML, trong tag <head> thực hiện include CSS, Javascript và init code cần thiết tùy theo version với link bắt đầu http://alexgorbatchev.com/pub/sh/. Version hiện tại là
3.0.83 ngày 2016/12/24. Hay có thể dùng CDN https://cdnjs.com/libraries/SyntaxHighlighter (Blogger dùng với https). Có thể dùng theme default, Eclipse hay midnight. Include các brush thông dụng như C++, Java, C#, Scala, Python, CSS, SQL, XML... Thực hiện config Blogger mode bật ON. Save và kiểm tra có lỗi Javascript hay không.

3. Thực hiện test bằng cách đơn giản nhất là dùng tag <pre>, tất nhiên là phải chuyển qua HTML code, xong copy source từ source file hay IDE hay text editor như Notepad++ qua. Nên bật ruler và tắt toolbar.

Set defaults như sau:
SyntaxHighlighter.defaults['tab-size'] = 4;
SyntaxHighlighter.defaults['toolbar'] = false;

Ngay sau khi gọi SyntaxHighlighter.all()

<pre class="brush: csharp; toolbar: false;">
using namespace System;
namespace Demo
{
    public class Pet
    {
        public string Name { get; set; }

        public Pet()
        {

        }
    }
}
</pre>

Kết quả như sau:

using namespace System;
namespace Demo
{
    public class Pet
    {
        public string Name { get; set; }

        public Pet()
        {

        }
    }
}

Cách thứ 2 là để trong tag script và bắt buộc có CDATA

<script type="syntaxhighlighter" class="brush: js"><![CDATA[
/**
 * SyntaxHighlighter
 */
function foo()
{
 if (counter <= 10) {
  return;
 }

 // it works!
}
]]></script>

Dùng first-line để chỉ định line number đầu tiên trên ruler và highlight dùng chỉ định highlight line number nào. Ví dụ:
<pre class="brush: php; toolbar: false; auto-links: false; first-line: 10; highlight: [11, 13]">
  /**
    * https://github.com/syntaxhighlighter
    */
  echo("https://github.com/syntaxhighlighter");
</pre>

Kết quả sẽ là

  /**
    * https://github.com/syntaxhighlighter
    */
  echo("https://github.com/syntaxhighlighter");

2016-11-30

Retained Fragment, headless Fragment là gì, setRetainInstance(true)?

Thực ra mình cũng định nhắc tới headless Fragment từ lâu. Cũng vài năm rồi, dạo gần đây có đụng lại Android, cần phải giải thích, có search 1 vòng nhưng vẫn không thấy một bài viết tiếng Việt nào có sẵn nên note luôn ở đây. Post này không bàn chi tiết về code, hay cụ thể trường hợp sử dụng headless Fragment nào chỉ focus chung vào đặc điểm của headless Fragment và một vài case thông dụng.

Headless Fragment là gì?

Đầu tiên là tên gọi headless Fragment? Nhiều developer khác gọi là viewless Fragment, UI-less Fragment, retained Fragment không có view hay nhiều khi còn gọi là retained "worker" Fragment lý do sẽ đề cập sau là Fragment này thông thường được sử dụng để manage một worker hay background operation.

Tất nhiên cái tên này làm liên tưởng nhiều đến kỵ sĩ không đầu headless horseman/knight.

Có nhiều developer thông tin rằng tên gọi này bắt nguồn từ tutorial của Lars Vogel tại
Multi-pane development in Android with Fragments - Tutorial#Headless Fragments.

Vậy headless Fragment cụ thể là gì? Mặc dù tên là headless Fragment nhưng tính năng đáng nói nhất lại là "retained" qua configuration change.

setRetainInstance(true)

Mặc định Fragment sẽ bị hủy (destroyed) và tạo lại (recreated) cùng với parent Activity. Việc sử dụng Fragment#setRetainInstance(true) sẽ giúp Fragment được giữ lại retained khi Activity được tạo lại (recreation).

LƯU Ý: điều này chỉ áp dụng với các Fragment KHÔNG NẰM TRONG BACK STACK.

Trạng thái của Fragment sẽ được retained (duy trì, giữ lại) khi configuration change. Điều này "retained" có nghĩa là Fragment sẽ không bị destroyed khi configuration changes. Cũng có nghĩa là Fragment sẽ được giữ lại ngay cả khi configuration change làm cho Activity bị destroyed.

Tất nhiên cần nói rõ thêm. Giống như Activity, Fragment vẫn có thể bị destroyed bởi hệ thống khi tài nguyên bộ nhớ xuống thấp. Khi đó dù có thiết lập "retained" hay không thì hệ thống cũng sẽ destroy các Fragment này khi rời khỏi Activity. Trong trường hợp rời khỏi Activity (ví dụ nhấn nút home), Fragment có thể có hoặc không bị hủy. Nhưng khi rời khởi Activity bằng nút back (việc đó sẽ gọi finish() và sẽ destroy Activity), tất cả các Fragment cũng sẽ bị destroy.

Xem thêm Understanding Fragment's setRetainInstance(boolean) trên Stackoverflow,
Handling configuration changes with Fragments của Alex Lockwood

UI-less + setRetainInstance(true)

Headless Fragment là Fragment không có/không định nghĩa UI hay có nghĩa không inflate một View nào. Tài liệu chính thức của Adroid nói về headless Fragment là Fragment without UI tại Fragments guide/Adding a fragment without a UI. Tuy nhiên trong đoạn này có một chỗ ko rõ ràng là 

"This adds the fragment, but, because it's not associated with a view in the activity layout, it does not receive a call to onCreateView(). So you don't need to implement that method".

Chính xác thì Android có gọi Fragment#onCreateView() nhưng kết quả trả về là null. Tức là thay vì không override Fragment#onCreateView() thì vẫn có thể implement trả về null.

Ví dụ đi kèm SDK là /APIDemos/app/src/main/java/com/example/android/apis/app/FragmentRetainInstance.java có thể xem online tại FragmentRetainInstance.

Nhưng chỉ headless không thì cũng không có ý nghĩa gì đặc biệt: đáng nói ở đây thông thường là kết hợp headless Fragment và setRetainInstance(true) còn gọi là retained headless Fragment.

Thực tế thì headless Fragment thường sẽ đi kèm với "retained" hay cũng sẽ là retained headless Fragment nên retained sẽ "vô tình" bị bỏ đi. Vì Fragment không có UI chỉ dùng với mục đích manage Object nào đó thường là background operation.

UI + setRetainInstance(true)

Việc Fragment có UI và sử dụng setRetainInstance(true) vẫn không có vấn đề gì dù trong trường hợp retained này có thể xảy ra một temporary memory leak.

Fragment có UI và developer cần thao tác với các UI. Việc thao tác thực hiện thông qua reference tới các UI/View dùng findViewById chẳng hạn. Với retained Fragment, các reference cũng được "retained" kéo theo View cũng sẽ được "retained". Do đó có thể gây temporary memory leak vì View internal giữ Context của Activity. Giả sử configuration change từ "portrait" sang "landscape". Fragment giữ Context của "portrait" Activity và 1 text box (View) cũng giữ Context của "portrait" Activity. Khi configuration change hoàn thành reference tới Activity sẽ được update lại, ví dụ trong onViewCreated, text box sẽ reference tới với "landscape" Activity. Tức trước khi việc này xảy ra, text box vẫn giữ reference của "portrait" Activity. Việc này có thể ngăn cản "portrait" Activity cũ được thu hồi bởi GC. Hiển nhiên, nếu không cẩn thận, ví dụ giữ một reference tới chính activity trong Fragment thì memory leak thật sự có thể xảy ra.

Đó là lý do "retained" mới là tính năng quan trọng hơn là headless. Headless chỉ là tính năng phụ kéo theo khi Fragment không cần xử lý UI.

Usage

Headless Fragment rất hữu dụng khi nó là "worker" Fragment khi nó giữ các object như Thread, AsyncTask, Socket, etc ...

Ví dụ thông thường là retain một AsyncTask qua configuration change sử dụng headless Fragment. Việc này sẽ bảo đảm rằng progress sẽ cập nhật và kết quả sẽ trả về cho currently displayed Activity instance (Activity đang hiển thị) và bảo đảm sẽ không bị leak leak AsyncTask khi configuration change.

Khi Activity tạo lại thì Fragment sẽ được hệ thống xác định theo ID hoặc tag (nếu không chỉ định cả hai hệ thống sẽ lấy theo ID của container view) để find/restore Fragment. Headless Fragment sẽ được thêm programmatically tức là thêm bằng code nên trong trường hợp của headless fragment unique identifier là tag. Đơn giản trong onCreate của Activity nếu không tìm thấy "retained" Fragment với findFragmentByTag thì  thực hiện add mới Fragment và start background operation. Reference tới Activity sẽ được update thông qua onAttach và onDetach.

Kết quả là headless Fragment có thể dùng để retain Presenter (MVP) do Presenter thường dùng long running background operation. Cách này cũng được Mosby 2 sử dụng.

Headless Fragment cũng có thể được sử dụng để tổ chức việc Ask runtime permission theo như bài viết trên Medium Use headless Fragment for Android M run-time permissions and to check network connectivity.

2016-11-28

Android evolution ... the right architecture?

Gần đây mình được hỏi sắp xếp, gợi ý giùm một cái simple architecture để phát triển Android app. Thật sự việc này rất là khó nhất là khi chỉ nói chung chung, và không nắm 1 team cụ thể nào.

Hiện tại việc phát triển ứng dụng Android hình như là thay đổi quá nhanh. Mỗi ngày đều có những libraries mới, tools mới (mình hay theo dõi trên Medium). Những lần dev Android apps từ những năm 2010 đến sau này gần giữa 2014 mình đều cố gắng bắt nhịp với sự phát triển của Android. Đợt này bỏ quá lâu, có quá nhiều thứ để tìm hiểu :(.

Khoảng trước năm 2011 việc dev có vẻ đơn giản, gọi Restful service, dùng SQLite, + disk cache, và có lẽ vậy là đủ, mọi thứ tổ chức sao cho clean nhất có thể. 2010, mình cũng có tham khảo Google I/O 2010 - Android REST client applications và tìm hiểu thêm. Thật ra presentation tại Google I/O chỉ trình bày hướng phát triển, cũng không chỉ rõ cách implementation. Một số code nói là demo lại thì chỉ được 1 phần, không take care hết các trường hợp như configuration changes, lifecycle, reference Activity ...

Từ RoboSpice đến Volley + EventBus

Khoảng 2010, trước RoboSpice, mình có thử dùng Droid-Fu (sau này chuyển thành Ignition), 1 dạng hack trực tiếp Activity lifecycle với việc sử dụng WeakReferences. Nói chung là cũng không thích lắm. Khoảng 2012 thì xuất hiện RoboSpice implement theo hướng sử dụng Service và cache request result, 1 hướng mà Google I/O đã đề cập. Nhưng code theo RoboSpice cũng khá là rườm rà, mỗi lần tạo request phải chỉ định cache key và các thứ liên quan, lúc đó RoboSpice cũng còn thay đổi khá nhiều mãi sau này mới hoàn chỉnh với addListenerIfPending() hay getDataFromCache(). Code cũng không sáng sủa là mấy khi Activity hay Fragment có quá nhiều việc để làm. Rất khó xác định cache bao lâu là vừa (với cách thực hiện hiển thị UI là lấy cache trước, request network sau "get cache first then request" ... sẽ đề cập sau). Việc xử lý rotation hay back với activity nhiều khi cũng không quá quan trọng. Lý do app nhiều khi chỉ để portrait mode và thật sự thì việc user nhấn back có vẻ bị "bi kịch hóa" hơi quá. RoboSpice có một cái theo mình rất dở là thích ôm quá nhiều thứ từ caching, OR mapping, parser, HTTP request... thành ra 1 đống khó kiểm soát.

Sau đó, 2013 thì Volley ra đời và cả EventBus cũng xuất hiện vào thời gian này. Mọi người chuyển sang xài Volley với suy nghĩ rằng nó là của Google :D, ko gọi là xài 3rd party library. Bên cạnh đó EventBus được xài để thực hiện loosely coupling. Lúc này mình cũng hay develop apps ko hỗ trợ rotation. Việc code thì đơn giản theo dạng Activity, Fragment nói chuyện với một dạng Repository thông qua EventBus, việc gọi Restful service được giao cho Volley. Tất nhiên dùng Volley và EventBus vẫn phải care vụ Acvitity leak về mặt kỹ thuật vẫn có thể xảy ra, nhưng về tổ chức code thì có vẻ clean hơn.

Tham khảo thêm bài viết Android Application Architecture của Iván Carballo hay
Robust and readable architecture for an Android app part 2 (part 1) của Joan Zapata.

https://github.com/JoanZapata/android-asyncservice/wiki






Một số tổng hợp về chủ đề này trên github của ziem

MVP, MVVM và Clean architect

Sau đó là đến thời gian mình tìm hiểu Clean Architecture của Robert C. Martin a.k.a Uncle Bob. Như Uncle Bob đã nói architecture là mục tiêu, ý định (intent) không phải là framework: "Architecture is about intent, not frameworks".

Một architecture tốt là một architecture cho phép một quyết định đột ngột có thể thực hiện một cách dễ dàng, bao gồm một số đặc điểm:
+ Dễ maintain: kể cả thêm/bớt tính năng, thay đổi yêu cầu (cả những tính năng chưa biết trước)
+ Dễ test
+ Decoupled (tạo từ những thành phần độc lập tương đối và liên kết yếu - independent and loosely-coupled components)

Khoảng thời điểm này có rất nhiều "architecture" từ những platform khác được áp dụng cho phát triển Android từ MVC, MVP tới MVVM. Thật ra nếu gọi architecture chung chung thì không đầy đủ, chỉ là cho phần tổ chức UI vì đây thực ra là những UI design patterns. Mình biết MVP, MVVM từ khi làm việc với .NET/C# (ASP.NET, WPF và Prism). Mình ko đi sâu chi tiết về các pattern này. Có thể tham khảo theo các bài viết của Martin Fowler (phân tích rất kỹ) về MVC, Passive View, Presentation ModelMVP.

MVVM (theo MSDN)


MVVM (được phát triển từ Microsoft) thông thường đi kèm với data bindings, commands không được ưa chuộng bằng MVP trên Android (có lẽ đa phần không thích binding Android Data Binding Library). 

Các project mẫu thực hiện MVP trên GitHub
https://github.com/googlesamples/android-architecture

https://github.com/googlesamples/android-architecture/tree/todo-mvp


Xem thêm series giới thiệu MVP của Tin Megali, Model View Presenter (MVP) in Android, bài viết MVP for Android: how to organize the presentation layer của Antonio Leiva.

Có thể kể đến các libraries thực hiện MVP architecture như Mosby, Nucleus... Theo ý kiến của mình thì ít nhất cũng phải xem qua các libraries này thực hiện MVP như thế nào. Nếu không thích tự mình viết MVP thì hoàn toàn có thể dùng luôn các library này. Một trong những tính năng được ưa thích của các libraries này là Presenter có thể survive qua configuration/orientation changes (sẽ đề cập kỹ phần sau).

Mosby là library đặt theo tên architect Ted Mosby trong series "How I met your mother", mình cũng thích series này :D. Hiện tại Mosby đã có version 3.0 SNAPSHOT. Mosby bao gồm 2 phần chính MVP và ViewState, một component nhỏ liên kết giữa Presenter và View để giải quyết orientation changes.

Tương tự Mosby Nucleus cũng có tính năng tự động re-attach background task vào view mới khi orientation changes.

Mục đích đầu tiên MVP là cho phép thực hiện test dễ dàng hơn (nhất là unit tests với mocking). Nhưng theo cá nhân mình suy nghĩ thì dùng MVP cũng nhiều overhead. Đầu tiên là phải khai báo và quản lý quá nhiều interface. Những tính năng thông thường như login đôi khi phải khai báo vài interface trong khi dev nào cũng có thể hình dung login với username/password còn những thứ khác cũng chỉ là thứ yếu? Việc cố gắng tách Presenter khỏi Android có thể cần rất nhiều mô tả về UI logic từ những thứ rất nhỏ như show/hide loading progress.

Đôi khi việc phát triển app trên Android cũng ko quá phức tạp mà đòi hỏi về thời gian phát triển nhiều hơn, vòng đời của app cũng khá ngắn → thông thường người dev Presenter cũng là người dev View, việc mô tả lại UI logic và implement cho Presenter là quá tốn công (lại khá chán). Nhiều khi mình thiên về sử dụng một dạng simple như mô tả của Joan Zapata ở trên.

Tất nhiên nếu sp có vòng đời lâu và testing thật sự quan trọng thì code theo MVP không có vấn đề gì. Còn nếu không quá cần thiết thì có thể bỏ qua trong một vài trường hợp. Với một developer cứng tay dù app đã viết theo cách nào (tất nhiên có tổ chức) thì khi join team, developer này cũng có thể nhanh chóng bắt kịp. Và rồi thì những công nghệ chúng ta đang dùng cũng sẽ trở thành dead technologies ngày nào đó giống như "good code today, legacy code tomorrow".

Theo như Robert C. Martin a.k.a Uncle Bob, Clean Code: A Handbook of Agile Software Craftsmanship

"Who can justify the expense of a sixlane highway through the middle of a small town that anticipates growth? Who would want such a road through their town?"

"Ai có thể biện minh/thuyết phục người khác về chi phí để làm một con đường cao tốc 6 làn xe qua một thị trấn nhỏ rằng sẽ dành cho việc tăng trưởng được tiên đoán trước. Ai muốn có một con đường như vậy đi qua thị trấn của họ".

Kết hợp với RxJava
Nếu sử dụng MVP thì có lẽ sẽ thiếu sót nếu bỏ qua RxJava. Có thể tham khảo việc kết hợp RxJava và MVP như architecture của Iván Carballo, gọi là "MVP-based architecture powered by RxJava".

MVP-based architecture
https://labs.ribot.co.uk/android-application-architecture-8b6e34acda65#.tgds3woxp

Lưu ý trong architecture này event bus chỉ dùng rất "hạn chế" không dùng cho những event chỉ liên quan đến một màn hình mà liên quan đến brocasting toàn bộ như user logged out event.

MVP presenter và Activity/Fragment lifecycle, view state

Việc thực hiện MVP có cả ngàn cách. Và thật sự thì MVP cũng chỉ là chỉ dẫn về architecture còn việc thực hiện ntn thì vẫn tùy thuộc vào implementation. Một câu hỏi quan trọng đặt ra là mối quan hệ giữa Presenter và Activity/Fragment lifecycle và view state ntn?

Theo định nghĩa của Presenter thì không có chức năng nào liên quan đến lifecycle và việc persistence view state. Đầu tiên hãy tham khảo bài viết Presenters don't need lifecycle events của Hannes Dorfmann. Tóm tắt như sau: tác giả thấy ko có lý do gì để Presenters có những callbacks liên quan đến Activity/Fragment lifecycle như onCreate(), onPause() và onResume()... 

Việc bắt Presenter quản lý luôn cả lifecycle của Android là không hợp lý. Tại sao lại focus vào những view phức tạp như Fragment? Và nếu đem "phức tạp" đó vào Presenter thì nó cũng sẽ thành 1 đám hỗn độn. Team SoundCloud đã tạo một library là LightCycle để "tách vấn đề này ra" nhưng nói chung "liên quan" Presenter chỉ là đứng riêng ra. Team của Trello thì tạo RxLifecycle tiếp cận lifecycle bằng RxJava. Theo Hannes Dorfmann walk-around là tách khỏi View những logic liên quan đến lifecycle bằng cách thêm 1 layer.

Có thể xem thêm một số thông tin ở các bài viết:
  1. Android MVP - Part 2: Presenters and view state của Nathan Zylbersztejn  
  2. Android code that scales, with MVP của Nathan Barraille.
  3. MVP - Presenters that survive configuration changes của Brad Campbell
Tóm lại vấn đề Presenter và lifecycle có thể liệt kê một số cách giải quyết như sau:
  1. Để Presenter die khi Activity/Fragment die và restore state thông qua onSaveInstanceState (liên quan đến vụ callbacks). Việc này có thể thực hiện với các data đơn giản (có thể serialization được, Parcelable với Bundle). Nhưng sẽ phức tạp khi Presenter reference tới các object khó thực hiện serialization hoặc reference tới một background operation.
  2. Dùng Presenter pool, một dạng static caching đâu đó. Nếu dùng cách này thì phải chú ý đến trường hợp có nhiều Fragment cùng loại, cần tổ chức key của Presenter. Static caching cũng ko được đẹp đẽ cho lắm nhất là khi số lượng Presenter khá nhiều.
  3. Một cách khác là dùng headless Fragment (nghe giống kị sĩ không đầu :D), tên do community gọi Fragment không có UI và gọi setRetainInstance(true). Cách này có thể dùng với Dagger để Inject Presenter với fragment scope.
  4. Sử dụng Loaders và cache.
  5. Sử dụng các libraries hỗ trợ tính năng này như MosbyNucleus.

Unidirectional UI pattern/data flow

OK, mình tiếp tục liệt kê thêm những lựa chọn khác.

Flux, "Flux is the application architecture that Facebook uses for building client-side web applications.", là kiến trúc được Facebook dùng để build ứng dụng web đi chung với React.
--- và ---
Redux, "Redux is an application architecture inspired by Facebook Flux and and functional programming language Elm.", một application architecture "lấy cảm hứng" từ Flux và Elm.

Cả hai architecture đều có mấu chốt là dòng dữ liệu 1 chiều unidirectional data flow và đều là architecture cho web application (rất hot với front-end development).

Để thực hiện theo Redux thì khó khăn đầu tiên là phải suy nghĩ "theo Redux". Redux muốn developer nghĩ rằng ứng dụng bắt đầu với initial state và sẽ tương tác với một dòng actions (đến đây thì sẽ thấy bóng dáng reactive và functional programming). Nó đóng vai trò một container chứa state của ứng dụng.

Tất nhiên khi nói tới Flux và Redux thì không thể không nhắc React vì các kiến trúc này rất phù hợp với cách hoạt động của React (cho phần View).

Giới thiệu qua đã đủ, bây giờ tập trung cho Anroid. Nếu đồng ý với nhận định Android app không quá phức tạp như back-end và có vẻ giống client-side web app hơn thì đầu tiên hãy đọc một bài rất hay của Luis G. Valle Flux Architecture on Android.
"Well you have to deal with platform issues: memory, storage, pause, resume, network, location, etc. But that is not your app business logic. You have all of that in every app."



Với kiến trúc này thì mọi thứ có vẻ gọn hơn với 4 phần như diagram, nhưng để ý lại thì nó tập trung phức tạp rất nhiều lên Store. Library hỗ trợ Flux trên Android khá ít, ngay cả Facebook khi mới đề xuất về Flux cũng không hướng dẫn cụ thể thực hiện ntn.

Tuy nhiên ý tưởng của Facebook được mọi người ủng hộ và cải tiến thành Redux. Trikita có implement một library gọi là Jedux xem bài viết Writing a Todo app with Redux on Android.

Dù với UI pattern nào thì các vấn đề cần giải quyết với Android cũng vẫn như cũ và cần phải tìm hiểu thêm. Chi tiết thực hiện app với Redux có lẽ sẽ bàn kỹ ở một bài khác.


2016-11-23

PhoneGap or Adobe PhoneGap, or Apache Cordova?

PhoneGap hay Adobe PhoneGap hay Apache Cordova? Gọi thế nào cho đúng, và nó khác gì nhau?

Khi nói chuyện vẫn không ít người nhầm, có người còn hoàn toàn không biết mối quan hệ giữa những cái tên nay. Thực tế còn có nhiều người giải thích như vậy:

"PhoneGap is a distribution of Apache Cordova".

Nhưng vậy cũng là không đủ nghĩa mà còn rất nhập nhằng. Mình đã xài PhoneGap từ những ngày đầu nên nghĩ phải viết một vài dòng giải thích (có thể xem thêm trên Wikipedia và bài này Which to Use: Cordova or PhoneGap?, những giải thích sau dựa trên sườn của nó).

Trên website http://phonegap.com là website chính thức của Adobe PhoneGap định nghĩa như sau:

"From the team behind Apache Cordova, the Adobe PhoneGap framework is an open source distribution of Cordova — providing the advantage of technology created by a diverse team of pros along with a robust developer community — plus access to the PhoneGap toolset, so you can get to mobile faster."

Lưu ý ở đây là Adobe PhoneGap chứ không phải PhoneGap mới là distribution của Cordova.

PhoneGap ban đầu là tên của một dự án open source do công ty Nitobi tạo ra và quản lý. Nó được đánh giá cao bởi các tổ chức và công ty phát triển sản phẩm, trong đó có cả những cty lớn như IBM. Một số công ty còn tham gia vào project này như Google.

Năm 2011, Adobe mua lại Nitobi. Tuy nhiên, ngay trước khi bị/được mua, thì Nitobi đã tặng PhoneGap cho Apache Software Foundation. Lý do nêu ra là để bảo vệ quyền quản lý (stewardship) và tính lâu dài của dự án (biết đâu bị giết luôn). 

Sau khi được tặng Apache đổi tên là Apache Callback. Nhưng bị cho rằng quá chung chung nên tên này được đổi ngay sau đó thành Apache DeviceReady (do event hay xài deviceready). Tuy nhiên cái tên này cũng không thành công gì cả. Cuối cùng Apache đổi tên PhoneGap thành Apache Cordova (từ tên đường Nitobi đặt trụ sở chính mà ra, theo thông tin bài viết mình chưa kiểm chứng nhưng chắc là đúng :D).

Tại thời điểm này (version 1.4), Apache Cordova hay PhoneGap chỉ là hai cái tên khác nhau của cùng một thứ, không có sự khác biệt gì.

Sau khi Nitobi đã chung 1 nhà với Adobe thì team này (giờ là một phần của Adobe) đã tạo một phân phối (distribution) và đặt tên bằng cách lấy lại tên cũ + thêm Adobe đằng trước gọi là Adobe PhoneGap.

Hiện trạng đó duy trì cho đến ngày nay. Tức là mỗi khi Apache Cordova update thì Adobe (team Nitobi cũ) lại phát hành distribution dựa trên Apache Cordova (với những tính năng tăng cường từ Adobe) 

Kết luận:

Adobe PhoneGap là một phân phối do Adobe phát triển trên Apache Cordova, với một số tính năng của Adobe.

Còn PhoneGap, cũ rồi thôi quên nó đi :P.

http://www.informit.com/articles/article.aspx?p=2478076


2016-11-11

Accessing a localhost server (host) from the Genymotion emulator


Khi develop Android app thông thường sẽ có trường hợp cần access localhost server  (chẳng hạn REST API), như trong trường hợp dùng để testing.

TL;DR

Trước đây thì dùng 10.0.2.2, xem How to access localhost from a Genymotion android emulator?.
Trong bản update mới của Genymotion thì IP là 10.0.3.2. Như vậy để truy cập localhost server trên host thì trên emulator dùng http://10.0.3.2:8000 (giả sử localhost server chạy port 8000 như Laravel với php artisan serve).

Trên host machine, IP mặc định của VirtualBox Host-Only là 192.168.56.1

Ethernet adapter VirtualBox Host-Only Network:

   Connection-specific DNS Suffix  . :
   Link-local IPv6 Address . . . . . : fe80::7909:fd7d:d323:52d7%24
   IPv4 Address. . . . . . . . . . . : 192.168.56.1
   Subnet Mask . . . . . . . . . . . : 255.255.255.0
   Default Gateway . . . . . . . . . :

Như vậy có thể chạy localhost server với IP 192.168.56.1 hoặc any.
Nếu đang sau proxy settings thì phải bypass proxy trong emulator, thực hiện vào Settings → Wifi → chọn Connected Wifi (WiredSSID), click và giữ chọn để hiển thị (click & hold) → Modify network → Thêm bypass proxy cho 10.0.3.*

Just fight for your life ...

1 cái note mình viết trên FB từ 2009, 7 năm trôi qua vẫn còn thấy có những điều phải suy nghĩ về nghề nghiệp :D.


November 10, 2009 at 2:42am

People say "Programming is for fun, not for money" and many people get in programming with this idea. Sometimes I have the same thought but is it really true? Programming is neither inherently fun or not fun. Career path, the lack of a programming-centric. I can't work for a little of money or work without any of the potential benefits. 

Faster, better, cheaper but how... Almost programs you developed are incomplete softwares, just-runable things. Even you don't know what they are. So you develop/create what or you're just forced to write something you don't like. Really fun? 

Many companies think the good way to encourage smart developers is moving them elsewhere, 'moving into management'. New opportunities, new challenges? Maybe. But I don't think experienced developers really want to move into management. Developers do that because they feel a lot of pressure while companies often don't know what to do with their developers. And the most stupid thing about this is a really good developer is worth far more than any low or middle level manager. 

All fool things, I won't care. Now I'll looking for really exciting programs and enjoy lots of new thing. Try to get enough money with bored job. Professional programming is a profession and has its good points and bad points. So fight for your fun...

2016-11-06

Reactive programming, từ declarative programming đến RxJava, RxAndroid (phần 1)

Dạo sau này khi code mình xài Python, Scala nhiều hơn. Một cách tự nhiên sẽ đụng nhiều hơn về functional programming. Tất nhiên lúc trước khi code web và Node thì cũng đã không lạ gì với style này kiểu như chắc chắn phải xài lodash chẳng hạn. 1 thời gian sau đó là xem qua Swift và dạo gần đây là RxAndroid. Có vẻ functional programming đang được chú ý nhiều ngày càng nhiều hơn. Lại nhớ cái hồi F# mới ra, cũng download sách vào đọc 1 xíu xong rồi cũng quăn :D. Cũng nhiều lần tính nghiên cứu sâu hơn, định note lại những cái đã xem lâu rồi nhưng lười. Bây giờ thì "ít lười" hơn, và cũng nên note lại cho thấm.


RxAndroid

RxJava là một bản port từ Netflix của Reactive Extensions (Rx) dành cho Java. 
Ban đầu Reactive Extensions (Rx) chỉ là một bộ thư viện (a set of libraries) do một nhóm nghiên cứu tại Microsoft Open Technologies do Erik Meijer (kiến trúc sư/architect) và các thành viên (có thể kể đến Jeffery Van GoghWes DyerBart De Smet) phát triển.
Sau đó Rx được công bố mã nguồn (November, 2012) trở thành open-source project trên Codeplex (đã chuyển qua Github Reactive Extensions for .NET) với mục đích mở rộng việc sử dụng Rx để tăng khả năng tương tác cho các ứng dụng trên nhiều loại thiết bị và môi trường cloud. 
Trong một bài phỏng vấn (Rx in 15 minutes - Rx is here!!!!!), Erik Meijer (Architect) đã trình bày ý tưởng tạo ra Rx khi so sánh mô hình Pull (Interactive) với mô hình Push (Reactive) với data source IEnumerable (đặc biệt để tăng hiệu quả làm việc với LINQ). Rx được tạo ra bằng cách định nghĩa IObservables và IObservers tương ứng với IEnumerables và IEnumerators, unify các method và cách sử dụng (hay API).Theo đó định nghĩa ban đầu của Rx là Rx = Observables + LINQ + Schedulers.

RxJava được định nghĩa như sau:
RxJava is a Java VM implementation of ReactiveX (Reactive Extensions): a library for composing asynchronous and event-based programs by using observable sequences.

RxAndroid là mở rộng của RxJava sử dụng cho lập trình ứng dụng Android.
RxAndroid adds the minimum classes to RxJava that make writing reactive components in Android applications easy and hassle-free.

What is ReactiveX?

Theo giới thiệu của chính ReactiveX thì ReactiveX là
An API for asynchronous programming with observable streams.
hay
ReactiveX is a combination of the best ideas from the Observer pattern, the Iterator pattern, and functional programming.
ReactiveX dùng để lập trình bất đồng bộ với các dòng dữ liệu có thể "quan sát" (có nghĩa là push/emit, dạng push model). Hay ReactiveX là sự kết hợp các ý tưởng tốt nhất từ Observer patternIterator pattern và functional programming (lập trình hàm).

Có thể dùng ReactiveX với nhiều implementation cho các ngôn ngữ khác nhau: RxJava, RxJS, Rx.NET, RxScala, RxPy hay RxSwift...

Programming paradigms

Trước khi sử dụng reactive programming (RP) cần nói qua về programming paradigm. Tiếp theo cần phân biệt hai programming paradigm là imperative programming và  declarative programming.
Paradigm là gì? Paradigm là một thuật ngữ chỉ hình mẫu, lý thuyết, khái niệm, giả thuyết hoặc khung tham chiếu. Có một vài ý kiến cho rằng có thể dịch paradigm thành mô hình trong tiếng Việt, tức programming paradigm sẽ dịch là mô hình lập trình. Tuy nhiên "mô hình" không thể truyền tải hết những ý nghĩa của của paradigm. Có thể coi thuật ngữ paradigm tương ứng với ý nghĩa của từ mô thức(method + model + pattern .../模式 [MÔ THỨC], 範例 [PHẠM LỆ] hay 模范 [MÔ PHẠM]) tức là mô hình hình mẫu kết hợp với phương thức, cách thức. Cũng có thể cho rằng một programming paradigm là một trường phái lập trình (school/流派 [LƯU PHÁI]).

Không thể có sự so sánh chung cho các paradigm vì không có tiêu chuẩn để so sánh và căn bản các paradigm có các suy nghĩ, cách nhìn và phương pháp hoàn toàn khác nhau.

Ví dụ các programming paradigm hay được nhắc tới như sau:
§  Imperative programming (tạm dịch lập trình chỉ thị/mệnh lệnh)
§  Declarative programming (tạm dịch lập trình khai báo)
§  Object-oriented programming (OOP, lập trình hướng đối tượng)
§  Procedural programming (tạm dịch lập trình thủ tục)
§  Functional programming (tạm dịch lập trình hàm/lập trình hướng chức năng)
§  Logic programming

Functional programming và logic programming có thể được coi là "declarative".
Hầu hết các ngôn ngữ lập trình đều là các ngôn ngữ nhiều paradigm (multi-paradigm programming languages) có nghĩa support nhiều hơn một programming paradigm.

Imperative programming vs declarative programming

Imperative programming theo Wikipedia
Imperative programming is a programming paradigm that uses statements that change program's state.
Là paradigm sử dụng các phát biểu/lệnh/chỉ thị (statements/instructions) dùng để thay đổi trạng thái của chương trình.
Imperative programming focuses on describing how a program operates.
Imperative programming tập trung vào việc mô tả các chương trình thực hiện. Tức tập trung vào mô tả làm các nào thực hiện việc gì đó, chỉ thị cho computer/compiler thực hiện những gì mình muốn xảy ra từng bước (giống đặt bản thân vào vai của computer). Đây là các tiếp cận với programming rất tự nhiên từ những ngày đầu khi mà compiler còn rất đơn giản.

Structured programming là programming paradigm subset của imperative programming khi các chức năng (functionality) được chia thành những đơn vị (units). Cách thực hiện phân chia có thể thấy như phân chia thành blockscontrol flows, và subroutines hay cao hơn là những modulespackages. Ví dụ với control flow có thể thấy cách tiếp cận này đã không còn khuyến khích sử dụng go-to statements.

Theo định nghĩa như trên thì object oriented programming (OOP như C#, Java, Python) "tự nhiên" được coi là subset của structured programming khi các chức năng được tổ chức theo hướng chia thành những đối tượng. 
Phần còn lại không hướng đối tượng mà tổ chức  tổ chức các statements thành những procedures (hay functions) được gọi là procedural programming (như Pascal, Fortran, C) hiển nhiên cũng là một subset của structured programming.
Thật ra cũng có những ý kiến không đồng tình với kết luận trên khi cho rằng nếu đơn thuần structured programming sẽ có cách tiếp cập top-down trong khi đó OOP lại có cả cách tiếp cập bottom-up (khi bài toán đi lên từ các object). 
Tương tự có ý kiến không đồng ý quan hệ giữa OOP và procedural programming trong structured programming như đã nói ở trên khi cho rằnh OOP là subset của procedural programming khi mà việc thao tác với các objects cũng thông qua các methods đã được định sẵn. Tất nhiên là không có vấn đề gì. Tình huống này giống như việc mọi người hay so sánh giữa C++ và C nhưng phần lớn trường hợp C là subset của C++ (well written, và chính xác hơn là ANSI C, xem Is C a subset of C++?).
Ngược lại với imperative programming, declarative programming được định nghĩa như sau:
Declarative programming is a programming paradigm—a style of building the structure and elements of computer programs—that expresses the logic of a computation without describing its control flow.
Declarative programming mô tả vấn đề hay cách giải quyết mà không đi sâu vào việc mô tả tường minh trạng thái của công việc sẽ được tiến hành. Tức là mô tả cái mà mình mong muốn và phần còn lại cách thực hiện sẽ dành cho computer. 

Việc này có liên quan nhiều đến sự so sánh giữa statements và expressions.
Expression (biểu thức) thể hiện hay là cách mô tả giá trị, cần phải được evaluated (đánh giá) để trả về giá trị (tức nếu chỉ riêng một mình thì expression không thể làm gì cả). Một ví dụ hay gặp là biểu thức logic (logical expression/boolean expression). Do đó expression có thể pass như một đối số (argument) cho một function trong khi statement thông thường thì không (do không trả về giá trị). 
Vấn đề là với các ngôn ngữ như C/C++ chỉ cần thêm semicolon ; là có thể chuyển một expression thành một statement gọi là expression statements. Rõ ràng mọi developer đều nhận thấy là expression sẽ được evaluated và giá trị trả về coi như bị vứt đi (có vẻ như vô hại).
Điều đáng nói ở đây là trường hợp của gán giá trị assignment và toán tử gán assignment operator. Một khi cho phép expression chuyển thành một statement thì thông thường toán tử gán (assignment operator) cũng được cho phép xuất hiện trong expression (như C/C++), tức là cho phép việc chuyển một statement thành một expression. Với các ngôn ngữ cho phép điều này (C/C++) giá trị trả về của assignment statement sẽ là giá trị của expression sau khi evaluated và gán cho variable. Khi đó assignment statement không đơn thuần là một statement mà còn là một expression.
Việc duy trì quan hệ statements và expressions như trên được cho rằng sẽ có thể dẫn tới side-effects. Khi xem kỹ đoạn code sau, chuyện xảy ra nếu func có thể làm một điều gì đó không hay, có vẻ như không còn vô hại được nữa:

1 + 2 * func(3);

Side effects là gì? Nói chung là những hiệu ứng không mong muốn. Ví dụ khi thực hiện một statement có trả về một kết quả ẩn và kết quả trả về này có thể làm thay đổi giá trị được lưu trữ (hay nói chung là trạng thái) của các đối tượng khác. 
Giả sử một lỗi nếu mắc phải với assignment operator của C/C++ thì rất khó nhận ra (nhất là thời kỳ IDE còn cùi mía): phép gán trả về kết quả 10 và tự động casting sang kiểu boolean là true.

if(a = 10) {

}

Hay một ví dụ tương tự cũng của  assignment operator như sau

double x = 3.5;
int y;
double z = y = x;  // z = 3

Ngoài ra side-effect cũng thường xảy ra khi một function call thay đổi một giá trị bên ngoài (outside world, như global variable hay static variable hay thậm chí một method thay đổi một member variable không tường minh hoặc không theo đúng thiết kế).

Việc nhập nhằng giữa statements và expressions có thể thấy xảy ra ở tất cả các ngôn ngữ giống C (bao gồm C/C++, C# hay Java). Một số nhà thiết kế ngôn ngữ lập trình nghĩ theo hướng khác vì không thích điều này và mong muốn là tìm một giải pháp giảm thiểu side-effects. Theo đó một cách "tự nhiên" imperative programming thiên về statements thì declarative programming focus vào solution sẽ thiên về expressions. Ví dụ các functional programming sẽ tìm cách loại bỏ statements nhất là assignment statements bằng cách chỉ sử dụng expressions và một dạng gọi là khởi tạo giá trị (initialization) hay declaration style.
Để dễ hiểu hơn 1 chút, bạn cần xem qua ví dụ tính tổng một array. Với imperative programming, việc thực hiện dạng như sau:

var  numbers = [1, 2, 3, 4, 5]
var  sum = 0
for(var i = 0; i < numbers.length; i++) {
   sum = sum + numbers[i];
}

Với declarative programming code sẽ có dạng như sau

var numbers = [1, 2, 3, 4, 5]
var sum = numbers.reduce((x, y) => x + y)

Cụ thể với Scala 

val numbers = Array(1, 2, 3, 4, 5)
var sum = 0
       
for(i <- 0 to numbers.length - 1) {
   sum = sum + numbers(i)
}


val numbers = Array(1, 2, 3, 4, 5)
val sum = numbers.reduceLeft[Int](_ + _)

Hay x2 với một array cách tiếp cận imperative programming sẽ là khai báo một array mới, duyệt array cũ và push vào array mới từng giá trị của element nhân 2. Trong khi declarative programming sẽ code như sau:

val numbers = Array(1, 2, 3, 4, 5)
val doubled = numbers.map(x => 2 * x)

Ví dụ trên thể hiện hai "cái nhìn" rất khác nhau, với declarative programming thì việc quan tâm là focus vào logic như x => 2 *x. Tất nhiên nhiều người sẽ đặt câu hỏi, chuyện gì ở bên trong function map hay reduce kia. Rõ ràng có thể đặt lại vấn đề là việc thực hiện này có sự giúp sức của libraries hay hệ thống.

Thực ra có thể đưa ra ví dụ dễ dàng bắt gặp hơn (đồng nghĩa là ít thắc mắc/ý kiến hơn) khi sử dụng ngôn ngữ truy vấn như SQL:

SELECT * FROM Users WHERE country = 'USA';

Rõ ràng ít người thắc mắc câu query này hoạt động như thế nào hơn là việc xuất hiện cái method map hay reduce kia (gần như chấp nhận). Con người là như vậy, nhiều khi biết 1 chút ít sẽ là rào cản để đón nhận cái mới.
Một số ví dụ khác có thể thấy trong những năm qua như LINQ với C#

var odds = collection.Where(num => num % 2 != 0);

Thực ra các markup languages không xa lạ gì như HTML, XML, XAML là những ví dụ thiên về declarative khi được sử dụng để khai báo UI thay vì thực sự code để paint UI (được render bởi engine/libraries).
Declarative programming có lẽ gần với giấc mơ về lập trình hơn. Vì một ngày nào đó sẽ chỉ cần dùng ngôn ngữ tự nhiên coding bằng cách kêu computer tính "sum" mà không cần code một cái gì hết.
Việc sử dụng declarative programming được cho là giảm thiểu side effects (tác dụng phụ/hiệu ứng phụ/hiệu ứng bên lề). Điều này sẽ được nói rõ hơn với functional programming.

Reactive programming

Reactive programming (RP, tạm dịch lập trình phản ứng) không phải là khái niệm mới mẻ vì thực chất đã được giới thiệu từ những năm 70s. Tuy nhiên có những hạn chế về mặt implementation (compiler còn chưa phát triển) và quan trọng nhất là nhu cầu hay yêu cầu để nó có thể phát triển còn chưa lớn, chưa có một enterprise lớn dạng "cây đa cây đề" nào phát động. Sự phát triển của reactive programming không phải là ngẫu nhiên khi đi chung với sự phát triển của microservices (kiến trúc nhiều dịch vụ nhỏ), multi-core CPU, distributed processing hay parallel distributed processing tức việc xử lý data thường có tính chất concurrent, parallel (xem thêm concurrent vs parallel), asynchronous (bất đồng bộ), từ nhiều nguồn (hay là nhiều flow). Xem thêm Notes on Reactive Programming tại Spring.io hay Why Reactive Programming Is Not a Fad tại DZone.

Theo Wikipedia:
Reactive programming is a programming paradigm oriented around data flows and the propagation of change.

Reactive programming là programming paradigm hướng tới việc xử lý dòng dữ liệu và sự lan truyền thay đổi.
Đơn giản có thể coi reactive programming là cách lập trình với những toolbox nhằm nâng mức trừu tượng (the level of abstraction) của source code lên một mức cao hơn khi focus (tập trung) vào việc xử lý các  sự kiện và quan hệ giữa các sự kiện (the interdependence of events) mô tả business logic thay vì phải tốn nhiều thời gian cho việc tổ chức cài đặt (implementation) các chi tiết nhằm giải quyết các business logic này.

Phần sau sẽ trình bày tiếp functional programming, functional reactive programming trước khi đi qua RxJava.