Commit 3b9a5cf70191e2f27991f771c2f6a708dc87ea7a
delete original posts
Kamal Bin Mustafa committed on 3/29/2015, 2:26:19 PMParent: f99e70d9056cac29bb7152c2d6305a3383e87d32
Files changed
_posts/2012-12-15-automated-testing.md | ||
---|---|---|
@@ -1,239 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: "Automated Testing Dalam Pembangunan Perisian" | |
4 | -date: 2012-12-15 01:19 | |
5 | -permalink: /automated-testing-dalam-pembangunan-perisian.html | |
6 | -include_toc: true | |
7 | -level: 2 | |
8 | ---- | |
9 | - | |
10 | -_Testing_ adalah sebahagian daripada proses pembangunan perisian komputer. Setiap kali baris-baris kod ditulis, diubah atau dipadam, ia mesti melalui proses testing bagi memastikan program tersebut masih lagi berjalan sebagaimana yang diharapkan. Ini bermakna kita sama sekali tidak boleh mengelak daripada melakukan _testing_ terhadap program atau aplikasi yang kita bangunkan. | |
11 | - | |
12 | -<!--more--> | |
13 | - | |
14 | -## Manual Testing | |
15 | -Testing biasanya dilakukan secara manual dengan pengaturcara cuba menjalankan aturcara atau aplikasi yang dibangunkan dan memerhatikan sama ada ia mengeluarkan output yang dikehendaki ataupun semua _features_ berfungsi sebagai mana diharapkan. Ambil contoh aturcara ringkas berikut:- | |
16 | - | |
17 | -{% highlight python %} | |
18 | - function add(num1, num2) { | |
19 | - return num1 + num2; | |
20 | - } | |
21 | - | |
22 | - print add(1, 2) . "\n" # akan paparkan 3 | |
23 | - print add(2, 2) . "\n" # akan paparkan 4 | |
24 | -{% endhighlight %} | |
25 | - | |
26 | -Andaikan aturcara diatas ditulis menggunakan bahasa PHP dan disimpan dalam fail bernama `add.php`. Untuk menguji aturcara ini, pengaturcara akan `execute` fail tersebut dan memerhatikan sama ada ia memaparkan out yang diharapkan iaitu:- | |
27 | - | |
28 | - 3 | |
29 | - 4 | |
30 | - | |
31 | -Aturcara tersebut mungkin boleh dijalankan seperti berikut:- | |
32 | - | |
33 | -{% highlight bash %} | |
34 | - php add.php | |
35 | - 3 | |
36 | - 4 | |
37 | -{% endhighlight %} | |
38 | - | |
39 | -Di atas kita dapati aturcara tersebut memaparkan output yang kita kehendaki. Sekarang kita andaikan berlaku sedikit kesilapan dalam kod tersebut. Katakan ia ditulis seperti berikut:- | |
40 | - | |
41 | -{% highlight python %} | |
42 | - function add(num1, num2) { | |
43 | - return num1 * num2; | |
44 | - } | |
45 | - | |
46 | - print add(1, 2) . "\n"; # akan paparkan 3 | |
47 | - print add(2, 2) . "\n"; # akan paparkan 4 | |
48 | -{% endhighlight %} | |
49 | - | |
50 | -Apabila dijalankan, kita akan dapati outputnya berlainan:- | |
51 | - | |
52 | - 2 | |
53 | - 4 | |
54 | - | |
55 | -Ini bermakna program tersebut gagal dalam proses _testing_ kita. Cara _testing_ seperti diatas walaupun mudah untuk difahami dan diamalkan ia menjadi amat tidak efektif apabila program semakin berkembang dan kompleks. Ia juga tidak efektif kerana bergantung semata-mata kepada keupayaan mata kita untuk mengesan perbezaan pada output yang dipaparkan. Bukan mahu menidakkan keupayaan mata namun manusia sememangnya tidak sesuai untuk melakukan kerja-kerja leceh dan remeh seperti ini. Disinilah fungsi komputer supaya manusia boleh menumpukan kepada kerja-kerja yang lebih memerlukan daya fikir, intelek serta kreativiti yang tinggi. | |
56 | - | |
57 | -## Automated Testing | |
58 | -Dalam proses _testing_ secara manual di atas, kita bergantung kepada tenaga manusia untuk memerhatikan semasa program dijalankan, ia menghasilkan output yang dikehendaki atau tidak. Dalam _automated testing_ kita akan menulis satu aturcara lain bagi menguji aturcara yang dibangunkan. Ini membolehkan kita untuk _delegate_ tugas-tugas menguji tersebut kepada komputer yang sudah semestinya lebih efisyen untuk melaksanakannya. | |
59 | - | |
60 | -Contoh kod sebelum ini boleh ditulis seperti berikut untuk <fill in>:- | |
61 | - | |
62 | -{% highlight php %} | |
63 | - function add($num1, $num2) { | |
64 | - return $num1 * $num2; | |
65 | - } | |
66 | - | |
67 | - assert(add(1, 2) === 3); | |
68 | - assert(add(2, 2) === 4); | |
69 | -{% endhighlight %} | |
70 | - | |
71 | -Apabila dijalankan kita akan melihat output seperti berikut:- | |
72 | - | |
73 | - Warning: assert(): Assertion failed in /home/rkiteratai/add.php on line 6 | |
74 | - | |
75 | -Aah, sekarang anda sudah dapat melihat bagaimana komputer sudah mula mengambil peranan manusia dalam menguji kod aturcara. | |
76 | - | |
77 | -Kod automated testing boleh ditulis dengan 2 cara, sama ada selepas kod aturcara perisian siap ditulis atau sebelum kod aturcara perisian ditulis. | |
78 | - | |
79 | -## Kategori _Test_ | |
80 | -* Unit Test | |
81 | -* Functional Test | |
82 | -* Integration Test | |
83 | -* Stress Test | |
84 | - | |
85 | -## Test Framework | |
86 | -... | |
87 | - | |
88 | -## Contoh Test mengikut bahasa pengaturcaraan | |
89 | - | |
90 | -### Unit Test dalam C# (.NET) | |
91 | - | |
92 | -Dalam dunia .NET, antara _unit testing framework_ yang paling awal dan paling meluas digunakan ialah NUnit. Berikut adalah contoh bagaimana ia digunakan. | |
93 | - | |
94 | -Katakan kod yang ingin diuji adalah seperti berikut: | |
95 | - | |
96 | -{% highlight csharp %} | |
97 | -class Calculator | |
98 | -{ | |
99 | - public int Add(int operand1, int operand2) | |
100 | - { | |
101 | - return operand1 + operand2; | |
102 | - } | |
103 | - | |
104 | - public int Minus(int operand1, int operand2) | |
105 | - { | |
106 | - return operand1 + operand2; | |
107 | - } | |
108 | -} | |
109 | -{% endhighlight %} | |
110 | - | |
111 | -Kita boleh membuat _test fixture_ seperti ini untuk mengujinya: | |
112 | - | |
113 | -{% highlight csharp %} | |
114 | -using NUnit.Framework | |
115 | - | |
116 | -[TestFixture] | |
117 | -public class CalculatorTest | |
118 | -{ | |
119 | - [Test] | |
120 | - public void AddShouldDoSum() | |
121 | - { | |
122 | - var calc = new Calculator(); | |
123 | - var result = calc.Add(2, 1); | |
124 | - | |
125 | - Assert.AreEqual(3, result); | |
126 | - } | |
127 | - | |
128 | - [Test] | |
129 | - public void MinusShouldDoSubtraction() | |
130 | - { | |
131 | - var calc = new Calculator(); | |
132 | - var result = calc.Minus(2, 1); | |
133 | - | |
134 | - Assert.AreEqual(1, result); | |
135 | - } | |
136 | -} | |
137 | -{% endhighlight %} | |
138 | - | |
139 | -Setelah _test code_ di atas dikompil menjadi _assembly_ (DLL) atau _executable_, larikan ia menggunakan sama ada _console runner_ (nunit-console.exe) atau _GUI runner_ (nunit-gui.exe). | |
140 | - | |
141 | -Di bawah adalah contoh apa bila ia dilarikan menggunakan _GUI NUnit runner_. Kita dapat lihat bahawa _test_ untuk fungsi _Add()_ berjaya, tetapi _test_ untuk _Minus()_ gagal kerana terdapat kesilapan dalam _code_ kita. | |
142 | - | |
143 | -![Contoh antaramuka NUnit GUI Runner](http://i.imgur.com/m8z2n.png) | |
144 | - | |
145 | -### Unit Test Python | |
146 | -Kod untuk testing dalam Python boleh ditulis dengan bantuan module `unittest` dalam Python Standard Library. Katakan kod yang ingin diuji adalah seperti berikut: | |
147 | - | |
148 | -{% highlight python %} | |
149 | -class Calculator(object): | |
150 | - def add(self, num1, num2): | |
151 | - return num1 + num2 | |
152 | - | |
153 | - def minus(self, num1, num2): | |
154 | - return num1 + num2 | |
155 | -{% endhighlight %} | |
156 | - | |
157 | -Simpan kod di atas dalam fail bernama `calculator.py`. Seterusnya kod untuk testing boleh ditulis seperti berikut:- | |
158 | - | |
159 | -{% highlight python %} | |
160 | -import unittest | |
161 | - | |
162 | -from calculator import Calculator | |
163 | - | |
164 | -class CalculatorTest(unittest.TestCase): | |
165 | - def test_add_should_do_sum(self): | |
166 | - calc = Calculator() | |
167 | - result = calc.add(2, 1) | |
168 | - | |
169 | - self.assertEqual(result, 3) | |
170 | - | |
171 | - def test_minus_should_do_substraction(self): | |
172 | - calc = Calculator() | |
173 | - result = calc.minus(2, 1) | |
174 | - | |
175 | - self.assertEqual(result, 1) | |
176 | - | |
177 | -if __name__ == '__main__': | |
178 | - unittest.main() | |
179 | -{% endhighlight %} | |
180 | -Simpan kod di atas dalam fail bernama `tests.py`. Seterusnya kita boleh jalankan test dengan melancarkan arahan berikut melalui console:- | |
181 | - | |
182 | -{% highlight console %} | |
183 | -python tests.py | |
184 | -{% endhighlight %} | |
185 | -Anda akan dapati outputnya seperti berikut:- | |
186 | - | |
187 | -{% highlight console %} | |
188 | -.F | |
189 | -====================================================================== | |
190 | -FAIL: test_minus_should_do_substraction (__main__.CalculatorTest) | |
191 | ----------------------------------------------------------------------- | |
192 | -Traceback (most recent call last): | |
193 | - File "tests.py", line 16, in test_minus_should_do_substraction | |
194 | - self.assertEqual(result, 1) | |
195 | -AssertionError: 3 != 1 | |
196 | - | |
197 | ----------------------------------------------------------------------- | |
198 | -Ran 2 tests in 0.000s | |
199 | - | |
200 | -FAILED (failures=1) | |
201 | -{% endhighlight %} | |
202 | - | |
203 | -Di atas kita dapati satu test gagal kerana terdapat kesilapan dalam kod kita sebelum ini. Setelah kesilapan itu dibetulkan, kita akan dapati outputnya seperti berikut:- | |
204 | - | |
205 | -{% highlight console %} | |
206 | -.. | |
207 | ----------------------------------------------------------------------- | |
208 | -Ran 2 tests in 0.000s | |
209 | - | |
210 | -OK | |
211 | -{% endhighlight %} | |
212 | - | |
213 | -## Soalan Lazim | |
214 | - | |
215 | -### Apa itu _assert_ ? | |
216 | -_Assertion_ merupakan satu proses menguji nilai pada bahagian-bahagian tertentu aturcara bagi memastikan ia sentiasa benar sebagaimana yang diharapkan oleh pengaturcara. Kegagalan pada _assertion_ boleh dianggap sebagai kegagalan langsung aturcara tersebut dan ia mesti dibetulkan. Ini berbeza dengan _error handling_ dimana ia sesuatu yang dijangka akan berlaku dan pengaturcara hanya perlu memastikan langkah-langkah sepatutnya dilakukan untuk menangani _error_ tersebut.[^1] | |
217 | - | |
218 | -### Apa itu _regression_ ? | |
219 | -_Regress_ adalah berlawanan kepada _progress_, maksudnya kita bergerak ke belakang. Bug yang sudah dibetulkan muncul balik akibat penambahan baru pada code. Ia biasa berlaku dalam development apabila kita fix sesuatu bug dan kemudian deploy code tersebut ke server live, selepas beberapa ketika akan dapat komplen akan isu baru dan bila diselidiki ia adalah disebabkan oleh fix sebelum ini. Satu kelebihan automated tests adalah boleh detect regression dengan lebih cepat, sebelum code sampai ke production. | |
220 | - | |
221 | -### Bagaimana menguruskan test yang melibatkan beberapa data berlainan tapi logik yang sama ? | |
222 | -Boleh gunakan teknik seperti [data provider][1] (minit 19:13) atau [test generator][2]. | |
223 | - | |
224 | -### Boleh tulis test dulu sebelum menulis kode ? | |
225 | -Ya boleh. Ia dinamakan Test Driven Development (TDD). Dalam TDD, kita akan mulakan menulis satu set test terhadap komponen yang hendak dibangunkan. Test biasanya akan pass input-input yang diperlukan oleh function atau class terbabit dan akan check _return value_ sama ada menepati requirement atau tidak. Pada peringkat ini kesemua function atau class yang hendak di test adalah stub dan test akan fail. Seterusnya kita akan mula implement function atau class berkenaan sehingga semua test pass. Bagaimanapun secara realiti TDD jarang dapat dipraktikkan sepenuhnya. Code biasanya ditulis tanpa sebarang test dan bila ia mula mencapai peringkat tertentu barulah test ditulis untuk memastikan ia berfungsi sebagaimana diharapkan. | |
226 | - | |
227 | -## Penulis | |
228 | -Nama-nama di bawah adalah penyumbang kepada tulisan ini:- | |
229 | - | |
230 | -* Mohd. Kamal bin Mustafa (k4ml) - http://k4ml.github.com/ | |
231 | -* Mohd Amree (amree) - http://ieatbinary.com/ | |
232 | -* Mior Muhammad Zaki (crynobone) - http://crynobone.com/ | |
233 | -* Irwan Azam Ahmad (ryzam) - https://github.com/ryzam | |
234 | -* Ikhwan Hayat (ikhwanhayat) - https://github.com/ikhwanhayat | |
235 | - | |
236 | -[^1]: http://en.wikipedia.org/wiki/Assertion_(computing) | |
237 | - | |
238 | -[1]:http://www.youtube.com/watch?v=84j61_aI0q8&feature=player_embedded#t=1130s | |
239 | -[2]:https://gist.github.com/k4ml/5165424 |
_posts/2012-12-22-buku-pilihan.md | ||
---|---|---|
@@ -1,33 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: Buku-buku Pilihan | |
4 | -date: 2012-12-22 16:13:00 | |
5 | -permalink: /buku-buku-pilihan.html | |
6 | -level: 1 | |
7 | ---- | |
8 | - | |
9 | -Senarai buku-buku yang direkomen oleh ahli-ahli komuniti MyDev. Senarai ini adalah berdasarkan [topik perbincangan][1] di laman [komuniti G+ MyDev][2]. | |
10 | - | |
11 | -<!--more--> | |
12 | - | |
13 | -1. [The Pragmatic Programmer](http://www.amazon.com/Pragmatic-Programmer-Journeyman-Master/dp/020161622X) | |
14 | -1. [Head First Design Patterns](http://shop.oreilly.com/product/9780596007126.do) | |
15 | -1. [Ship It](http://pragprog.com/book/prj/ship-it) | |
16 | -1. [Write Great Code - Understanding Machine](http://www.amazon.com/Write-Great-Code-Understanding-Machine/dp/1593270038/ref=pd_sim_b_1) | |
17 | -1. [Write Great Code, Volume 2: Thinking Low-Level, Writing High-Level](http://www.amazon.com/Write-Great-Code-Volume-High-Level/dp/1593270658/ref=pd_sim_b_1) | |
18 | -1. [Eric Sink on the Business of Software](http://www.amazon.com/Eric-Business-Software-Experts-Voice/dp/1590596234) | |
19 | -1. [Refactoring](http://www.amazon.com/Refactoring-Improving-Design-Existing-Code/dp/0201485672) | |
20 | -1. [Patterns of Enterprise Application Architecture](http://www.amazon.com/Patterns-Enterprise-Application-Architecture-Martin/dp/0321127420) | |
21 | -1. [Domain-Driven Design](http://www.amazon.com/Domain-Driven-Design-Tackling-Complexity-Software/dp/0321125215/) | |
22 | -1. [Applying UML and Patterns: An Introduction to Object-Oriented Analysis and Design and Iterative Development (3rd Edition)](http://www.amazon.com/Applying-UML-Patterns-Introduction-Object-Oriented/dp/0131489062) | |
23 | -1. [Design Patterns: Elements of Reusable Object-Oriented Software](http://www.amazon.com/Design-Patterns-Object-Oriented-Professional-Computing/dp/0201634988) | |
24 | -1. [High Performance MySQL: Optimization, Backups, and Replication](http://www.amazon.com/High-Performance-MySQL-Optimization-Replication/dp/1449314287) | |
25 | -1. [Enterprise Integration Patterns](http://www.amazon.com/o/asin/0321200683/ref=nosim/enterpriseint-20) | |
26 | -1. [The Art of Scalability - Scalable Web Architecture, Processes, and | |
27 | -Organizations for the Modern Enterprise](http://theartofscalability.com/) | |
28 | - | |
29 | -Sebarang tambahan kepada senarai di atas adalah dialu-alukan. Anda boleh melakukannya sama ada dengan 'fork' [repo mydev][3] di github dan membuat 'pull request' atau menambahnya ke [topik perbincangan][1] di [komuniti G+][2]. | |
30 | - | |
31 | -[1]:https://plus.google.com/u/0/105721265741813048018/posts/chsdf4ekQ8S | |
32 | -[2]:https://plus.google.com/u/0/communities/104883828501447858589 | |
33 | -[3]:https://github.com/mydevcommunity/mydev |
_posts/2012-12-28-jargon-pengaturcaraan.md | ||
---|---|---|
@@ -1,79 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: Jargon Pengaturcaraan | |
4 | -date: 2012-12-28 10:14 | |
5 | -permalink: /jargon-pengaturcaraan.html | |
6 | -level: 1 | |
7 | ---- | |
8 | - | |
9 | -**Jargon** adalah perkataan atau frasa istimewa yang sukar difahami. Dalam bidang pembangunan perisian, seperti bidang profesional lain, seringkali terdapat perkataan-perkataan sukar ini. Artikel ini bertujuan untuk mengumpulkan jargon tersebut berserta dengan penerangan ringkas mengenainya sebagai rujukan mudah untuk semua. | |
10 | - | |
11 | -<!--more--> | |
12 | - | |
13 | -Gunakan fungsi _find_ (Ctrl+F) dalam pelayar web anda untuk membuat carian dan untuk navigasi. | |
14 | - | |
15 | ---- | |
16 | - | |
17 | -1. **Automated Testing** : Ujian yang diautomasikan. Satu program tertentu dijalankan dan ia akan melakukan ujian terhadap sistem. | |
18 | - | |
19 | -1. **Bug** : Ralat atau kecacatan di dalam sistem. | |
20 | - | |
21 | -1. **Business Layer** : Salah satu layer dalam N-Layered Architecture. Menempatkan aturcara yang menjalankan kerja utama dalam sistem tersebut. | |
22 | - | |
23 | -1. **Class Diagram** : Rajah berbentuk blok-blok yang mewakili `class`. Ia menunjukkan struktur `class` dan hubungan antaranya. Sebahagian dari UML. | |
24 | - | |
25 | -1. **Cloud Computing** : Penggunaan sumber komputer (hardware dan software) yang dihantar sebagai servis melalui network (Internet) | |
26 | - | |
27 | -1. **Data Layer** : Salah satu layer dalam N-Layered Architecture. Menempatkan aturcara yang berinteraksi dengan storan/simpanan/pangkalan data. | |
28 | - | |
29 | -1. **Data Transfer Object (DTO)** : Struktur yang dipermudahkan untuk tujuan penghantaran data dari satu bahagian ke bahagian lain. Suatu domain class yang kompleks mungkin dipermudahkan untuk menghantaran melalui web service atau paparan di UI. | |
30 | - | |
31 | -1. **Domain Expert** : Pihak yang pakar tentang keperluan sistem dan masalah yang ingin diselesaikan. Biasanya terlibat dalam System Requirements Study (SRS). Juga dipanggil Subject Matter Expert (SME). | |
32 | - | |
33 | -1. **Entity Relationship Diagram (ERD)** : Rajah yang menunjukkan table di dalam pangkalan data, column yang terdapat di dalamnya, dan hunbungan antara table-table tersebut. | |
34 | - | |
35 | -1. **Integrated Development Environment (IDE)** : Suatu pakej aplikasi yang digunakan untuk membina aturcara. Mungkin di dalam satu program atau berbilang program. Biasanya mengandungi editor, compiler, debugger dan sokongan lain seperti bantuan utk melayari dokumentasi, code completion dan sebagainya. | |
36 | - | |
37 | -1. **Model View Controller (MVC)** : Satu senibina sistem di mana ia dipecahkan kepada 3 komponen. Model mewakili entiti di dalam sistem. View adalah UI yang dipaparkan kepada pengguna. Controller adalah mengantara dan pemudahcara antara Model dan View, ia berperanan menerima input dan mengarahkan komponen lain bergerak. | |
38 | - | |
39 | -1. **Monkey Patching** : Suatu teknik dalam dynamic programming di mana suatu function/method disuntik ke dalam objek semasa runtime, walaupun class asalnya tidak memiliki function/method tersebut. | |
40 | - | |
41 | -1. **N-Layered Architecture** : Pendekatan merekabentuk sistem dengan membahagikan kepada bahagian yang dinamakan _layer_. Kebiasaannya 2-Layer, 3-Layer, atau 4-Layer. | |
42 | - | |
43 | -1. **Persistence** : Storan atau simpanan. Biasanya pangkalan data, sistem fail dan sebagainya. | |
44 | - | |
45 | -1. **Platform as a Service (PaaS)** : Satu kategori servis komputer cloud di mana ia membekal platform dan kaedah komputer sebagai servis. Ia adalah salah satu model servis pengkomputeran cloud. Dalam model ini, pembekal membekalkan rangkaian, pelayan, storan dan servis servis lain. Pengguna pula menggunakan alatan dan sebagainya yang dibekalkan pembekal untuk membina software. | |
46 | - | |
47 | -1. **Presentation Layer** : Salah satu layer dalam N-Layered Architecture. Menempatkan antaramuka pengguna (UI). | |
48 | - | |
49 | -1. **Representational State Transfer (REST)** : Adalah gaya seni bina perisian untuk sistem seperti World Wide Web. Semua permintaan kepada penghubung mesti mengandungi maklumat yang diperlukan seperti method dan data yang diperlukan. Berlawanan dengan cara laman web yang biasa menggunakan cookies dan session untuk menyelenggara data diantara sesi. | |
50 | - | |
51 | -1. **Sequence Diagram** : Rajah yang menunjukkan aliran perjalanan sistem | |
52 | - | |
53 | -1. **Service Layer** : Salah satu layer dalam N-Layered Architecture. | |
54 | - | |
55 | -1. **Service Oriented Architecture (SOA)** : ? | |
56 | - | |
57 | -1. **Simple Object Access Protocol (SOAP)** : ? | |
58 | - | |
59 | -1. **Software as a Service (SaaS)** : Software sebagai servis. Satu model penghantaran software di mana software dan data berkaitan dihos pada cloud. SaaS biasanya diakses pengguna menggunakan thin client seperti web browser. Ia telah menjadi satu model penghantaran software yang biasa bagi banyak aplikasi perniagaan seperti akaun, kolaborasi, pengurusan hubungan pengguna (CRM), sistem pengurusan informasi (MIS), perancangan sumber enterprise (ERP), invoice, pengurusan sumber pengguna (HRM), pengurusan kandungan (CM), dan pengurusan helpdesk. Salah satu modal untuk menjual bagi syarikat syarikat ini ialah potensi untuk mengurangkan kos sokongan IT dengan melepaskan sokongan hardware, penyelenggaraan software, dan sokongan kepada pembekal SaaS. | |
60 | - | |
61 | -1. **Subject Matter Expert** : Rujuk _Domain Expert_. | |
62 | - | |
63 | -1. **Unified Modeling Language (UML)** : UML menyediakan tatabahasa (seperti Use Case, Actor, dan sebagainya) yang dapat digunakan untuk memodelkan sistem berdasarkan Object-Oriented Design. Ia menetapkan rajah yang boleh digunakan untuk menggambarkan sistem seperti Use Case Diagram, Class Diagram, Sequence Diagram, Activity Diagram, dan lain-lain. | |
64 | - | |
65 | -1. **Unit Test** : Kod yang ditulis untuk menguji satu "unit" kecil dalam sistem. Unit ini biasanya merujuk kepada satu business class. Unit test ini biasanya tidak termasuk dalam sistem sebenarnya. | |
66 | - | |
67 | -1. **Use Case** : Satu scenario antara pengguna dan sistem. Contohnya dalam sistem kedai online, ada use case administrator memasukkan produk, use case pelanggan melayari produk, use case pelanggan membuat pembelian, dan sebagainya. | |
68 | - | |
69 | -1. **User Story** : Satu ayat pendek yang menerangkan interaksi dalam sistem. Ia menunjukkan siapa, apa, dan mengapa sesuatu berlaku/dilakukan. Contohnya, "Sebagai pelanggan, saya ingin melihat produk yang dijual, supaya saya boleh membuat pilihan". | |
70 | - | |
71 | -1. **Version Control System (VCS)** : Sistem untuk menyimpan fail-fail aturcara. Ia membenarkan perubahan demi perubahan (versi) disimpan dan pengguna boleh mengambil mana-mana versi yang terdahulu untuk digunakan. Jika digunakan dalam team, ia memudahkan perkongsian kod dan mengelakkan pertembungan perubahan (_conflict_) antara berbilang pengguna melalui proses _merge_. Antara VCS yang popular ialah CVS (nama product, Concurrent Versioning System), Subversion, Mercurial, Git, dan Bazaar. | |
72 | - | |
73 | -1. **Web Service** : Satu method standard untuk komputer di internet untuk memberi akses program atau fungsi yang boleh dicapai dan digunakan dari komputer lain | |
74 | - | |
75 | -1. **Z-Index** : ? | |
76 | - | |
77 | ---- | |
78 | - | |
79 | -Untuk menyumbang, sila isikan perkataan/frasa di kiri dan maksudnya di sebelah kanan. Jargon boleh jadi dalam Bahasa Melayu atau Inggeris, tapi penerangannya mesti dibuat dalam Bahasa Melayu. Susun jargon mengikut abjad. |
_posts/2013-03-22-memahami-dependency-injection.md | ||
---|---|---|
@@ -1,340 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: Memahami Dependency Injection | |
4 | -date: 2013-03-22 | |
5 | -author: ikhwanhayat | |
6 | -permalink: /memahami-dependency-injection.html | |
7 | -include_toc: true | |
8 | -level: 2 | |
9 | ---- | |
10 | - | |
11 | -__Dependency Injection__ adalah suatu teknik rekabentuk perisian untuk menjadikannya lebih _modular_ dan _flexible_. Ia kadangkala juga disebut sebagai __Dependency Inversion__ atau __Inversion of Control (IoC)__. Maksud sebenar setiap satu frasa sedikit berbeza, namun untuk permulaan bolehlah dianggap semuanya membawa maksud yang hampir serupa. | |
12 | - | |
13 | -<!--more--> | |
14 | - | |
15 | -## Apa Itu Dependency | |
16 | - | |
17 | -Untuk memahami apa itu _Dependency Injection_ (DI), kita perlu terlebih dahulu mengetahui apa yang dimaksudkan dengan _dependency_. | |
18 | - | |
19 | -Dalam suatu sistem yang besar, perkara pertama yang perlu dilakukan ialah pecahkan ia kepada bahagian-bahagian yang lebih kecil supaya mudah untuk kita selesaikan dan yang lebih penting mudah untuk kita senggara (_mantainable_). | |
20 | - | |
21 | -Katakan kita ingin membina suatu sistem _online_ yang akan memaparkan cuaca bagi suatu tempat. Keperluan yang telah ditetapkan ialah sistem mesti mampu memberitahu pengguna cuaca di bandar mereka melalui alamat IP yang dikesan. | |
22 | - | |
23 | -Jadi kita akan buatkan suatu _class_ `WeatherService` untuk tujuan ini. Katakan kita sudah mempunyai pangkalan data yang akan memberikan kita nama bandar berdasarkan IP. Ada pangkalan data lain pula yang diberikan pada kita oleh Jabatan Meteorologi yang menyenaraikan ramalan cuaca untuk satu-satu bandar. | |
24 | - | |
25 | -Untuk memudahkan pemahaman, kita buatkan dulu ia sebagai applikasi konsol. Kita akan gunakan bahasa C# untuk contoh ini. | |
26 | - | |
27 | -```csharp | |
28 | -public class WeatherService | |
29 | -{ | |
30 | - public void ShowForIp(string ip) | |
31 | - { | |
32 | - Console.WriteLine("Your IP is " + ip); | |
33 | - | |
34 | - // Hubungi pangkalan data geolocation | |
35 | - // Dan larikan query untuk dapatkan bandar berdasarkan IP | |
36 | - | |
37 | - var connGeo = new SqlConnection("server1..."); | |
38 | - connGeo.Open(); | |
39 | - var sqlCity = new SqlCommand("select top 1 city from IpCity where ip='" + ip + "'", connGeo); | |
40 | - | |
41 | - var city = (string)sqlCity.ExecuteScalar(); | |
42 | - Console.WriteLine("City: " + city); | |
43 | - | |
44 | - connGeo.Close(); | |
45 | - | |
46 | - // Hubungi pula pangakalan data untuk cuaca | |
47 | - // Dan dapatkan cuaca terkini untuk bandar | |
48 | - | |
49 | - var connWeather = new SqlConnection("server2..."); | |
50 | - connWeather.Open(); | |
51 | - var sqlWeather = new SqlCommand("select top 1 weather from CityWeather where city='" + city + "' and day=" + DateTime.Now.DayOfYear, connWeather); | |
52 | - | |
53 | - var weather = (string)sqlWeather.ExecuteScalar(); | |
54 | - Console.WriteLine("Weather: " + weather); | |
55 | - | |
56 | - connWeather.Close(); | |
57 | - } | |
58 | -} | |
59 | - | |
60 | -// Panggil dari applikasi utama | |
61 | - | |
62 | -var svc = new WeatherService(); | |
63 | -svc.ShowForIp("10.10.10.10"); | |
64 | - | |
65 | -// Contoh output | |
66 | -Your IP is 10.10.10.10 | |
67 | -City: Kuala Lumpur | |
68 | -Weather: Heavy Rain | |
69 | -``` | |
70 | - | |
71 | -Kita dapati _class_ ini perlu melakukan beberapa perkara iaitu pertama ia menerima input, kemudian ia mencari bandar pengguna, lalu mencari cuaca, dan akhirnya memaparkannya. | |
72 | - | |
73 | -Bila dilihat kembali, terlalu banyak kerja yang perlu dilakukan oleh _class_ ini. _Class_ yang baik ialah ianya fokus pada kerjanya sahaja. Bila kita kecilkan skop tugas suatu _class_, kita dapat menjadikan ia lebih "cohesive", tugasnya lebih fokus. | |
74 | - | |
75 | -Tugas asasi _class_ ini ialah menerima IP dan memaparkan cuaca bagi IP tersebut. Namun ia tidak dapat berfungsi jika ia tidak dapat mencari bandar untuk IP itu dan seterusnya mencari cuaca untuk bandar tersebut. Apa kata jika kita buatkan _class_ lain untuk melakukan dua tugas tersebut untuknya. _Class_ `WeatherService` pula nanti hanya perlu gunakan _class_ baru yang kita akan buat ini supaya objektifnya dapat dicapai. | |
76 | - | |
77 | -```csharp | |
78 | -public class CityFinder | |
79 | -{ | |
80 | - public string FindFromIp(string ip) | |
81 | - { | |
82 | - // Hubungi pangkalan data geolocation | |
83 | - // Dan larikan query untuk dapatkan bandar berdasarkan IP | |
84 | - | |
85 | - var connGeo = new SqlConnection("server1..."); | |
86 | - connGeo.Open(); | |
87 | - var sqlCity = new SqlCommand("select top 1 city from IpCity where ip='" + ip + "'", connGeo); | |
88 | - | |
89 | - var city = (string)sqlCity.ExecuteScalar(); | |
90 | - | |
91 | - connGeo.Close(); | |
92 | - | |
93 | - return city; | |
94 | - } | |
95 | -} | |
96 | - | |
97 | -public class WeatherFinder | |
98 | -{ | |
99 | - public string FindForCity(string city) | |
100 | - { | |
101 | - // Hubungi pangakalan data untuk cuaca | |
102 | - // Dan dapatkan cuaca terkini untuk bandar | |
103 | - | |
104 | - var connWeather = new SqlConnection("server2..."); | |
105 | - connWeather.Open(); | |
106 | - var sqlWeather = new SqlCommand("select top 1 weather from CityWeather where city='" + city + "' and day=" + DateTime.Now.DayOfYear, connWeather); | |
107 | - | |
108 | - var weather = (string)sqlWeather.ExecuteScalar(); | |
109 | - | |
110 | - connWeather.Close(); | |
111 | - | |
112 | - return weather; | |
113 | - } | |
114 | -} | |
115 | - | |
116 | - | |
117 | -public class WeatherService | |
118 | -{ | |
119 | - public void ShowForIp(string ip) | |
120 | - { | |
121 | - Console.WriteLine("Your IP is " + ip); | |
122 | - | |
123 | - var city = new CityFinder().FindFromIp(ip); | |
124 | - Console.WriteLine("City: " + city); | |
125 | - | |
126 | - var weather = new WeatherFinder().FindForCity(city); | |
127 | - Console.WriteLine("Weather: " + weather); | |
128 | - } | |
129 | -} | |
130 | - | |
131 | -// Panggil dari applikasi utama | |
132 | - | |
133 | -var svc = new WeatherService(); | |
134 | -svc.ShowForIp("10.10.10.10"); | |
135 | - | |
136 | -``` | |
137 | - | |
138 | -Cuba lihat, _class_ `WeatherService` nampak lebih bersih bukan? Kurang berserabut apabila tugasnya telah dipecahkan kepada _class_ lain. Baik, pada tahap ini anda dapat lihat bagaimana satu _class_ besar dipecahkan kepada _class_ lebih kecil. Aturcara yang baru ini boleh dikatakan lebih _modular_ dari sebelumnya. | |
139 | - | |
140 | - | |
141 | -Namun, _class_ `WeatherService` ini **bergantung kepada** _class_ `CityFinder` dan `WeatherFinder` untuk berfungsi. Untuk mencapai _modularity_, kita menghadapi satu masalah lain pula iaitu _dependency_ (kebergantungan). Adanya _dependency_ membuatkan perubahan sukar dilakukan, kerana perubahan pada satu tempat akan mempengaruhi tempat lain. Namun jika tiada _dependency_ langsung maka _class_ `WeatherService` ini langsung tidak dapat berfungsi! | |
142 | - | |
143 | -## Mengurus Dependency | |
144 | - | |
145 | -Kita perlukan cara untuk menguruskan _dependency_ ini. Salah satu caranya ialah menggunakan teknik _Dependency Injection_. | |
146 | - | |
147 | -Dalam _class_ `WeatherService` ini, _dependency_ pada CityFinder dan WeatherFinder adalah kuat kerana ia perlu _instantiate_ _class-class_ ini sendiri sebelum menggunakannya. Jika kita ingin mengubahnya pada masa akan datang, kita perlu korek semula _class_ `WeatherService` ini dan lakukan perubahan di dalamnya. | |
148 | - | |
149 | -Lebih baik jika tugas untuk _instantiate_ _class-class_ ini dilakukan oleh "orang lain". "Orang lain" ini kemudiannya akan memberikan _instance_ _class-class_ yang diperlukan kepada `WeatherService` untuk digunakan. Mari kita lihat apa yang saya maksudkan. | |
150 | - | |
151 | -```csharp | |
152 | - | |
153 | -// Anggapkan tiada perubahan pada class CityFinder dan WeatherFinder | |
154 | - | |
155 | -public class WeatherService | |
156 | -{ | |
157 | - private CityFinder cityFinder; | |
158 | - private WeatherFinder weatherFinder; | |
159 | - | |
160 | - public WeatherService(CityFinder cityFinder, WeatherFinder weatherFinder) | |
161 | - { | |
162 | - this.cityFinder = cityFinder; | |
163 | - this.weatherFinder = weatherFinder; | |
164 | - } | |
165 | - | |
166 | - public void ShowForIp(string ip) | |
167 | - { | |
168 | - Console.WriteLine("Your IP is " + ip); | |
169 | - | |
170 | - var city = cityFinder.FindFromIp(ip); | |
171 | - Console.WriteLine("City: " + city); | |
172 | - | |
173 | - var weather = weatherFinder.FindForCity(city); | |
174 | - Console.WriteLine("Weather: " + weather); | |
175 | - } | |
176 | -} | |
177 | - | |
178 | -// Panggil dari applikasi utama | |
179 | - | |
180 | -var cityFinder = new CityFinder(); | |
181 | -var weatherFinder = new WeatherFinder(); | |
182 | - | |
183 | -var svc = new WeatherService(cityFinder, weatherFinder); | |
184 | -svc.ShowForIp("10.10.10.10"); | |
185 | - | |
186 | -``` | |
187 | - | |
188 | -Kita dapat lihat, applikasi utama yang perlu _instantiate_ _class_ `CityFinder` dan `WeatherFinder`, dan kemudiannya _inject_ mereka ke dalam `WeatherService`. Nah, inilah yang dinamakan __Dependency Inversion__ (mengalihkan tugas mengurus _dependency_ ke tempat lain) atau __Dependency Injection__ (memasukkan _dependency_ ke dalam _class_ yang memerlukannya). | |
189 | - | |
190 | -Tugas mengawal _dependency_ biasanya diserahkan kepada kod yang berada lebih atas dalam hierarki panggilan kerana ia lebih mudah dikonfigurasikan. | |
191 | - | |
192 | - | |
193 | -## Lebih Panjang dan Sukar? | |
194 | - | |
195 | -Nampaknya ia hanya memanjangkan kod aturcara kita sahaja? Apa bagusnya begini? Untuk mendemonstrasikan kelebihannya, mari kita wujudkan satu situasi perubahan yang biasa berlaku dalam sistem perisian. | |
196 | - | |
197 | -Katakan pada suatu hari, Jabatan Meteorologi telah meningkat taraf perkhidmatan IT mereka. Cuaca sekarang boleh diperolehi menggunakan web service yang telah mereka sediakan. Lebih tepat dan terkini. Kita ingin mengubahkan sistem kita supaya dapat menggunakan web service ini dan tidak perlu bersusah-payah mengambil data dari mereka setiap minggu :) | |
198 | - | |
199 | -```csharp | |
200 | - | |
201 | -// | |
202 | -// Dalam C#, cara yang saya tunjukkan ini menggunakan interface. Dalam bahasa lain mungkin ia tidak diperlukan. | |
203 | -// | |
204 | -public interface IWeatherFinder | |
205 | -{ | |
206 | - string FindForCity(string city); | |
207 | -} | |
208 | - | |
209 | -// | |
210 | -// Ubah sedikit untuk class WeatherFinder asal supaya ia masih dapat digunakan | |
211 | -// | |
212 | -public class WeatherFinderFromDb : IWeatherFinder | |
213 | -{ | |
214 | - public string FindForCity(string city) | |
215 | - { | |
216 | - // ... kod sama | |
217 | - } | |
218 | -} | |
219 | - | |
220 | -// | |
221 | -// Class yang baru untuk mencari menggunakan web service | |
222 | -// | |
223 | -public class WeatherWebService : IWeatherFinder | |
224 | -{ | |
225 | - public string FindForCity(string city) | |
226 | - { | |
227 | - // Hubungi web service | |
228 | - // Dapatkan cuaca untuk bandar yang diberi | |
229 | - // Anggaplah kod selengkapnya ada di sini :) | |
230 | - | |
231 | - return weather; | |
232 | - } | |
233 | -} | |
234 | - | |
235 | -public class WeatherService | |
236 | -{ | |
237 | - private CityFinder cityFinder; | |
238 | - | |
239 | - private IWeatherFinder weatherFinder; // gunakan interface, bukan concrete class lagi | |
240 | - | |
241 | - public WeatherService(CityFinder cityFinder, IWeatherFinder weatherFinder) | |
242 | - { | |
243 | - this.cityFinder = cityFinder; | |
244 | - this.weatherFinder = weatherFinder; | |
245 | - } | |
246 | - | |
247 | - public void ShowForIp(string ip) | |
248 | - { | |
249 | - Console.WriteLine("Your IP is " + ip); | |
250 | - | |
251 | - var city = cityFinder.FindFromIp(ip); | |
252 | - Console.WriteLine("City: " + city); | |
253 | - | |
254 | - var weather = weatherFinder.FindForCity(city); | |
255 | - Console.WriteLine("Weather: " + weather); | |
256 | - } | |
257 | -} | |
258 | - | |
259 | -// Panggil dari applikasi utama | |
260 | - | |
261 | -var cityFinder = new CityFinder(); | |
262 | -var weatherFinder = new WeatherWebService(); // gunakan class yang baru | |
263 | - | |
264 | -var svc = new WeatherService(cityFinder, weatherFinder); | |
265 | -svc.ShowForIp("10.10.10.10"); | |
266 | - | |
267 | -``` | |
268 | - | |
269 | -Kita dapat lihat bahawa hanya perubahan yang sedikit perlu dilakukan pada `WeatherService`. Malah jika anda menggunakan interface dari awal (satu lagi prinsip yang baik untuk digunakan), maka perubahan langsung tidak dilakukan dalam _class_ `WeatherService` tersebut. | |
270 | - | |
271 | -Melalui teknik ini juga, pengujian dapat dilakukan dengan lebih mudah. Katakan kita buatkan satu _unit test_ untuk `WeatherService` ini. Kita tidak mahu web service itu dipanggil setiap kali, kerana ia pastilah lambat. Kita anggapkan sahaja web service ini sudah terbukti berfungsi kerana kita telah lakukan satu lagi _unit test_ untuknya ditempat lain. | |
272 | - | |
273 | -Maka kita buatkan satu `WeatherFinderStub` yang memulangkan cuaca yang sudah kita tentukan. _Stub_ ini kemudiannya kita gunakan untuk menguji `WeatherService`. | |
274 | - | |
275 | -```csharp | |
276 | - | |
277 | -public class WeatherFinderStub : IWeatherFinder | |
278 | -{ | |
279 | - public string FindForCity(string city) | |
280 | - { | |
281 | - return "Cloudy"; | |
282 | - } | |
283 | - | |
284 | -} | |
285 | - | |
286 | -// Dalam unit test | |
287 | - | |
288 | -void TestWeatherServiceCanReturnWeatherForIp() | |
289 | -{ | |
290 | - var svc = new WeatherService(new CityFinder(), new WeatherFinderStub()); // gunakan stub | |
291 | - | |
292 | - // Lakukan asserts | |
293 | -} | |
294 | - | |
295 | -``` | |
296 | - | |
297 | - | |
298 | -## Dependency Injection Container | |
299 | - | |
300 | -_Depedency_ mungkin boleh jadi kompleks contohnya jika `WeatherFinder` itu sendiri perlu bergantung pada _value_ atau _object_ lain. Namun _dependency chain_ seperti ini sebenarnya adalah perkara biasa dalam sistem perisian. Agak sukar sebenarnya jika kita perlu susun sendiri semua _dependency_ ini setiap kali ingin menggunakan _class_ kita. | |
301 | - | |
302 | -Katakan _class_ `CityFinder` telah kita ubah supaya _constructor_nya menerima suatu `ConnectionPool` yang menguruskan hubungan ke pangkalan data. Jadi `CityFinder` tidak perlu tahu server mana yang perlu dihubungi. `WeatherWebService` pula menerima URL untuk webservice itu supaya kita mudah melakukan konfigurasi. Ini bermakna _dependency_ kepada hubungan pangkalan data atau URL ditelah dilonggarkan dari _class_ yang asal. | |
303 | - | |
304 | -Situasi seperti ini dapat dipermudahkan dengan menggunakan _framework-framework_ _DI Container_ atau kadangkala disebut _IoC Container_. _DI Container_ biasanya ada fungsi automatic injection untuk menguruskan _dependency_ secara automatik. Contoh _framework_ seperti ini yang ada di dalam dunia .NET adalah seperti Castle Windsor, Autofac, Ninject, dan sebagainya. | |
305 | - | |
306 | -_Container_ ini biasanya berfungsi seperti berikut: | |
307 | - | |
308 | -```csharp | |
309 | - | |
310 | -// DiContainer adalah sebuah framework khayalan | |
311 | - | |
312 | -var container = new DiContainer(); | |
313 | - | |
314 | -container.Register<IConnectionPool>().Using<ConnectionPool>() | |
315 | - .WithParamater("connString", "server1..."); | |
316 | - | |
317 | -container.Register<ICityFinder>().Using<CityFinder>(); | |
318 | - | |
319 | -container.Register<IWeatherFinder>().Using<WeatherWebService>() | |
320 | - .WithParameter("url", "http://webservice/..."); | |
321 | - | |
322 | -container.Register<IWeatherService>().Using<WeatherService>(); | |
323 | - | |
324 | -// Panggil dari applikasi utama | |
325 | - | |
326 | -var svc = container.GetObject<IWeatherService>(); // Dapatkan WeatherService dari container | |
327 | -svc.ShowForIp("10.10.10.10"); | |
328 | - | |
329 | -``` | |
330 | - | |
331 | -Container akan mengambil tugas membina `WeatherService` dan menyambungkan semua _dependency_ nya supaya ia dapat hidup dan berfungsi. Kita tidak perlu menguruskannya sendiri. | |
332 | - | |
333 | - | |
334 | -## Kesimpulan | |
335 | - | |
336 | -_Dependency Injection_ tidak akan dapat difahami jika kita tidak memahami apa itu _dependency_ dan bagaimana ia boleh wujud. Setelah memahaminya, _Dependency Injection_ dapat digunakan untuk mengurus _dependency_ dan seterusnya membantu kita mencapai _modularity_ dan _flexibility_ yang diidam-idamkan dalam sistem kita. Gunakan juga _DI Container_ untuk memudahkan tugas kita menghubungkan _dependency_ antara _object_. | |
337 | - | |
338 | -_NOTA: Kod dalam artikel ini adalah khusus untuk memahami Dependency Injection. Ia mungkin mengabaikan aspek lain seperti keselamatan dan sebagainya._ | |
339 | - | |
340 | -Perbincangan mengenai artikel ini ada di [sini](https://plus.google.com/105721265741813048018/posts/Av85xxdHXUx). |
_posts/2014-09-13-memahami-session.md | ||
---|---|---|
@@ -1,86 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: Memahami Session dalam Aplikasi Web | |
4 | -date: 2014-09-13 | |
5 | -author: kamalmustafa | |
6 | -permalink: /memahami-session-dalam-aplikasi-web.html | |
7 | -level: 2 | |
8 | ---- | |
9 | - | |
10 | -_Session_ dalam aplikasi web adalah untuk mengatasi masalah yang berkaitan dengan sifat _stateless_ dalam protokol HTTP. Contohnya apabila kita melayari satu laman web, dan membuka laman utama dan kemudian laman yang kedua, server tidak akan dapat mengenalpasti orang yang mengakses laman kedua adalah orang yang sama mengakses laman pertama tadi. Ini menyebabkan masalah apabila kita ingin membangunkan aplikasi di mana sebahagian daripada laman kita adalah untuk pengguna tertentu sahaja. | |
11 | - | |
12 | -<!--more--> | |
13 | - | |
14 | -Atau pun aplikasi yang perlu menyimpan data apa yang user lakukan pada laman pertama, dan seterusnya memaparkan di laman yang kedua atau seterusnya. Contohnya sebuah laman _e-commerce_ yang mempunyai fungsi _shopping cart_. Di laman pertama, pengguna akan _add_ barangan yang ingin dibeli ke dalam _cart_. Bila pengguna membuka laman lain di website tersebut, kita mungkin ingin memaparkan kepada pengguna apa yang telah mereka masukkan ke dalam _cart_. | |
15 | - | |
16 | -[Protokol HTTP][1] mempunyai konsep _cookie_, di mana apabila pengguna mengakses laman web kita, kita boleh 'tanam' data yang akan disimpan dalam komputer pengguna. Setiap kali mereka mengakses laman kita, data tersebut akan dihantar sekali. Ini membolehkan kita mengenalpasti pengguna ini telah pun melawat laman kita sebelum ini. Jadi secara teori, kita boleh menggunakan _cookie_ ini untuk menyelesaikan masalah berkaitan _shopping cart_ sebelum ini. Kita boleh simpan barang yang pengguna masukkan ke dalam _cart_ di dalam _cookie_. _Cookie_ bagaimana pun mempunyai beberapa masalah seperti saiz yang terhad (4K) dan juga pengguna boleh mengubah data yang disimpan di dalam _cookie_ sesuka hati mereka. Ada cara untuk mengelakkan data dalam _cookie_ diubah namun ia di luar skop artikel ini. | |
17 | - | |
18 | -Jadi satu teknik baru untuk menyimpan data pengguna digunakan - ia dipanggil _session_. Ia masih menggunakan _cookie_ tetapi tidak menyimpan kesemua data ke dalam cookie. Sebaliknya apa yang disimpan dalam _cookie_ hanyalah rujukan (reference / pointer) kepada data sebenar yang di simpan di bahagian server. Apa yang disimpan dalam _cookie_ hanyalah ID unik yang boleh digunakan untuk _query_ _data store_ di server bagi mendapatkan data sebenar. _data store_ ini boleh jadi berbentuk _file_ (default storage PHP session), row dalam database dan sebagainya. Dalam tulisan ini, saya cuba menunjukkan konsep asas implementasi _session_ menggunakan bahasa pengaturcaraan PHP. | |
19 | - | |
20 | -Berikut adalah kod utama yang akan _implement_ _session_ bagi web aplikasi kita. Kod ini boleh disimpan dalam fail bernama `mysession.php`:- | |
21 | - | |
22 | -```php | |
23 | - | |
24 | -/* This is for learning purpose only - just to show how session in theory being | |
25 | -implemented. For real session usage, use the session provided by your web framework. | |
26 | -*/ | |
27 | - | |
28 | -$HERE = realpath(dirname(__FILE__)); | |
29 | -$SESSION_CLOSED = False; | |
30 | - | |
31 | -function end_session() { | |
32 | - if (!$GLOBALS['SESSION_CLOSED']) { | |
33 | - $session_file = $GLOBALS['HERE'] . '/' . $GLOBALS['_MYSESSID'] . '.session'; | |
34 | - file_put_contents($session_file, serialize($GLOBALS['_MYSESSION'])); | |
35 | - $GLOBALS['SESSION_CLOSED'] = True; | |
36 | - } | |
37 | -} | |
38 | - | |
39 | -function start_session() { | |
40 | - if (array_key_exists('mysessid', $_COOKIE)) { | |
41 | - $mysessid = $_COOKIE['mysessid']; | |
42 | - $session_file = $GLOBALS['HERE'] . '/' . $mysessid . '.session'; | |
43 | - if (file_exists($session_file)) { | |
44 | - $GLOBALS['_MYSESSION'] = unserialize(file_get_contents($session_file)); | |
45 | - } | |
46 | - else { | |
47 | - $GLOBALS['_MYSESSION'] = array(); | |
48 | - } | |
49 | - } | |
50 | - else { | |
51 | - $mysessid = uniqid('MYSESSID'); | |
52 | - setcookie('mysessid', $mysessid); | |
53 | - $GLOBALS['_MYSESSION'] = array(); | |
54 | - } | |
55 | - $GLOBALS['_MYSESSID'] = $mysessid; | |
56 | - register_shutdown_function('end_session'); | |
57 | -} | |
58 | -``` | |
59 | - | |
60 | -Dan bagi setiap _page_ yang ingin menggunakan fungsi _session_ ini, contohnya `index.php`:- | |
61 | - | |
62 | -```php | |
63 | - | |
64 | - | |
65 | -include 'mysession.php'; | |
66 | - | |
67 | -start_session(); | |
68 | -print_r($_MYSESSION); | |
69 | -$_MYSESSION['name'] = 'kamal'; | |
70 | -``` | |
71 | - | |
72 | -Page yang kedua, `index2.php`:- | |
73 | - | |
74 | -```php | |
75 | - | |
76 | - | |
77 | -include 'mysession.php'; | |
78 | - | |
79 | -start_session(); | |
80 | -print_r($_MYSESSION); | |
81 | -$_MYSESSION['on_index2'] = True; | |
82 | -``` | |
83 | - | |
84 | -Dalam contoh di atas, apabila pengguna melawat `index2.php`, data dalam `$_MYSESSION['name']` yang disetkan pada laman pertama akan dipaparkan. Dalam function `start_session()`, apa yang berlaku adalah kita check jika pengguna mempunyai nilai cookie `mysessid`, jika ada kita akan cuba load data yang disimpan dalam _file_ `$mysessid.session` ke dalam _variable_ global `$_MYSESSION`. Manakala setiap kali _script_ tersebut berakhir, kita akan simpan balik data dalam variable `$_MYSESSION` ke dalam _file_ `$mysessid.session`. Ini adalah konsep asas bagaimana _session_ berfungsi. Di sini kita menyimpan data di dalam _file_ namun boleh saja data tersebut disimpan di dalam database table dengan `mysessid` berfungsi sebagai _primary key_ bagi rekod tersebut. | |
85 | - | |
86 | -[1]:http://tools.ietf.org/html/rfc2616 |
_posts/2014-09-15-belajar-javascript-part-1.md | ||
---|---|---|
@@ -1,149 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: 'Belajar Javascript: Bhg 1' | |
4 | -date: 2014-09-15 | |
5 | -author: kamalmustafa | |
6 | -permalink: /belajar-javascript-bhg-1.html | |
7 | -level: 1 | |
8 | ---- | |
9 | - | |
10 | -Memetik kata-kata [Douglas Crockford][1], JavaScript adalah bahasa | |
11 | -pengaturcaraan yang sering disalahfahami walaupun ianya merupakan bahasa | |
12 | -pengaturcaraan yang paling popular sekali dengan penggunaan yang paling meluas. | |
13 | - | |
14 | -<!--more--> | |
15 | - | |
16 | -JavaScript, sebelum penggunaannya yang begitu meluas seperti sekarang biasanya | |
17 | -menjadi bahasa kelas kedua bagi kebanyakkan programmer. Saya katakan kelas | |
18 | -kedua kerana ia jarang dipelajari secara formal sepertimana bahasa lain seperti | |
19 | -PHP, Python, Ruby, Perl, Java, C dan sebagainya. Maksud 'formal' disini ialah | |
20 | -kita mengambil masa untuk berkenalan dengan bahasa tersebut bermula daripada | |
21 | -ciri-ciri asas seperti *data type*, *control structure* dan sebagainya. | |
22 | - | |
23 | -Seringkali apabila terpaksa menggunakan JavaScript, kita akan mendapatkan | |
24 | -library ataupun *code snippet* di Internet, ubah beberapa baris dan sekiranya | |
25 | -ia melakukan apa yang kita kehendaki, selesai ! Akhirnya JavaScript sering | |
26 | -menjadi cercaan apabila beberapa masalahnya yang tidak dijangka kita temui | |
27 | -dalam aplikasi yang kita bangunkan. | |
28 | - | |
29 | -Saya bercadang untuk mula mempelajari JavaScript secara lebih tersusun dan | |
30 | -berharap dapat berkongsi pengalaman tersebut melalui beberapa siri tulisan | |
31 | -dalam blog ini. Untuk proses pembelajaran ini, saya akan cuba membina sebuah | |
32 | -aplikasi JavaScript ringkas dan akan cuba meneroka ciri-ciri asas JavaScript. | |
33 | - | |
34 | -Ini bagi saya lebih menarik dan tidak menjemukan berbanding mencuba satu demi | |
35 | -satu contoh kod bagi setiap *features* yang ada. Sebaliknya kita akan | |
36 | -mengenalpasti masalah yang perlu diselesaikan dan cuba cari *features* | |
37 | -JavaScript yang boleh digunakan untuk menyelesaikan masalah tersebut. | |
38 | - | |
39 | -Aplikasi yang saya ingin bangunkan adalah fungsi *autocomplete* ringkas. Kita | |
40 | -selalu temui *features* ini dalam banyak laman web, terutamanya yang melibatkan | |
41 | -fungsi carian. Saya juga banyak menggunakan *autocomplete* dalam aplikasi yang | |
42 | -saya bangunkan. Namun sehingga ke hari ini saya tidak pernah mengambil tahu | |
43 | -bagaimana sebenarya fungsi autocomplete ini berfungsi dalam JavaScript. | |
44 | - | |
45 | -Kita mulakan aplikasi ini dengan kod html ringkas seperti berikut:- | |
46 | - | |
47 | -```html | |
48 | -<html> | |
49 | -<head> | |
50 | -<script src="app.js"></script> | |
51 | -</head> | |
52 | -<body> | |
53 | -<input type="text" name="keyword" id="keyword" value="" size="20" /> | |
54 | -</body> | |
55 | -</html> | |
56 | -``` | |
57 | - | |
58 | -`app.js` pula akan kelihatan seperti di bawah:- | |
59 | - | |
60 | -```js | |
61 | -(function() { | |
62 | - var keyword = document.getElementById('keyword'); | |
63 | - alert (keyword); | |
64 | -}()); | |
65 | -``` | |
66 | - | |
67 | -Daripada kod seringkas ini pun sebenarnya banyak yang dapat dipelajari | |
68 | -berkaitan JavaScript. Pertama sekali adalah cara kod itu sendiri ditulis. Ia | |
69 | -mungkin sedikit pelik bagi yang telah biasa menulis kod aturcara dalam bahasa | |
70 | -pengaturcaraan lain seperti PHP, Python, Perl, Java atau C. Sebenarnya kod | |
71 | -JavaScript digalakkan ditulis dalam bentuk sedemikian rupa untuk mengelakkan | |
72 | -*variable-variable* yang digunakan daripada bocor (*leaked*) ke dalam skop | |
73 | -global program. Ini antara satu kekurangan JavaScript dimana semua unit | |
74 | -aturcara hanya boleh wujud dalam satu skop iaitu global. Tidak wujud *module* | |
75 | -atau *namespace* dalam JavaScript. Bagaimanapun kita agak bernasib baik kerana | |
76 | -*function* dalam JavaScript adalah agak fleksibel jadi kita boleh | |
77 | -menggunakannya untuk mengehadkan skop variable yang kita gunakan. | |
78 | - | |
79 | -Walaupun *function* dalam JavaScript boleh digunakan untuk mengehadkan skop, | |
80 | -masih terdapat satu lagi keburukan JavaScript yang mesti diambil perhatian oleh | |
81 | -semua programmer iaitu kesemua variable yang digunakan dalam *function* mesti | |
82 | -diisytiharkan menggunakan *keyword* `var` sepertimana yang kita lihat dalam | |
83 | -contoh kod di atas. Jika tidak, ia akan turut wujud dalam skop global walaupun | |
84 | -hanya digunakan dalam *function* ! Sebagai contoh, perhatikan kod di bawah:- | |
85 | - | |
86 | -```js | |
87 | -function add(num1, num2) { | |
88 | - _tmp1 = parseInt(num1); | |
89 | - _tmp2 = parseInt(num2); | |
90 | - | |
91 | - return _tmp1 + _tmp2; | |
92 | -} | |
93 | - | |
94 | -total = add(1, 2); | |
95 | -console.log(_tmp1); | |
96 | -``` | |
97 | - | |
98 | -Dalam kod di atas, `tmp1` dan `_tmp2` hanyalah *variable* sementara dan | |
99 | -sepatutnya wujud dalam function `add` sahaja. Namun anda akan dapati | |
100 | -`console.log` tetap memaparkan nilai 2 iaitu nilai `_tmp2` di dalam function | |
101 | -`add` ! Ini tidak sepatutnya berlaku kerana dalam satu aturcara yang besar, ia | |
102 | -akan menyebabkan bug yang sukar dijejaki di mana puncanya kerana variable | |
103 | -`_tmp1` kini boleh dicapai oleh mana-mana bahagian aturcara sekalipun. Untuk | |
104 | -membetulkan keadaan di atas, *keyword* `var` mesti sentiasa digunakan untuk | |
105 | -mengisytiharkan *variable* dalam *function*. Contoh:- | |
106 | - | |
107 | -```js | |
108 | -function add(num1, num2) { | |
109 | - var _tmp1 = parseInt(num1); | |
110 | - var _tmp2 = parseInt(num2); | |
111 | - | |
112 | - return _tmp1 + _tmp2; | |
113 | -} | |
114 | -``` | |
115 | - | |
116 | -Seterusnya mengapa contoh kod sebelum ini ditulis dalam bentuk function ? Ini | |
117 | -juga melibatkan isu berkaitan global variable dalam JavaScript. Untuk | |
118 | -meminimumkan bilangan *variable* yang didedahkan kepada skop global, kita | |
119 | -*wrap* kod tersebut dalam function yang terus dipanggil apabila fail tersebut | |
120 | -dibuka oleh *JavaScript engine*. Kod sebelum ini contohnya, tidak mendedahkan | |
121 | -sebarang variable kepada skop global berbanding sekiranya ia ditulis seperti | |
122 | -berikut:- | |
123 | - | |
124 | -```js | |
125 | -function init() { | |
126 | - var keyword = document.getElementById('keyword'); | |
127 | - alert (keyword); | |
128 | -} | |
129 | - | |
130 | -init(); | |
131 | -``` | |
132 | - | |
133 | -Dalam contoh ini kita telah mendedahkan satu nama baru ke dalam skop global | |
134 | -iaitu `init` walaupun `init` mungkin hanya akan digunakan sekali iaitu untuk | |
135 | -*run* kod dalam function tersebut. Jika kita perhatikan library JavaScript yang | |
136 | -besar seperti JQuery, YUI, Backbone dan sebagainya mereka hanya mendedahkan | |
137 | -satu nama ke dalam skop global seperti jQuery/$ utk JQuery dan YUI untuk YUI. *Function-function* lain kesemuanya diakses melalui *top level* namespace | |
138 | -tersebut seperti `$.getJSON`, `YUI.dom` dan sebagainya. Walaupun JavaScript | |
139 | -tidak mempunyai sokongan *namespace* atau *module*, function dan object boleh | |
140 | -digunakan untuk *simulate* namespace. Lagi yang boleh dipelajari daripada contoh | |
141 | -ringkas ini adalah perbezaan antara *function declaration* dan *function expression* tetapi saya tidak bercadang untuk mengulasnya dalam bahagian ini. | |
142 | - | |
143 | -Setakat ini sahaja untuk bahagian pertama. Saya berharap akan dapat terus menulis dan berkongsi bahagian seterusnya, Insya Allah. | |
144 | - | |
145 | -[1]:http://javascript.crockford.com/ | |
146 | -[2]:http://stackoverflow.com/questions/1634268/explain-javascripts-encapsulated-anonymous-function-syntax | |
147 | -[3]:http://stackoverflow.com/questions/9342122/javascript-on-load-execution | |
148 | -[4]:https://plus.google.com/104286962752255423480/posts | |
149 | -[5]:https://plus.google.com/u/0/104286962752255423480/posts/Tb1ffbfzZdM |
_posts/2014-11-04-belajar-javascript-part-2.md | ||
---|---|---|
@@ -1,140 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: 'Belajar Javascript: Bhg 2' | |
4 | -date: 2014-11-04 | |
5 | -author: kamalmustafa | |
6 | -permalink: /belajar-javascript-bhg-2.html | |
7 | -level: 1 | |
8 | ---- | |
9 | - | |
10 | -Sebelum ini kita telah menulis kod JavaScript asas seperti berikut:- | |
11 | - | |
12 | -```js | |
13 | -(function() { | |
14 | - var keyword = document.getElementById('keyword'); | |
15 | - alert keyword; | |
16 | -})(); | |
17 | -``` | |
18 | - | |
19 | -Bagi yang biasa dengan JavaScript pasti menyedari ada masalah dengan kod di | |
20 | -atas. Malah jika anda membuka fail `index.html` melalui browser, anda akan | |
21 | -dapati nilai yang dipaparkan dalam `alert` adalah `null`. Ini sudah pasti bukan | |
22 | -yang kita harapkan kerana nilai yang sepatutnya adalah reference kepada DOM | |
23 | -object HTMLInput. Ini adalah disebabkan kod tersebut terus dijalankan apabila | |
24 | -ia dibaca dalam browser. Bagaimanapun sentiasa ada kemungkinan semasa kod | |
25 | -tersebut dijalankan, DOM element yang kita cuba dapatkan masih belum disediakan | |
26 | -sepenuhnya oleh browser. | |
27 | - | |
28 | -<!--more--> | |
29 | - | |
30 | -Untuk membetulkan masalah di atas, kita perlu attach function tersebut kepada | |
31 | -`load` event sama ada pada object `window` ataupun pada element `body`. Contohnya adalah seperti berikut:- | |
32 | - | |
33 | -```js | |
34 | -window.onload = function() { | |
35 | - var keyword = document.getElementById('keyword'); | |
36 | - alert('using window.onload'); | |
37 | - alert (keyword); | |
38 | -} | |
39 | -``` | |
40 | - | |
41 | -Atau:- | |
42 | - | |
43 | -```js | |
44 | -function init() { | |
45 | - var keyword = document.getElementById('keyword'); | |
46 | - alert('using body.onload'); | |
47 | - alert (keyword); | |
48 | -} | |
49 | -``` | |
50 | - | |
51 | -```html | |
52 | -// dalam fail index.html | |
53 | -<body onload="init()"> | |
54 | -</body> | |
55 | -``` | |
56 | - | |
57 | -Tidak ada DOM object untuk `body` dan saya pada mulanya mencuba seperti | |
58 | -berikut:- | |
59 | - | |
60 | -```js | |
61 | -document.body.onload = function() { | |
62 | - var keyword = document.getElementById('keyword'); | |
63 | - alert('using document.body.onload'); | |
64 | - alert (keyword); | |
65 | -} | |
66 | -``` | |
67 | - | |
68 | -tetapi mendapat error `Uncaught TypeError: Cannot set property 'onload' of | |
69 | -null`. Menggunakan `body onload=init()` bagaimanapun memerlukan untuk kita | |
70 | -declare satu function pada skop global, sesuatu yang kita cuba elakkan seperti | |
71 | -yang telah dibincangkan dalam tulisan yang lalu. Bagi browser moden pada hari | |
72 | -ini, cara yang direkomenkan adalah dengan menggunakan event listener seperti | |
73 | -berikut:- | |
74 | - | |
75 | -```js | |
76 | -(function() { | |
77 | - window.addEventListener('load', function() { | |
78 | - var keyword = document.getElementById('keyword'); | |
79 | - alert (keyword); | |
80 | - }, false); | |
81 | -}()); | |
82 | -``` | |
83 | - | |
84 | -Kelebihan cara di atas adalah struktur kod kita masih kekal sebagaimana asal | |
85 | -dipermulaan siri ini. Bagaimanapun menggunakan `load` event tetap mempunyai | |
86 | -satu masalah iaitu kod tersebut hanya akan dijalankan apabila kesemua elemen | |
87 | -dan juga *resource* seperti imej telah selesai dimuat-turun oleh browser. Kebanyakkan kod JavaScript adalah untuk memanipulasi DOM jadi agak membuang | |
88 | -masa dan juga mungkin menghasilkan kesan yang tidak diingini jika terpaksa | |
89 | -menunggu kesemua *resource* selesai dimuat-turun sebelum kod JavaScript kita | |
90 | -boleh memainkan peranan. Alternatif kepada `load` event adalah | |
91 | -`DOMContentLoaded` dan kod di atas boleh ditulis seperti berikut:- | |
92 | - | |
93 | -```js | |
94 | -(function() { | |
95 | - window.addEventListener('DOMContentLoaded', function() { | |
96 | - var keyword = document.getElementById('keyword'); | |
97 | - alert (keyword); | |
98 | - }, false); | |
99 | -}()); | |
100 | -``` | |
101 | - | |
102 | -Kelebihan `DOMContentLoaded` adalah ia akan terus *execute* kod kita sebaik | |
103 | -sahaja kesemua struktur DOM telah dibina dalam memori. Namun hidup dalam dunia | |
104 | -JavaScript adalah sangat tidak menentu dan sukar diduga. Tidak semua browser | |
105 | -menyokong event `DOMContentLoaded` ini jadi kod kita perlu melakukan beberapa | |
106 | -adaptasi bagi membolehkan ia berfungsi pada semua browser. Atas sebab inilah | |
107 | -library seperti JQuery menyediakan function khas untuk mengatasi masalah ini. Menggunakan JQuery, kod di atas boleh ditulis seperti berikut:- | |
108 | - | |
109 | -```js | |
110 | -(function() { | |
111 | - $(document).ready(function() { | |
112 | - var keyword = document.getElementById('keyword'); | |
113 | - alert (keyword); | |
114 | - }); | |
115 | -}()); | |
116 | -``` | |
117 | - | |
118 | -Untuk membaca dengan lebih lanjut berkaitan isu yang dibincangkan dalam | |
119 | -bahagian ini boleh rujuk perbincangan di laman stackoverflow:- | |
120 | - | |
121 | -1. http://stackoverflow.com/questions/3698200/window-onload-vs-document-ready | |
122 | -1. http://stackoverflow.com/questions/3474037/window-onload-vs-body-onload-vs-document-onready | |
123 | - | |
124 | -## Nota | |
125 | -Saudara [Zulfa Juniadi][zulfa] memberikan komen dalam grup FB [JomWeb] bahawa penggunaan | |
126 | -`$.ready()` adalah tidak perlu sekiranya kod JavaScript kita diletakkan pada pengakhiran dokumen, sebelum tag `</body>`. Ini | |
127 | -kerana apabila kod tersebut dijalankan oleh browser, kesemua kandungan DOM telah pun diproses | |
128 | -oleh browser, menghasilkan kesan yang sama seperti `DOMContentLoaded` yang dibincangkan di atas. | |
129 | -Perbincangan berkaitan di Stackoverflow - http://stackoverflow.com/q/4643990/139870. | |
130 | - | |
131 | -[Cadangan lain] di Stackoverflow adalah untuk load JavaScript pada bahagian `<head>` tapi menggunakan `async` atau `defer` | |
132 | -attribute. Cara ini juga tidak akan *block* browser daripada terus memproses laman HTML kita dan disokong oleh | |
133 | -80% browser moden pada hari ini. | |
134 | - | |
135 | -Sekian untuk kali ini, sehingga berjumpa lagi untuk siri akan datang, Insya | |
136 | -Allah. | |
137 | - | |
138 | -[zulfa]:https://github.com/zulfajuniadi | |
139 | -[JomWeb]:https://www.facebook.com/groups/jomweb/ | |
140 | -[Cadangan lain]:http://stackoverflow.com/questions/436411/where-is-the-best-place-to-put-script-tags-in-html-markup/24070373#24070373 |
_posts/2014-11-09-belajar-javascript-part-3.md | ||
---|---|---|
@@ -1,195 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: 'Belajar Javascript: Bhg 3' | |
4 | -date: 2014-11-09 | |
5 | -author: kamalmustafa | |
6 | -permalink: /belajar-javascript-bhg-3.html | |
7 | -level: 1 | |
8 | ---- | |
9 | - | |
10 | -Alhamdulillah, kita dapat bertemu lagi dalam bahagian ke-3, siri belajar bahasa | |
11 | -pengaturcaraan JavaScript. Untuk bahagian ke-3 ini bagaimanapun saya memohon maaf | |
12 | -terlebih dahulu kerana fokusnya bukan pada JavaScript secara umum tetapi lebih | |
13 | -kepada 'browser DOM programming' kerana saya ingin memulakan apa yang saya rancang | |
14 | -pada bahagian 1 iaitu membina sebuah *autocomplete* ringkas. | |
15 | - | |
16 | -<!--more--> | |
17 | - | |
18 | -Kita mulakan dengan dokumen HTML ringkas seperti di bawah:- | |
19 | - | |
20 | -```html | |
21 | -<html> | |
22 | -<head> | |
23 | -<style> | |
24 | -</style> | |
25 | -</head> | |
26 | -<body> | |
27 | -<input type="text" name="keyword" id="keyword" value="" size="20" /> | |
28 | -<script src="app.js"></script> | |
29 | -</body> | |
30 | -</html> | |
31 | -``` | |
32 | -Manakala `app.js` adalah seperti berikut:- | |
33 | - | |
34 | -```js | |
35 | -(function() { | |
36 | - var keyword_elm = document.getElementById('keyword'); | |
37 | -}()); | |
38 | -``` | |
39 | -<div class="admonition-info"> | |
40 | - Saya akan menggunakan <i>suffix</i> <code>_elm</code> bagi setiap <i>variable</i> dalam tutorial ini | |
41 | - bagi menunjukkan yang ia adalah <i>DOM element</i>. | |
42 | -</div> | |
43 | -<div> </div> | |
44 | - | |
45 | -Sebelum itu mari kita lihat dulu perkara-perkara yang perlu kita lakukan untuk membina | |
46 | -fungsi *auto complete* ini:- | |
47 | - | |
48 | -* Apabila pengguna menaip beberapa karakter di dalam kotak carian, satu *pop-up* akan | |
49 | - dipaparkan di bawah kotak carian tersebut, memaparkan beberapa cadangan yang berkaitan. | |
50 | -* Pengguna boleh klik mana-mana cadangan yang dipaparkan dan ia akan dimasukkan ke dalam | |
51 | - kotak carian. | |
52 | -* Pengguna juga boleh skroll *pop-up* cadangan dan memilih hanya dengan menekan butang | |
53 | - Enter pada *keyboard*. | |
54 | - | |
55 | -Bagi keperluan pertama, kita boleh menggunakan *event* `keyup` pada elemen input kotak | |
56 | -carian. *Event* `keyup` ini akan dijana oleh browser apabila pengguna menekan sesuatu | |
57 | -kekunci pada *keyboard* dan melepaskannya. Jadi kita boleh menulis kod JavaScript seperti | |
58 | -berikut:- | |
59 | - | |
60 | -```js | |
61 | -(function() { | |
62 | - var keyword_elm = document.getElementById('keyword'); | |
63 | - keyword_elm.addEventListener('keyup', function(evt) { | |
64 | - var keyword = evt.target.value; | |
65 | - console.log(keyword); | |
66 | - }); | |
67 | -}()); | |
68 | -``` | |
69 | - | |
70 | -<div class="admonition-warning"> | |
71 | - Method <code>.addEventListener()</code> tidak disokong oleh IE7 dan IE6. Kebanyakkan contoh dalam | |
72 | - tutorial ini menganggap anda menggunakan browser moden yang terkini. | |
73 | -</div> | |
74 | -<div> </div> | |
75 | - | |
76 | -Setiap *event handler function* akan di*pass* satu *argument* berbentuk *event object* | |
77 | -yang mengandungi maklumat terperinci berkaitan *event* yang dijana oleh browser. | |
78 | -Maklumat lanjut berkaitan *event handler* ini boleh dirujuk kepada laman [Eloquent | |
79 | -JavaScript][eloquent]. Melalui *event object* ini, kita akan dapat merujuk kembali | |
80 | -kepada elemen asal di mana *event* tersebut dijana. Ini membolehkan kita untuk meraih | |
81 | -nilai yang dimasukkan oleh pengguna pada elemen input kotak carian. | |
82 | - | |
83 | -*Event* `keyup` akan dijana oleh browser setiap kali pengguna menaip sesuatu karakter | |
84 | -pada *keyboard* dan ini juga bermakna setiap kali itulah juga kod JavaScript kita | |
85 | -perlu *handle* dan memproses *event* tersebut. Ia agak tidak efisien dan antara cadangan | |
86 | -yang saya jumpa adalah dengan menggunakan function `setTimeout` untuk [mengesan hanya | |
87 | -setelah pengguna berhenti menaip baru kod JavaScript kita bertindak][settimeout]. Saya | |
88 | -bagaimanapun akan mengabaikan isu ini buat seketika. | |
89 | - | |
90 | -Kita teruskan dengan melaksanakan apa yang diperlukan pada syarat pertama fungsi ini | |
91 | -iaitu memaparkan *pop-up* apabila pengguna menaip sesuatu pada kotak carian. Untuk | |
92 | -permulaan ini, saya akan menggunakan cara yang paling naif terlebih dahulu. Kita akan | |
93 | -sama-sama menambah baik menggunakan teknik yang lebih sesuai dan canggih pada siri yang | |
94 | -akan datang, setelah kita semakin menguasai teknik pengaturcaraan `browser DOM` | |
95 | -menggunakan JavaScript ini. | |
96 | - | |
97 | -Cara naif pertama yang saya gunakan adalah dengan meletakkan *hidden div* di bawah | |
98 | -kotak carian untuk dipaparkan sebagai *pop-up*:- | |
99 | - | |
100 | -```html | |
101 | -<html> | |
102 | -<head> | |
103 | -<style> | |
104 | -#keyword-result { | |
105 | - visibility: hidden; | |
106 | - border: 1px solid; | |
107 | - width: 170px; | |
108 | -} | |
109 | -</style> | |
110 | -</head> | |
111 | -<body> | |
112 | -<input type="text" name="keyword" id="keyword" value="" size="20" /> | |
113 | -<div id="keyword-result"> | |
114 | -</div> | |
115 | -<script src="app.js"></script> | |
116 | -</body> | |
117 | -</html> | |
118 | -``` | |
119 | - | |
120 | -Kod JavaScript adalah seperti berikut:- | |
121 | - | |
122 | -```js | |
123 | -(function() { | |
124 | - var keyword_elm = document.getElementById('keyword'); | |
125 | - keyword_elm.addEventListener('keyup', function(evt) { | |
126 | - var keyword = evt.target.value; | |
127 | - var keyword_result_elm = document.getElementById('keyword-result'); | |
128 | - var list_elm = document.createElement('ul'); | |
129 | - if (keyword.length > 2) { | |
130 | - for (var i = 0; i < 5; i++) { | |
131 | - var list_item_elm = document.createElement('li'); | |
132 | - var list_item = document.createTextNode('result ' + i); | |
133 | - list_item_elm.appendChild(list_item); | |
134 | - list_elm.appendChild(list_item_elm); | |
135 | - } | |
136 | - } | |
137 | - keyword_result_elm.appendChild(list_elm); | |
138 | - keyword_result_elm.style.visibility = 'visible'; | |
139 | - }); | |
140 | -}()); | |
141 | -``` | |
142 | - | |
143 | -Dalam kod di atas, apa yang ia lakukan adalah bertindak balas terhadap *event* `keyup` | |
144 | -pada kotak carian dan kemudian secara dinamik membina sebuah *unordered list* (`<ul>`). | |
145 | -List tersebut kemudian dimasukkan ke dalam elemen `div` yang pada asalnya adalah *hidden*. | |
146 | -Elemen `div` tersebut kemudian dipaparkan dengan mengeset *properties* *visibility* kepada | |
147 | -`visible`, memberikan efek seperti element tersebut *pop-up* pada bahagian bawah kotak | |
148 | -carian. | |
149 | - | |
150 | -Setelah dapat memaparkan *pop-up*, kita beralih kepada syarat kedua iaitu membolehkan | |
151 | -setiap elemen dalam *list* yang kita jana sebelum ini boleh di'klik' dan nilainya | |
152 | -dipaparkan pada kotak carian. Ianya boleh dilakukan dengan meng'attach' *event* `click` | |
153 | -pada setiap item dalam list tersebut:- | |
154 | - | |
155 | -```javascript | |
156 | -list_item_elm.addEventListener('click', function(evt) { | |
157 | - keyword_elm.value = evt.target.textContent; | |
158 | - keyword_result_elm.style.display = 'none'; | |
159 | -}); | |
160 | -``` | |
161 | -Di sini kita raih nilai string yang ada pada setiap item dalam list dan setkan sebagai | |
162 | -*value* kepada kotak carian. Seterusnya kita set *properties* *display* pada *pop-up* | |
163 | -kepada `none` untuk memberikan kesan seperti ia hilang. | |
164 | - | |
165 | -Syarat ketiga adalah untuk membolehkan pengguna memilih menggunakan *keyboard* berbanding | |
166 | -mengklik menggunakan *mouse*. Saya masih belum dapat mencari penyelesaian kepada masalah | |
167 | -ini. Cubaan pertama saya adalah dengan *properties* `scroll` pada `div`:- | |
168 | - | |
169 | -```css | |
170 | -#keyword-result { | |
171 | - display:hidden; | |
172 | - border: 1px solid; | |
173 | - width: 170px; | |
174 | - overflow-y: scroll; | |
175 | -} | |
176 | -``` | |
177 | -Ia akan meletakkan *scroll bar* pada `div` tersebut tetapi kita masih belum dapat skroll | |
178 | -seperti fungsi *auto complete* yang biasa kita temui. Ia mungkin sebab *focus* masih | |
179 | -pada kotak carian. Jadi saya cuba set *fokus* pada *pop-up* tersebut tetapi ini akan | |
180 | -menghalang saya daripada terus menaip pada kotak carian kerana kini *focus* adalah pada | |
181 | -*pop-up*. Ini adalah satu masalah yang menarik, saya masih lagi meneliti [script ini][autoComplt] | |
182 | -dan [ini][completely] untuk mengenalpasti bagaimana ia menyelesaikan masalah *scroll* ini. | |
183 | - | |
184 | -Sekiranya anda mempunyai sebarang idea, saya mengalu-alukan idea dan cadangan anda ! Kod penuh untuk | |
185 | -tutorial ini boleh dilihat pada laman [codepen]. | |
186 | - | |
187 | -[eloquent]:http://eloquentjavascript.net/14_event.html | |
188 | -[settimeout]:http://davidwalsh.name/javascript-settimeout | |
189 | -[autoComplt]:https://github.com/Fischer-L/autoComplt | |
190 | -[completely]:http://complete-ly.appspot.com/ | |
191 | -[codepen]:http://codepen.io/k4ml/pen/zxxzJq | |
192 | - | |
193 | -### Rujukan | |
194 | -* http://stackoverflow.com/questions/9707397/making-a-div-vertically-scrollable-using-css | |
195 | -* http://stackoverflow.com/questions/6754275/set-keyboard-focus-to-a-div |
_posts/2015-01-18-github-sebagai-hos-laman-web.md | ||
---|---|---|
@@ -1,36 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: GitHub Sebagai Hos Laman Web | |
4 | -author: ikhwanhayat | |
5 | -level: 2 | |
6 | -summary: Github adalah satu servis di mana anda boleh meletakkan kod sumber perisian anda dan boleh menjemput pengaturcara lain untuk berkolaborasi membangunkan perisian tersebut. Namun disamping itu, GitHub juga menyediakan servis di mana anda boleh meletakkan laman web anda di situ. Perkhidmatan ini dinamakan GitHub Pages dan disediakan secara percuma | |
7 | ---- | |
8 | - | |
9 | -[GitHub](https://github.com) adalah satu servis di mana anda boleh meletakkan kod sumber perisian anda dan boleh menjemput pengaturcara lain untuk berkolaborasi membangunkan perisian tersebut. Namun disamping itu, GitHub juga menyediakan servis di mana anda boleh meletakkan laman web anda di situ. Perkhidmatan ini dinamakan [GitHub Pages](https://pages.github.com) dan disediakan secara percuma! | |
10 | - | |
11 | -<!--more--> | |
12 | - | |
13 | -Artikel ini akan mengandaikan anda sudah biasa dengan GitHub dan [Git](http://git-scm.com), kerana jika ingin menerangkan tentang kedua-duanya maka akan jadi panjang ceritanya nanti (mungkin lain kali :). | |
14 | - | |
15 | -Untuk menggunakan GitHub Pages, anda mestilah membuat satu repositori yang dinamakan "_usernameanda_.github.io". Seterusnya anda perlu masukkan halaman-halaman web anda yang di dalam bentuk fail HTML, imej, dan sebagainya ke dalam repositori tersebut. Kemudian, anda boleh terus melayarinya di "http://usernameanda.github.io". Semudah itu! | |
16 | - | |
17 | -Panduan langkah demi langkah memulakan GitHub Pages boleh anda dapati di [halaman utama GitHub Pages](https://pages.github.com/). Sebenarnya ada dua cara penggunaan GitHub Pages, iaitu sama ada laman web untuk _user/organization_ atau untuk _project_. Dokumentasi penuh anda boleh baca di [laman bantuan GitHub Pages](https://help.github.com/categories/github-pages-basics/). | |
18 | - | |
19 | -Untuk lebih jelas, mari kita ambil satu contoh. Laman web MyDev ini sendiri sebenarnya dihoskan oleh GitHub Pages. Username yang kami gunakan ialah "mydevcommunity" dan profil GitHub kami boleh dilihat di [https://github.com/mydevcommunity](https://github.com/mydevcommunity). Kandungan laman web ini kami letakkan di repositori [mydevcommunity.github.io](https://github.com/mydevcommunity/mydevcommunity.github.io). Ini membolehkan ia dilayari di [http://mydevcommunity.github.io](http://mydevcommunity.github.io). | |
20 | - | |
21 | -Domain "www.mydev.my" sebenarnya dihalakan ke domain "mydevcommunity.github.io". Cara untuk menggunakan domain anda sendiri bersama GitHub Pages ada di [sini](https://help.github.com/articles/about-custom-domains-for-github-pages-sites/). | |
22 | - | |
23 | -Jika anda perhatikan dalam repositori tersebut, kami sebenarnya tidak hoskan terus fail-fail HTML, tetapi kami menggunakan sejenis CMS (_Content Management System_) dinamakan [Jekyll](http://jekyllrb.com). | |
24 | - | |
25 | -GitHub Pages menyokong penggunaan Jekyll di mana pengguna tidak perlu menguruskan fail-fail HTML satu per satu. Kandungan boleh ditulis dalam format [Markdown ](http://daringfireball.net/projects/markdown/) dan kemudian Jekyll akan menjana fail-fail HTML secara automatik berdasarkan _layout_ dan konfigurasi yang kita telah tetapkan sebelum itu. | |
26 | - | |
27 | -Maklumat lanjut integrasi GitHub Pages dan Jekyll boleh dibaca di [sini](https://help.github.com/articles/using-jekyll-with-pages/) | |
28 | - | |
29 | -Antara kelebihan penggunaan GitHub Pages ini adalah: | |
30 | - | |
31 | -1. Ia percuma :) | |
32 | -1. Anda boleh menggunakan _social feature_ dalam GitHub untuk berkolaborasi membangunkan laman web anda, seperti melalui penggunaan _pull request_. | |
33 | -1. Hanya gunakan Git untuk _publish_ laman web anda, tak perlu FTP atau sebagainya. | |
34 | -1. Secara tidak langsung, segala perubahan pada kod sumber laman web anda akan direkodkan. | |
35 | - | |
36 | -Jadi, melalui GitHub Pages, anda boleh membina laman web korporat anda, laman peribadi, laman komuniti, atau pun blog dengan mudah dan murah. |
_posts/2015-01-20-cara-murah-guna-https.md | ||
---|---|---|
@@ -1,36 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: Cara Murah Guna SSL (HTTPS) Untuk Laman Web Anda | |
4 | -author: kamalmustafa | |
5 | -date: 2015-01-20 | |
6 | -level: 2 | |
7 | -summary: > | |
8 | - Penggunaan SSL (HTTPS) adalah penting tapi memerlukan penggunaan dedicated IP | |
9 | - bagi setiap website. Bagaimana SNI membantu menyelesaikan masalah ini ? | |
10 | ---- | |
11 | - | |
12 | -Penggunaan SSL (HTTPS) adalah penting jika laman web anda melibatkan data-data pengguna | |
13 | -seperti username, password, maklumat pembelian, data peribadi seperti nombor kad pengenalan | |
14 | -dan sebagainya. Data-data penting ini begitu mudah untuk dicuri jika pengguna menggunakan | |
15 | -capaian Internet di tempat awam. | |
16 | - | |
17 | -<!--more--> | |
18 | - | |
19 | -Untuk menggunakan HTTPS bagaimana pun memerlukan setiap website mempunyai alamat IP yang | |
20 | -tersendiri. Kebanyakkan laman web pula menggunakan perkhidmatan *shared hosting* sebagai | |
21 | -hos dan ini bermakna mereka berkongsi alamat IP dengan pelbagai laman lain di hos yang sama. | |
22 | - | |
23 | -Jadi untuk menggunakan HTTPS, mereka perlu menyewa alamat IP tambahan, khusus untuk laman web | |
24 | -mereka sahaja. | |
25 | - | |
26 | -*Server Name Indication* (SNI) adalah teknologi yang membolehkan penggunaan *SSL certificate* | |
27 | -pada website tanpa memerlukan *dedicated* IP. Kebanyakkan browser hari ini menyokong SNI. | |
28 | -Untuk peranti mobile android, support bermula dengan Android 3.0 (HoneyComb) manakala untuk | |
29 | -IoS (Iphone) bermula dgn versi 4.0. | |
30 | - | |
31 | -Ini bermakna peranti yang dibeli dalam tempoh 4 tahun lepas sudah pun mempunyai sokongan terhadap SNI. | |
32 | -SNI (Server Name Indication) boleh memangkin penggunaan HTTPS yang lebih meluas. | |
33 | - | |
34 | -Jika anda menggunakan *shared hosting* dan ingin menggunakan HTTPS bagi laman web anda, hubungi penyedia | |
35 | -*shared hosting* anda untuk bertanyakan sama ada mereka sudah mempunyai sokongan untuk SNI atau | |
36 | -tidak. |
_posts/2015-01-23-client-side-vs-server-side.md | ||
---|---|---|
@@ -1,335 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: Client-Side vs Server-Side | |
4 | -author: ikhwanhayat | |
5 | -level: 1 | |
6 | -include_toc: true | |
7 | -summary: > | |
8 | - Perbezaan asas antara client-side dan server-side dalam web development. Bacaan wajib bagi | |
9 | - mereka yang baru bermula dalam bidang ini, ataupun masih keliru dengan perbezaan antara | |
10 | - keduanya. | |
11 | ---- | |
12 | - | |
13 | -Suatu sistem berasaskan web adalah komunikasi antara 2 pihak. Pihak pertama ialah pelayar web iaitu yang kita panggil **_client-side_**. Pihak kedua pula ialah pelayan ataupun **_server-side_**. _Client_ akan memulakan proses komunikasi dengan meminta fail dari _server_, dan _server_ akan memulangkan fail tersebut kepada _client_. _Client_ akan memproses fail tersebut dan memaparkannya kepada pengguna. Seorang pengaturcara web perlu mempunyai pemahaman yang baik tentang konsep ini. | |
14 | - | |
15 | -<!--more--> | |
16 | - | |
17 | -## Bahasa Client-Side | |
18 | - | |
19 | -Fail yang diterima pada client biasanya adalah dalam bahasa **HTML**. Kandungan yang ingin dipaparkan seperti teks, imej, jadual, dan lain-lain ditetapkan melalui HTML. Satu bahasa lain pula iaitu **CSS** digunakan untuk membantu menggayakan elemen yang terdapat dalam HTML tadi, seperti mewarnakan teks atau latar belakang, menetapkan tebal garisan, dan sebagainya. HTML dan CSS dikatakan sebagai bahasa pengaturcaraan _client-side_. | |
20 | - | |
21 | -Di bawah ialah contoh mudah kandungan sebuah fail HTML yang mengandungi sedikit CSS. Ia akan memaparkan sebuah jadual: | |
22 | - | |
23 | -```html | |
24 | -<html> | |
25 | - <head> | |
26 | - <style rel="stylesheet" type="text/css"> | |
27 | - /* | |
28 | - * CSS untuk menetapkan gaya tulisan dan jadual | |
29 | - */ | |
30 | - div.title { | |
31 | - font-size: 130%; | |
32 | - } | |
33 | - table { | |
34 | - border-collapse: collapse; | |
35 | - } | |
36 | - th, td { | |
37 | - border: 1px solid black; | |
38 | - padding: 5px; | |
39 | - } | |
40 | - </style> | |
41 | - </head> | |
42 | - <body> | |
43 | - <!-- | |
44 | - Kandungan atau maklumat yang ingin dipaparkan | |
45 | - --> | |
46 | - <div class="title">Density of Precious Metals, in g/cm^3</div> | |
47 | - <table> | |
48 | - <tr> | |
49 | - <th>Element</th> | |
50 | - <th>Density</th> | |
51 | - </tr> | |
52 | - <tr> | |
53 | - <td>Copper</td> | |
54 | - <td>8.94</td> | |
55 | - </tr> | |
56 | - <tr> | |
57 | - <td>Silver</td> | |
58 | - <td>10.49</td> | |
59 | - </tr> | |
60 | - <tr> | |
61 | - <td>Gold</td> | |
62 | - <td>19.30</td> | |
63 | - </tr> | |
64 | - <tr> | |
65 | - <td>Platinum</td> | |
66 | - <td>21.45</td> | |
67 | - </tr> | |
68 | - </table> | |
69 | - </body> | |
70 | -</html> | |
71 | -``` | |
72 | - | |
73 | -Jadual seperti di bawah ini akan dipaparkan pada pelayar web: | |
74 | - | |
75 | -![Result 1]({{ site.baseurl }}/public/client-side-vs-server-side/diag1.jpg) | |
76 | - | |
77 | -## Bahasa Server-Side | |
78 | - | |
79 | -Fail HTML ini mungkin sahaja adalah sememangnya sebuah fail sebenar yang berada di _server_. Sang pengaturcara menaipkan kod-kod HTML dan CSS seperti di atas ke dalam sebuah editor teks dan menyimpannya sebagai sebuah fail. Fail itu kemudiannya diletakkan di dalam satu folder di _server_ yang boleh diakses oleh _client_ atau pelayar web. Fail seperti ini kadangkala dipanggil _static HTML_. | |
80 | - | |
81 | -Namun boleh jadi juga fail HTML ini tidak wujud terlebih dahulu, tetapi dijanakan secara dinamik. Sang pengaturcara boleh menggunakan bahasa seperti **PHP, Java, C#, Ruby, Python, Perl** dan sebagainya untuk menjana HTML tersebut. Bahasa-bahasa seperti ini disebut bahasa pengaturcaraan _server-side_. | |
82 | - | |
83 | -Berikut adalah contoh bagaimana bahasa PHP boleh digunakan untuk menghasilkan output yang seperti di atas, tetapi dengan datanya diambil dari sebuah pangkalan data berbanding ditaip terus seperti tadi. | |
84 | - | |
85 | -```php | |
86 | -<html> | |
87 | - <head> | |
88 | - <style rel="stylesheet" type="text/css"> | |
89 | - /* | |
90 | - * CSS untuk menetapkan gaya tulisan dan jadual | |
91 | - */ | |
92 | - div.title { | |
93 | - font-size: 130%; | |
94 | - } | |
95 | - table { | |
96 | - border-collapse: collapse; | |
97 | - } | |
98 | - th, td { | |
99 | - border: 1px solid black; | |
100 | - padding: 5px; | |
101 | - } | |
102 | - </style> | |
103 | - </head> | |
104 | - <body> | |
105 | - <!-- | |
106 | - Kandungan atau maklumat yang ingin dipaparkan | |
107 | - --> | |
108 | - <div class="title">Density of Precious Metals, in g/cm^3</div> | |
109 | - <table> | |
110 | - <tr> | |
111 | - <th>Element</th> | |
112 | - <th>Density</th> | |
113 | - </tr> | |
114 | - | |
115 | - /* | |
116 | - * Dapatkan data dari pangkalan data. | |
117 | - * Setiap "metal" mengandungi maklumat | |
118 | - * "name" dan "density". | |
119 | - */ | |
120 | - $metals = retrieveMetalDensitiesFromDatabase(); | |
121 | - | |
122 | - foreach ($metals as $metal) | |
123 | - { | |
124 | - ?> | |
125 | - <tr> | |
126 | - <td>echo $metal["name"]; </td> | |
127 | - <td>echo $metal["density"]; </td> | |
128 | - </tr> | |
129 | - } | |
130 | - </table> | |
131 | - </body> | |
132 | -</html> | |
133 | -``` | |
134 | - | |
135 | -Ia akan menghasilkan output sama seperti di atas, jika kandungan pangkalan data itu mengandungi senarai yang sama. | |
136 | - | |
137 | -## JavaScript | |
138 | - | |
139 | -Berbalik kepada _client-side_, ada satu lagi bahasa yang kita boleh gunakan iaitu **JavaScript**. Ia boleh menjadikan halaman web lebih dinamik, contohnya seperti menggerakkan teks ke kiri dan ke kanan, mengeluarkan dialog amaran, menukar warna latar belakang mengikut masa dan lain-lain. Secara mudahnya, boleh dikatakan JavaScript ini memanipulasi HTML dan CSS tadi untuk memaparkan kandungan dan gaya berbeza kepada pengguna. | |
140 | - | |
141 | -Contoh di bawah ialah kod JavaScript yang memaparkan waktu semasa. Ia berdetik setiap saat and mengemaskini waktu yang dipaparkan. | |
142 | - | |
143 | -```html | |
144 | -<html> | |
145 | - <body> | |
146 | - Time now is <span id="clock"></span>. | |
147 | - <script> | |
148 | - function displayTime() { | |
149 | - document.getElementById("clock").innerHTML = new Date(); | |
150 | - } | |
151 | - setInterval(displayTime, 1000); | |
152 | - displayTime(); | |
153 | - </script> | |
154 | - </body> | |
155 | -</html> | |
156 | -``` | |
157 | - | |
158 | -<div class="message"> | |
159 | - Time now is <span id="csvsss_clock"></span>. | |
160 | -</div> | |
161 | - | |
162 | -<script> | |
163 | -function displayTime() { | |
164 | - document.getElementById("csvsss_clock").innerHTML = new Date(); | |
165 | -} | |
166 | -setInterval(displayTime, 1000); | |
167 | -displayTime(); | |
168 | -</script> | |
169 | - | |
170 | -Penggunaan JavaScript pada masa kini sudah menjadi sangat maju sehingga pelbagai perkara dapat dibuat untuk menjadikan paparan web lebih menarik. Ada banyak kod JavaScript yang siap digunakan di luar sana. | |
171 | - | |
172 | -Di sini ingin dibawakan satu contoh kod JavaScript yang dinamakan Google Charts yang mana boleh digunakan untuk membina perlbagai graf dan carta. Kita cuba masukkan satu carta lajur untuk jadual kita di atas. | |
173 | - | |
174 | -```html | |
175 | -<html> | |
176 | - <head> | |
177 | - <style rel="stylesheet" type="text/css"> | |
178 | - /* | |
179 | - * CSS untuk menetapkan gaya tulisan dan jadual | |
180 | - */ | |
181 | - div.title { | |
182 | - font-size: 130%; | |
183 | - } | |
184 | - table { | |
185 | - border-collapse: collapse; | |
186 | - } | |
187 | - th, td { | |
188 | - border: 1px solid black; | |
189 | - padding: 5px; | |
190 | - } | |
191 | - </style> | |
192 | - </head> | |
193 | - <body> | |
194 | - <!-- | |
195 | - Kandungan atau maklumat yang ingin dipaparkan | |
196 | - --> | |
197 | - <div class="title">Density of Precious Metals, in g/cm^3</div> | |
198 | - <table> | |
199 | - <tr> | |
200 | - <th>Element</th> | |
201 | - <th>Density</th> | |
202 | - </tr> | |
203 | - <tr> | |
204 | - <td>Copper</td> | |
205 | - <td>8.94</td> | |
206 | - </tr> | |
207 | - <tr> | |
208 | - <td>Silver</td> | |
209 | - <td>10.49</td> | |
210 | - </tr> | |
211 | - <tr> | |
212 | - <td>Gold</td> | |
213 | - <td>19.30</td> | |
214 | - </tr> | |
215 | - <tr> | |
216 | - <td>Platinum</td> | |
217 | - <td>21.45</td> | |
218 | - </tr> | |
219 | - </table> | |
220 | - | |
221 | - <!-- | |
222 | - JavaScript untuk membina carta | |
223 | - --> | |
224 | - <div id="chart"></div> | |
225 | - <script type="text/javascript" | |
226 | - src="https://www.google.com/jsapi"></script> | |
227 | - <script type="text/javascript"> | |
228 | - google.load('visualization', '1.0', | |
229 | - {'packages':['corechart']}); | |
230 | - google.setOnLoadCallback(drawChart); | |
231 | - function drawChart() { | |
232 | - var data = google.visualization.arrayToDataTable([ | |
233 | - ['Element', 'Density'], | |
234 | - ['Copper', 8.94], | |
235 | - ['Silver', 10.49], | |
236 | - ['Gold', 19.30], | |
237 | - ['Platinum', 21.45] | |
238 | - ]); | |
239 | - var chart = new google.visualization.ColumnChart(document.getElementById('chart')); | |
240 | - chart.draw(data); | |
241 | - } | |
242 | - </script> | |
243 | - </body> | |
244 | -</html> | |
245 | -``` | |
246 | - | |
247 | -Hasilnya akan kelihatan seperti berikut: | |
248 | - | |
249 | -![Result 2]({{ site.baseurl }}/public/client-side-vs-server-side/diag2.jpg) | |
250 | - | |
251 | -## Kerjasama Bahasa Client-Side dan Server-Side | |
252 | - | |
253 | -Jika kita ada menggunakan bahasa _server-side_, kita boleh mendapatkan hasil yang sama melalui kod seperti berikut: | |
254 | - | |
255 | -```php | |
256 | -<html> | |
257 | - <head> | |
258 | - <style rel="stylesheet" type="text/css"> | |
259 | - /* | |
260 | - * CSS untuk menetapkan gaya tulisan dan jadual | |
261 | - */ | |
262 | - div.title { | |
263 | - font-size: 130%; | |
264 | - } | |
265 | - table { | |
266 | - border-collapse: collapse; | |
267 | - } | |
268 | - th, td { | |
269 | - border: 1px solid black; | |
270 | - padding: 5px; | |
271 | - } | |
272 | - </style> | |
273 | - </head> | |
274 | - <body> | |
275 | - <!-- | |
276 | - Kandungan atau maklumat yang ingin dipaparkan | |
277 | - --> | |
278 | - <div class="title">Density of Precious Metals, in g/cm^3</div> | |
279 | - <table> | |
280 | - <tr> | |
281 | - <th>Element</th> | |
282 | - <th>Density</th> | |
283 | - </tr> | |
284 | - | |
285 | - /* | |
286 | - * Dapatkan data dari pangkalan data. | |
287 | - * Setiap "metal" mengandungi maklumat | |
288 | - * "name" dan "density". | |
289 | - */ | |
290 | - $metals = retrieveMetalDensitiesFromDatabase(); | |
291 | - | |
292 | - foreach ($metals as $metal) | |
293 | - { | |
294 | - ?> | |
295 | - <tr> | |
296 | - <td>echo $metal["name"]; </td> | |
297 | - <td>echo $metal["density"]; </td> | |
298 | - </tr> | |
299 | - } | |
300 | - </table> | |
301 | - | |
302 | - <!-- | |
303 | - JavaScript untuk membina carta | |
304 | - --> | |
305 | - <div id="chart"></div> | |
306 | - <script type="text/javascript" | |
307 | - src="https://www.google.com/jsapi"></script> | |
308 | - <script type="text/javascript"> | |
309 | - google.load('visualization', '1.0', | |
310 | - {'packages':['corechart']}); | |
311 | - google.setOnLoadCallback(drawChart); | |
312 | - function drawChart() { | |
313 | - var data = google.visualization.arrayToDataTable([ | |
314 | - | |
315 | - /* | |
316 | - * Gunakan data "metals" tadi untuk | |
317 | - * membina carta pula. | |
318 | - */ | |
319 | - foreach ($metals as $metal) | |
320 | - { | |
321 | - echo "['".$metal["name"]."', '".$metal["density"]."'],"; | |
322 | - } | |
323 | - ?> | |
324 | - ]); | |
325 | - var chart = new google.visualization.ColumnChart(document.getElementById('chart')); | |
326 | - chart.draw(data); | |
327 | - } | |
328 | - </script> | |
329 | - </body> | |
330 | -</html> | |
331 | -``` | |
332 | - | |
333 | -Perhatikan, bagaimana dengan bahasa _server-side_ (PHP), kita membina output yang terdiri dari bahasa _client-side_ (sama ada HTML, CSS, atau JavaScript). Hasilnya pula kemudiannya diproses oleh pelayar web dan dipaparkan. Ia seperti lapisan bahasa pengaturcaraan di atas bahasa pengaturcaraan yang lain! | |
334 | - | |
335 | -Perhatikan juga bagaimana di dalam satu fail berselang-seli bahasa _server-side_ dan _client-side_. Perkara ini kadang-kala mengelirukan pengaturcara-pengaturcara baru. Jika anda menghadapi situasi ini, cuba kembali kepada asasnya. Kenalpasti yang mana adalah kod _client-side_ dan yang mana _server-side_. Pemahaman yang baik tentang asas ini membolehkan anda cekap bermain dengan kod _client-side_ dan _server-side_ dan dapat menghasilkan penyelesaian yang kreatif. |
_posts/2015-03-01-di-sebalik-form.md | ||
---|---|---|
@@ -1,151 +1,0 @@ | ||
1 | ---- | |
2 | -layout: post | |
3 | -title: 'Di Sebalik Form' | |
4 | -date: 2015-03-01 | |
5 | -author: kamalmustafa | |
6 | -permalink: /di-sebalik-form.html | |
7 | -level: 2 | |
8 | -summary: > | |
9 | - Sebagai web developer, anda sudah biasa dengan proses membina form, dan kemudian | |
10 | - menghantar (submit) form tersebut untuk di proses di server, sama ada menggunakan | |
11 | - platform *server-side* seperti PHP, Python, .Net, Rails dan sebagainya. | |
12 | - | |
13 | - Tapi pernahkah anda terfikir, bagaimanakah data daripada *form* tersebut dihantar | |
14 | - daripada *client* (*browser*) ke *server* ? Apakah format data tersebut ? | |
15 | ---- | |
16 | -Sebagai web developer, anda sudah biasa dengan proses membina form, dan kemudian | |
17 | -menghantar (submit) form tersebut untuk di proses di server, sama ada menggunakan | |
18 | -platform *server-side* seperti PHP, Python, .Net, Rails dan sebagainya. | |
19 | - | |
20 | -Tapi pernahkah anda terfikir, bagaimanakah data daripada *form* tersebut dihantar | |
21 | -daripada *client* (*browser*) ke *server* ? Apakah format data tersebut ? | |
22 | - | |
23 | -<!--more--> | |
24 | - | |
25 | -Asas kepada *web development* adalah [HTTP][http] (Hypertext Transfer Protocol). Ia adalah | |
26 | -protokol, atau satu bentuk piawai yang menetapkan bagaimanakah data daripada *client* | |
27 | -dihantar ke *server*. Yang bagusnya, protokol ini adalah berasaskan *text*, iaitu data | |
28 | -dihantar dalam bentuk *plain text*, berbanding sesetengah protokol lain yang memerlukan | |
29 | -data dihantar dalam bentuk *binaries encoding*. | |
30 | - | |
31 | -Ini menjadikan HTTP tidak memerlukan sebarang peralatan (*tools*) khas jika kita ingin | |
32 | -membina client atau server yang boleh 'bercakap' dalam 'bahasa' HTTP. Apa saja yang boleh | |
33 | -menghantar dan menerima teks boleh digunakan. | |
34 | - | |
35 | -<div class="admonition-warning"> | |
36 | - Protokol baru HTTP/2 bagaimanapun berbeza dengan HTTP/1.1 yang digunakan sekarang | |
37 | - kerana ia tidak lagi berasaskan teks, tetapi dalam bentuk binari. | |
38 | -</div> | |
39 | -<div> </div> | |
40 | - | |
41 | -Apakah contoh satu *tools* yang boleh menghantar teks dengan mudah ke server ? Telnet ! | |
42 | - | |
43 | -Ya, untuk menghantar dan menerima data melalui HTTP anda tidak perlu membina sebuah *browser* | |
44 | -seperti Firefox atau Google Chrome. Contoh, anda boleh meminta (*request*) resource daripada | |
45 | -laman web Google menggunakan telnet seperti berikut:- | |
46 | - | |
47 | -``` | |
48 | -telnet www.google.com 80 | |
49 | -Trying 173.194.120.114... | |
50 | -Connected to www.google.com. | |
51 | -Escape character is '^]'. | |
52 | -GET / | |
53 | -HTTP/1.0 302 Found | |
54 | -Location: http://www.google.com.my/?gws_rd=cr&ei=xc3yVKKzMYuXuAS18oGABg | |
55 | -Cache-Control: private | |
56 | -Content-Type: text/html; charset=UTF-8 | |
57 | -Set-Cookie: PREF=ID=48850ef362af9ca3:FF=0:TM=1425198533:LM=1425198533:S=6i5_XBkARR8adf6f; expires=Tue, 28-Feb-2017 08:28:53 GMT; path=/; domain=.google.com | |
58 | -Set-Cookie: NID=67=e2bqYqDM8NNvzFh0-2DoYBMXsff90Meli0u3otU0yxtBELBn7WbS7zqPOYE1gf8ukH7qb08OtGS8RLf96ECSlQuCcoTnGcYPRyUGY_8OA3dFnUOLKM1EFsMbVYovs5hT; expires=Mon, 31-Aug-2015 08:28:53 GMT; path=/; domain=.google.com; HttpOnly | |
59 | -P3P: CP="This is not a P3P policy! See http://www.google.com/support/accounts/bin/answer.py?hl=en&answer=151657 for more info." | |
60 | -Date: Sun, 01 Mar 2015 08:28:53 GMT | |
61 | -Server: gws | |
62 | -Content-Length: 262 | |
63 | -X-XSS-Protection: 1; mode=block | |
64 | -X-Frame-Options: SAMEORIGIN | |
65 | -Alternate-Protocol: 80:quic,p=0.08 | |
66 | - | |
67 | -<HTML><HEAD><meta http-equiv="content-type" content="text/html;charset=utf-8"> | |
68 | -<TITLE>302 Moved</TITLE></HEAD><BODY> | |
69 | -<H1>302 Moved</H1> | |
70 | -The document has moved | |
71 | -<A HREF="http://www.google.com.my/?gws_rd=cr&ei=xc3yVKKzMYuXuAS18oGABg">here</A>. | |
72 | -</BODY></HTML> | |
73 | -Connection closed by foreign host. | |
74 | -``` | |
75 | -Dalam contoh di atas, setelah berjaya *connect* ke server Google pada port 80, kita menghantar | |
76 | -*request* seperti berikut:- | |
77 | - | |
78 | -``` | |
79 | -GET / | |
80 | -``` | |
81 | -*Request* di atas adalah sama dengan kita menaip di *address bar* browser `http://173.194.120.114/`. | |
82 | -Teks seterusnya adalah *response* yang kita dapat daripada *server* Google. 302 adalah HTTP status | |
83 | -daripada Google, manakala baris berikutnya merupakan *headers* yang menunjukkan url yang boleh kita | |
84 | -capai seterusnya. Inilah yang dinamakan *redirect* dan *HTTP client* seperti browser akan *redirect* | |
85 | -kita ke url yang diberikan. | |
86 | - | |
87 | -Menggunakan telnet sebagai HTTP client bagaimanapun agak terhad apa yang kita boleh lakukan. Dalam | |
88 | -contoh di atas, selepas *connect* ke Google, saya hanya boleh taip sebaris `GET /` dan Google terus | |
89 | -menghantar response. Saya tidak sempat untuk menghantar *headers* lain seperti `HOST` dan sebagainya. | |
90 | -Satu lagi *tools* lain yang lebih fleksibel adalah `nc`. Saya ada [menulis][nc] mengenai penggunaanya sebelum | |
91 | -ini. | |
92 | - | |
93 | -Berbalik kepada tajuk tulisan ini, mari kita lihat apakah data yang dihantar apabila kita submit *form* | |
94 | -pendaftaran di laman Facebook.com. Untuk melihat data yang dihantar, saya menggunakan kaedah yang paling | |
95 | -*simple*, iaitu menukar bahagian `<form action=...>` *form* tersebut ke tempat lain. | |
96 | - | |
97 | -<img src="http://i.imgur.com/QUF21Lj.png"></img> | |
98 | -<img src="http://i.imgur.com/rccFhbx.png"></img> | |
99 | - | |
100 | -Dalam *screenshot* di atas, saya telah menukar `<form action=...>` *form* tersebut ke:- | |
101 | - | |
102 | -``` | |
103 | -http://localhost:4000/ | |
104 | -``` | |
105 | -Ini adalah kaedah paling *simple*. Cara lain untuk 'menangkap' data yang dihantar adalah dengan menggunakan | |
106 | -perisian seperti Wireshark atau `tcpdump`. Saya lebih gemarkan cara ini kerana data yang kita dapat lebih | |
107 | -*raw* dan tidak melalui sebarang bentuk *processing*. Ia betul-betul data yang diterima daripada browser | |
108 | -pada *socket* di *port* 4000. Untuk menerima data tersebut, kita hanya perlu menggunakan perisian bernama | |
109 | -netcat atau nc. Jalankan arahan berikut:- | |
110 | - | |
111 | -``` | |
112 | -nc -l 4000 | |
113 | -``` | |
114 | -Arahan diatas meminta `nc` *listen* pada *port* 4000, dan bersedia menerima sebarang data yang dihantar | |
115 | -melalui *port* tersebut. Setelah kita *submit* *form* pendaftaran Facebook tadi, kita akan dapati teks | |
116 | -dibawah dipaparkan pada konsol dimana `nc` tadi dijalankan. | |
117 | - | |
118 | -Ya, inilah contoh data yang dihantar, apabila kita *submit* form pada satu-satu laman web, dalam contoh | |
119 | -ini laman Facebook.com. | |
120 | - | |
121 | -``` | |
122 | -POST / HTTP/1.1 | |
123 | -Host: localhost:4000 | |
124 | -Connection: keep-alive | |
125 | -Content-Length: 1022 | |
126 | -Cache-Control: max-age=0 | |
127 | -Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8 | |
128 | -Origin: https://www.facebook.com | |
129 | -User-Agent: Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.111 Safari/537.36 | |
130 | -Content-Type: application/x-www-form-urlencoded | |
131 | -Accept-Encoding: gzip,deflate | |
132 | -Accept-Language: en-US,en;q=0.8 | |
133 | - | |
134 | -lsd=AVpzsLKs&firstname=Kamal&lastname=Mustafa®_email__=kmkml%40yahoo.com®_email_confirmation__=kmkml%40yahoo.com®_passwd__=abc123&birthday_month=7&birthday_day=26&birthday_year=1991&sex=2&websubmit=&referrer=&asked_to_login=&terms=on&ab_test_data=®_instance=l_byVOe0tUkXB8lG29Dte0Zj&contactpoint_label=email_or_phone&locale=en_US&captcha_persist_data=AZlcaJSuaa-rSMdsK8CsS8tRNMgau9HFF2b33fK7a-ydHKi7emqwu3y-_E8fOuL3m3e5SDmXANKzSRspsF1O6ugJdZ_aCGJy0QHpi4JU0JpDypQIx2_WpbzT6OV1UhSetMP05to2mFtVK0hS50NWSbZ1BJYv_ygKP5tt1BRCEiUHyW9-hxLG-nrWUF7DBlyMeEiyDLdknXabXEtfdqMpToPOxvsb1qMymwv-9fibK9CHGGV1yD8bK3RlhSWVdsDk2Rl1V8d0-PkynVcXbT5GaJBDy-bBtctrMHHHTjzIIGATS5mKr7Dyu4qrDuUEYC3L7ipfExwoewlqrISKoTyoUhwsWhageWVrm5f7IcnRHyLeIg&captcha_session=CnTabJ0C4tNIiH63kxKnrw&extra_challenge_params=authp%3Dnonce.tt.time.new_audio_default%26psig%3DjAKLb4KI5WqB-zg_RE5QcLV8sss%26nonce%3DCnTabJ0C4tNIiH63kxKnrw%26tt%3DRXdPBAAUdMa1cxL9bQ0irk2F0lQ%26time%3D1425209003%26new_audio_default%3D1&recaptcha_type=password&captcha_response= | |
135 | -``` | |
136 | - | |
137 | -Di bahagian [*server-side*](/client-side-vs-server-side.html), data di atas kemudian akan diproses ke dalam bentuk yang lebih | |
138 | -mudah untuk *developer* gunakan. Contohnya dalam platform PHP, anda akan mendapat [data di atas dalam bentuk `$_GET` atau `$_POST`](http://k4ml.github.io/ms/posts/bagaimana-_post-dan-_get-terhasil.html). | |
139 | - | |
140 | -Kita boleh meneruskan eksperimen ini untuk melihat situasi-situasi lain, contohnya apabila *submit* form menggunakan | |
141 | -jQuery.AJAX contohnya tetapi saya akan berhenti disini terlebih dahulu. | |
142 | - | |
143 | -Poin terpenting yang saya ingin rumuskan disini | |
144 | -adalah apabila kita memahami bagaimana sesuatu teknologi itu berfungsi pada tahap yang paling asas, ia akan lebih membantu | |
145 | -kita dalam menyelesaikan permasalahan berkaitan teknologi tersebut. | |
146 | - | |
147 | -Sentiasa ajukan persoalan kepada diri sendiri, bagaimana sesuatu benda itu berfungsi dan jalankan eksperimen untuk | |
148 | -mendapatkan jawapannya. | |
149 | - | |
150 | -[nc]:http://metak4ml.blogspot.com/2013/05/craft-http-requests-using-nc.html | |
151 | -[http]:https://www.ietf.org/rfc/rfc2616.txt |
Built with git-ssb-web