tag:blogger.com,1999:blog-22156048853386793292024-03-05T16:58:52.951+08:00Don'tCare痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.comBlogger91125tag:blogger.com,1999:blog-2215604885338679329.post-46016265126101759032022-04-01T00:26:00.002+08:002022-04-01T00:26:23.599+08:00StarPocks 0.0.1 Released<p><a href="https://github.com/DontCareAbout/StarPocks">StarPocks</a> 是一個將 Java class(們)自動轉換成 <a href="https://mermaid-js.github.io/">Mermaid.js</a> class diagram 語法的工具。</p>
<p>0.0.1 版提供了下列功能:</p>
<ul>
<li>將 class 轉換成 <a href="https://mermaid-js.github.io/">Mermaid.js</a> 語法
<ul>
<li>顯示 public field / method(含 static)</li>
<li>以 stereotype 顯示是否為 interface / abstract class</li>
</ul>
</li>
<li>顯示 class 的 hierarchy,並呈現 class 之間的 implement / extend 關係</li>
<li>可指定轉換多個 class</li>
<li>自動排除 class 名稱相同造成的 <a href="https://mermaid-js.github.io/">Mermaid.js</a> 語法衝突問題</li>
</ul>
痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-69693808814332771502022-02-19T08:00:00.003+08:002022-03-01T17:06:11.926+08:00Mermaid.js Class Diagram 語法重點<blockquote>
<p>備註:若後續有改動,此文件不會再更新,請改參考此<a href="https://github.com/PsMonkey/wiki/blob/master/misc/Mermaid-JS.md">文件</a></p>
</blockquote>
<p>分為兩個部份:「class 定義」、「class 間的關係」。</p>
<p>由於 generic type 的定義哏(後敘),<br>
先寫「class 定義」再寫「class 間的關係」比較保險。</p>
<a href="http://blog.dontcareabout.us/2022/02/mermaidjs-class-diagram.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-84483918438707213922020-08-10T04:29:00.001+08:002020-08-10T04:29:20.540+08:00SpriteOverEvent 之靈異現象<h1 id="重現方式">重現方式</h1>
<p>直接上 SSCCE:</p>
<pre class=" language-java"><code class="prism language-java"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">SpriteTestEP</span> <span class="token keyword">extends</span> <span class="token class-name">DrawComponent</span> <span class="token keyword">implements</span> <span class="token class-name">EntryPoint</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> RectangleSprite red <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RectangleSprite</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">,</span> <span class="token number">201</span><span class="token punctuation">,</span> <span class="token number">100</span><span class="token punctuation">,</span> <span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> RectangleSprite none <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">RectangleSprite</span><span class="token punctuation">(</span><span class="token number">200</span><span class="token punctuation">,</span> <span class="token number">201</span><span class="token punctuation">,</span> <span class="token number">300</span><span class="token punctuation">,</span> <span class="token number">50</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token function">SpriteTestEP</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
red<span class="token punctuation">.</span><span class="token function">setFill</span><span class="token punctuation">(</span>RGB<span class="token punctuation">.</span>RED<span class="token punctuation">)</span><span class="token punctuation">;</span>
none<span class="token punctuation">.</span><span class="token function">setFill</span><span class="token punctuation">(</span>Color<span class="token punctuation">.</span>NONE<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">addSprite</span><span class="token punctuation">(</span>red<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">addSprite</span><span class="token punctuation">(</span>none<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">addSpriteOverHandler</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">SpriteOverHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onSpriteOver</span><span class="token punctuation">(</span>SpriteOverEvent event<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Over : "</span> <span class="token operator">+</span> <span class="token function">who</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token function">getSprite</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">addSpriteOutHandler</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">SpriteOutHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onSpriteLeave</span><span class="token punctuation">(</span>SpriteOutEvent event<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token function">log</span><span class="token punctuation">(</span><span class="token string">"Out : "</span> <span class="token operator">+</span> <span class="token function">who</span><span class="token punctuation">(</span>event<span class="token punctuation">.</span><span class="token function">getSprite</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> String <span class="token function">who</span><span class="token punctuation">(</span>Sprite sprite<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token punctuation">(</span>sprite <span class="token operator">==</span> red <span class="token operator">?</span> <span class="token string">"red"</span> <span class="token operator">:</span> <span class="token string">"none"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">native</span> <span class="token keyword">void</span> <span class="token function">log</span><span class="token punctuation">(</span>Object object<span class="token punctuation">)</span> <span class="token comment">/*-{
console.log(
@java.lang.String::valueOf(Ljava/lang/Object;)(object)
);
}-*/</span><span class="token punctuation">;</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">onModuleLoad</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">//無關緊要,純粹 follow GXT 習慣 XD</span>
Viewport vp <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Viewport</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
vp<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
RootPanel<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span>vp<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre>
<p>操作步驟:</p>
<ol>
<li>游標進入紅色區塊</li>
<li>慢慢水平移動滑鼠,直到離開紅色區塊</li>
</ol>
<a href="http://blog.dontcareabout.us/2020/08/spriteoverevent.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-12850405584722752052020-07-02T00:13:00.002+08:002020-07-02T00:13:45.087+08:00JDK 15 的新功能<p>原文網址:<a href="https://www.infoworld.com/article/3534133/jdk-15-the-new-features-in-java-15.html">https://www.infoworld.com/article/3534133/jdk-15-the-new-features-in-java-15.html</a></p>
<p><a href="https://openjdk.java.net/projects/jdk/15/">Java Development Kit 15</a> 是 Java SE 的下個版本,Oracle 的實做在 6/11 進入到初期的 ramp-down phase,該版本的功能集已經定型了。JDK 15 的亮點包含 text block、hidden class、foreign memory 存取 API 以及 sealed class、record 的 preview 版本。</p>
<p>Java upgrade 也進入到 ramp-down phase,兩個候選版本會在 8/20 之前釋出。general availability 會在 9/15。JDK 15 的前身是 3/17 發布的 <a href="https://www.infoworld.com/article/3436795/jdk-14-the-new-features-in-java-14.html">JDK 14</a>。Oracle 在 Java SE 保持著 6 個月發布一次新版的步調,每年會有兩個新的版本問世。</p>
<p>OpenJDK 15 的新功能與改變:</p>
<ul>
<li>第二個 <a href="https://openjdk.java.net/jeps/383">foreign memory 存取 API</a> 的孵化版本,這可以讓 Java 程式安全且有效率地存取 Java heap 以外的 foreign memory。API 可以操作數種不同的 foreign memory,像是 native、persistent、managed heap。許多 Java 程式會存取 foreign memory,像是 Ignite、MapDB。這個 API 會協助避免產生與 garbage collection、跨 process 的 share memory、將檔案對應至記憶體的序列化… 相關的成本與不確定性。目前的 Java API 沒有提供令人滿意的 foreign memory 存取方法。但在新的提案當中,API 應該也不會損害到 JVM 的安全性。這個功能在 <a href="https://www.infoworld.com/article/3436795/jdk-14-the-new-features-in-java-14.html">JDK 14</a> 當中完成了早期孵化板,在 JDK 15 當中提供的是精鍊過的版本。</li>
<li><a href="https://openjdk.java.net/jeps/360">sealed class</a> 的 preview 版本。除了 interface,sealed class 限制其他 class 或 interface 如何繼承或實做 sealed class 的方式。這個功能的目標包含 class 或 interface 的設計者可以控制哪些程式碼是有實做的責任、提供一個比 access modifier 更具表達力的方法來限制 super class 的使用、以及 support future directions in pattern matching by underpinning the exhaustive analysis of patterns。</li>
<li>移除 Solaris/SPARC、Solaris/x64、Linux/SPARC 的支援。(細節略)</li>
<li><a href="https://openjdk.java.net/jeps/384">record</a> 是一種 class、它是 immutable 資料的透明載體。在 JDK 14 當中以前期 preview 版面世,JDK 15 應該會包含 preview 二版。這個計畫的目標包含設計一個 OO 建造法來表達一個簡單的數據集合、幫助程式設計師專住在建構 immutable data 而不是可繼承的行為、自動實做資料相關的 method(像是 equals 跟 assessor)、保持 Java 長期以來的原則(像是 nominal typing 以及移植能力)。record 可以視為是 nominal tuple。</li>
<li>基於 <a href="https://openjdk.java.net/jeps/339">Edwards-Curve Digital Signature Algorithm (EdDSA)</a> 的加密簽章演算法。EdDSA 是現代的 elliptic curve scheme 勝過目前 JDK 當中的簽章 scheme。EdDSA 只有在 SunEC provider 當中會實做。EdDSA 會被需要是因為相較於其他簽章 scheme 它加強了安全度及效能。一些加密的 library(例如 OpenSSL 跟 BoringSSL)已支援這個演算法。</li>
<li><a href="https://openjdk.java.net/jeps/373">重新實做古老的 DatagramSocket API</a>,將底層 <code>java.net.datagram.Socket</code> 以及 <code>java.net.MulticastSocket</code> API 換成簡單且較現代的實做方式。這帶來幾點好處:1. 容易除錯與維護。2. 使用 <a href="https://www.infoworld.com/article/3230507/java-jdk-10-what-new-features-to-expect-in-the-next-java.html">Project Loom</a> 正在開發的 virtual thread。新的計畫會依循 JEP 353(重新實做古老的 Socket API)。目前 <code>java.net.datagram.Socket</code> 以及 <code>java.net.MulticastSocket</code> 的實做可以回溯至 JDK 1.0,那時 IPv6 還在開發中。這造成目前 <code>MulticastSocket</code> 的實做試著調解 IPv4 跟 IPv6 導致很難維護。</li>
<li>預設<a href="https://openjdk.java.net/jeps/374">關掉 biased locking</a>,所有相關的 command-line 選項也都 deprecate。(細節略)</li>
<li>延續 <a href="https://www.infoworld.com/article/3436795/jdk-14-the-new-features-in-java-14.html">JDK 14</a> 的 preview 版本,推出 <a href="https://openjdk.java.net/jeps/375"><code>instanceof</code> 的 pattern matching</a> 的 preview 二版。pattern matching 主要可以讓「在程式當中用特定條件取出 object 的 component」的表示法變得更簡潔。像 Haskell 跟 C# 都因為其簡約與安全的特性而包含 pattern matching。</li>
<li><a href="https://www.infoworld.com/article/3520792/hidden-classes-could-be-coming-to-java.html">hidden class</a> 是無法讓其他 class 在 bytecode 當中直接使用的 class,這讓 framework 在 runtime 製造出 class 然後透過 reflection 的方式間接地使用這些 class。hidden class 可以被定義為 <a href="https://openjdk.java.net/jeps/181">access control nest</a> 的 member,並且可以獨立 unload。這個提案透過啟用標準 API 來定義無法被找到且有 limited lifecycle 的 hidden class,會增加所有 JVM 上語言的效能。無論 JDK 內外的 framework 將可以動態地製造 class 而不是定義 hidden class。許多在 JVM 上的語言依賴動態製造 class 來達到彈性與效率。這個提案的目標包含:讓 framework 定義找不到實做細節的 class,這樣其他 class 就無法連結到、也無法用 reflection 的方式發現到;support for extending an access control nest with non-discoverable classes;以及支援無法找到的 class 的侵入式 unload,這樣 framework 就有彈性可以想定義多少就定義多少。另外一個目標是 deprecate 一個非標準 API <code>misc.Unsafe::defineAnonymousClass</code>,這代表未來的版本會移除掉。同樣地,Java 語言並不會因為這個提案而有所改變。</li>
<li><a href="https://openjdk.java.net/jeps/377">Z Garbage Collector</a>(<a href="https://openjdk.java.net/jeps/377">ZGC</a>)將從實現性質的功能轉變成產品。2018 年 9 月整合進 <a href="https://www.infoworld.com/article/3265447/java-jdk-11-all-the-new-features-now-available.html">JDK 11</a> 的 ZGC 是一個可拓展、低延遲的 GC。ZGC 以實驗性功能的身份導入,是因為 Java 開發人員認為 ZGC 的大小與複雜度應該小心地逐步帶入。從那之後補強了許多部份,ranging from concurrent class unloading, uncommitting of unused memory, and support for data-class sharing to improved NUMA awareness and multi-threaded heap pre-touching。heap 的最大值也從 4TB 增加到 16 TB。支援的平台包括 Linux、Windows 與 MacOS。</li>
<li>text block 在 JDK 14 與 <a href="https://www.infoworld.com/article/3340052/jdk-13-the-new-features-in-java-13.html">JDK 13</a> 都出過 preview 版,要讓 Java 程式碼當中撰寫多行字串的工作便得簡單、同時避免大多數情況下的 escape sequence。一個 text block 是多行的字串,其中不包含 escape sequence、自動用可預測的方式格式化、並且提供開發人員控制格式的能力。A goal of the text blocks proposal is enhancing the readability of strings in Java programs that denote code written in non-Java languages. Another goal is to support migration from string literals by stipulating that any new construct can express the same set of strings as a string literal, interpret the same escape sequences, and be manipulated in the same fashion as a string literal. OpenJDK 開發人員希望增加 escape sequence 以管理明確的 white space 以及換行符號。</li>
<li><a href="https://www.infoworld.com/article/2888189/red-hat-shenandoah-boosts-java-garbage-collection.html">Shenandoah low-pause-time garbage collector</a> 從實驗性的功能轉變成產品。這在 <a href="https://www.infoworld.com/article/3301197/jdk-12-the-new-features-in-java-12.html">JDK 12</a> 時候導入,已經經過一年了。</li>
<li>移除 <a href="https://www.infoworld.com/article/3279893/nashorn-javascript-engine-for-jvm-could-be-axed.html">Nashorn</a>。(細節略)</li>
<li><a href="https://openjdk.java.net/jeps/385">Deprecation of the RMI Activation mechanism</a>(細節略)</li>
</ul>
痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com1tag:blogger.com,1999:blog-2215604885338679329.post-24491643834454202702020-06-03T17:00:00.003+08:002020-06-03T17:00:39.237+08:00GWT 2.9.0 發布<h1 id="亮點">亮點</h1>
<ul>
<li>可以用 jsinterop-base 1.0.0、elemental2 1.0.0、jsinterop-annotations 2.0.0(除了 <code>@JsAsync</code> 跟 <code>@JsEnum</code>)做 compile,這會讓 GWT2 將可以用 J2CL 以及這些工具來 compile。</li>
<li>增加 Java language level 9, 10, 11 的支援度。</li>
<li>正式停止在 Java 7 上執行 GWT compiler 與 server side tooling 的支援。在這個版本當中,GWT 還是可以在 Java 7 上 compile,但是不會保證能否運作。未來的版本會以 Java 8+ compile bytecode。這個版本用來測試與提供不同平台上搭配 Java 8, 11, 14 一起運作的方式。</li>
</ul>
<h1 id="棄用">棄用</h1>
<ul>
<li>Elemental 已經正式棄用了,這個版本裡頭還有,但是未來的版本當中可能就不會出現。我們建議用 Elemental2 來取代,它可以同時用 GWT2 以及 J2CL compile。</li>
<li>移除 <code>NoSuchMethodException</code> 的模擬。</li>
</ul>
<h1 id="修正">修正</h1>
<ul>
<li>修正 <code>float[]</code> 與 <code>double[]</code> 的 <code>Arrays.binarySearch()</code>。</li>
<li>error / exception 增加支援多行訊息。</li>
<li><code>DiskCache</code> 增加關閉的 hook 來清除暫存檔們。</li>
<li>將 Gecko 版號快取起來,以減少在 FireFox 的 CPU 使用率</li>
<li>不再假設「<code>this</code> 一定不是 null」</li>
<li>Updates globals for Firefox version 60.0.2, Chrome 66.0.3359.45。</li>
<li>修正 <code>String.regionMatches()</code>。</li>
<li>原生的 <code>JsMethods</code> 允許跟實做程式碼以相同名稱共存。</li>
<li>必要時,確保 lambda 的 box、unbox、insert 有消除 cast。</li>
<li><code>Double.compare()</code> 與 <code>Float.compare()</code> 正確地處理負 0。</li>
</ul>
<h1 id="雜項">雜項</h1>
<ul>
<li>CLDR 更新到 v.34。</li>
<li><code>Arrays</code> 現在有 implement <code>Cloneable</code>。</li>
<li>Link backing errors together with a cause attribute, start tracking suppressed errors in addition to the cause in underlying error object.</li>
<li><code>AtomicReference</code> 加到 <code>gwt/emul</code>。</li>
<li>Propagate script nonces via <code>ScriptInjector</code></li>
<li>增加 <code>ExecutorService</code> 與 <code>ScheduledExecutorService</code> 的部份功能模擬。</li>
<li>模擬 <code>java.util.concurrent.Flow</code>。</li>
<li>模擬 <code>javax.annotation{,.processing}.Generated</code>。</li>
<li>當 <code>goog.global</code> 沒有定義時,讓他變成 <code>$wnd。</code></li>
<li>增加 <code>when-linker-added</code> element definition。</li>
<li>增加 <code>Reader</code> 以及 <code>StringReader</code> 模擬。</li>
<li>移除 GWT 版本檢查。</li>
<li>synthetic method 不會顯示「unusable-by-js」警示。</li>
<li>Update unmodifiableList to throw on Java8 methods.</li>
<li>預設關掉 <code>DataflowOptimizer</code>,用到時會發出警告。</li>
</ul>
<p>更多細節參見 <a href="https://gwt.googlesource.com/gwt/+log/2.8.2..release/2.9.0">commit log</a></p>
痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-85597827125104884482016-05-09T17:20:00.001+08:002016-05-09T17:20:10.999+08:00GXT Component 的 onLoad 與 onShow 時機點<p>最近想要在 UI component 出現 / 消失的時候自動做一些事情,於是打算從 GXT <code>Component</code> 下手。不過怎麼寫怎麼有問題,只好寫 n 個 SSCCE 來確認一下,實驗結果紀錄於此。</p>
<h1 id="基本認識">基本認識</h1>
<p>我關心這四個 method:</p>
<ul>
<li><code>onLoad()</code></li>
<li><code>onUnload()</code></li>
<li><code>onShow()</code></li>
<li><code>onHide()</code></li>
</ul>
<p><code>onLoad()</code> 跟 <code>onUnload()</code> 是從 GWT 的 <code>Widget</code> 就定義的 method。理論上跟 <code>onAttach()</code>、<code>onDetach()</code> 等意,就是這個 component 加入到 DOM(或是從 DOM 中移除)時會觸發的 method。不過 API 都強烈建議用 <code>onLoad()</code> 跟 <code>onUnload()</code> 了,就乖乖照辦。</p>
<p><code>onShow()</code>、<code>onHide()</code> 是 GXT Component 開始定義的 method,最常遇到的 caller 大概是 GXT Component 的 <code>setVisible()</code>(override <code>UIObject</code>)。</p>
<a href="http://blog.dontcareabout.us/2016/05/gxt-component-onload-onshow.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com3tag:blogger.com,1999:blog-2215604885338679329.post-5287474100076132272016-04-14T11:17:00.001+08:002016-04-14T11:17:34.739+08:00service 版的 Tomcat 無法列印<p>web server 的環境:</p>
<ul>
<li>Windows Server 2008 Enterprise SP2
<ul><li>64bit</li>
<li>32bit</li></ul></li>
<li>JDK 1.7.0_55 (32bit)</li>
<li>Tomcat 6.0.26</li>
<li>印表機:TSC TTP 345,以網路印表機的方式連接。</li>
</ul>
<p>有一個功能是使用者按下按鈕後,web server 會用 JNA 載入印表機的 DLL,然後以程式控制列印內容。印表機不是實際連接到 web server,而是用網路印表機的方式連到 LAN 上頭某台使用者的 PC。
</p><a href="http://blog.dontcareabout.us/2016/04/service-tomcat.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-92193051540272240242016-02-27T21:56:00.001+08:002016-02-27T21:56:51.946+08:00不同量級的數值在同一個圖表上呈現<p>標題好難下,完整的標題應該是:</p>
<blockquote>
<p>在 GXT Chart 中,如何把<strong>兩個不同量級</strong>的數值在同一個圖表中都用<strong>長條圖</strong>當中呈現。</p>
</blockquote>
<p>拿這張圖表來舉例說明:</p>
<p><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi7jUc83239W0NSEO7bxDrSB8ulLiSMP5BojA9v3B_ER1wt-Q6PFTdCwlnl13He2wsTQBVG2IMIdq00ptGl2qCWQz6LH99uqwM8N0OFdo4T19C1lrdP8KNUkXqOgyUJWuflGzJSePevImM/s0/chart.png" alt="" title="範例"></p>
<a href="http://blog.dontcareabout.us/2016/02/blog-post.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com1tag:blogger.com,1999:blog-2215604885338679329.post-2141412802877200812015-11-15T15:17:00.001+08:002015-11-15T15:26:39.364+08:00HTTP/2<p>原文網址:<a href="http://www.integralist.co.uk/posts/http2.html">http://www.integralist.co.uk/posts/http2.html</a></p>
<hr>
<h1 id="引言">引言</h1>
<p>這是一篇很簡短的文章,展示如何利用新的 HTTP/2 通訊協定。如果你不熟悉它,那麼讓我花一點點時間來討論其中的一些亮點:</p>
<ul>
<li>單一、持續的連線</li>
<li>Multiplexing</li>
<li>壓縮 header</li>
<li>優先等級</li>
<li>加密</li>
<li>Server Push</li>
</ul>
<p>如果這些功能對你而言都不知所云,讓我作進一步的解釋……</p>
<a href="http://blog.dontcareabout.us/2015/11/http2.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com4tag:blogger.com,1999:blog-2215604885338679329.post-26386228414402795692015-10-30T13:50:00.001+08:002015-10-30T13:50:31.316+08:00Maven Assembly 的各種版本哏<p>故事是這樣的,專案的 project 海當中有一個是處理 Applet(不要問為什麼這個年代還在用 Applet,我後來改了一個 JWS 的版本,但是客戶還是想要保留 Applet [攤手])。雖然這個 project 是 maven 結構,但是 sign jar 還有最後整合進去真正的 web project 都還是用人工手動作的(不要再問了,我都要落淚了)。</p>
<p>雖然千百個不願意碰這個 Applet project,但事情終究還是發生了,因為最底層的 library 升級了,所以不改不行,那就順便把他變得自動化一點吧… Orz</p>
<p>sign jar 當然是找 maven-jarsigner-plugin(以下簡稱 <code>jarsigner</code>),掛上去之後發現… 奇怪,怎麼始終 build 失敗?用他錯誤訊息噴出來的那個 Windows command 字串去執行看看(當然要把 keypass 跟 storepass 換回實際的字串)卻又沒問題。喔對了,似乎這個問題只會在 Windows 上頭重現… Orz</p>
<p>最後發現,問題不是出在 <code>jarsigner</code> 上,而是 project 當中本來就有掛的 maven-assembly-plugin(以下簡稱 <code>assembly</code>)造成的。因為如果拿掉 <code>assembly</code> 的設定、或是把 <code>jarsigner</code> 挪到 <code>assembly</code> 之前(這居然是某些人認為的解法… 完全沒意義阿… WTF),是可以正常運作的。</p>
<p>兩個 plugin 的官方 issue tracker 都有這件事情(<a href="https://issues.apache.org/jira/browse/MJARSIGNER-13">jarsigner</a>、<a href="https://issues.apache.org/jira/browse/MASSEMBLY-593">assembly</a>)。似乎是 <code>assembly</code> 2.2 版之後才會發生的事情,因為退回到 2.1 版就沒問題了,那就退回去吧… 祈禱不要踩到「為什麼要升級」的哏。</p>
<p>BUT…</p>
<p>希望 <code>assembly</code> 產生的檔名是乾淨的 <code>foo.jar</code>,所以加了 <code><finalName></code>、也加了 <code><appendAssemblyId>false</appendAssemblyId></code>,然後又開始 build 失敗了。問題點是卡在 <code><appendAssemblyId></code> 上頭。最妙的事情是… 這個問題在 2.2 之後解決了…</p>
<p>…………(嗶──)</p>
<p>好了,解法有兩個,一個是忘記 <code>assembly</code> 改成用 <code>maven-shade-plugin</code>,我用 2.0 版測試沒有問題,能滿足上述兩個需求。</p>
<p>另一個是… 把 <code>assembly</code> 提升到 2.6,也可以滿足上述兩個需求… (我沒有測 <code>assembly</code> 2.5 搭配 <code>jarsigner</code> 會不會出問題,但是 2.4 版是確定有問題的)</p>
<p>…………(嗶──)</p>
<p>我說那個 issue 可以麻煩順便關一關嗎?<del>還是說根本是不知不覺間修好了,所以也沒發現......</del></p>
<p>這種排列組合的問題實在是很浪費生命阿… [淚目]</p>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-74270210405785547592015-07-04T01:27:00.001+08:002015-07-04T01:28:40.246+08:00畫一個箭頭<blockquote>
<h6 id="注意">注意</h6>
<p>這是一個沒學過圖學、線性代數也亂學的人寫出來的東西 (艸</p>
</blockquote>
<h1 id="名詞定義">名詞定義</h1>
<p><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmskJyOluKeZRXD8PayALrfrai4Vs51ncpRmLI2llPwoduGxhJucr5Y8d5LAOUsRxYQfwNK8fb6mcGLQ7EJi3fLrt2O_TwpX51gLDY1yaXxUXInrdglY_yY3-34vBplgwc9bRgIJe0CFo/s0/ImageEditor.jpg" alt="" title=""></p>
<p>input:</p>
<ul>
<li>起始點 <code>S</code> 座標為 (sx, sy)</li>
<li>終止點 <code>E</code> 座標為 (ex, ey)</li>
<li>比例參數:<code>rx1</code>、<code>rx2</code>、<code>ry1</code>、<code>ry2</code>。</li>
<li>角度:<code>d</code>
<ul><li>在上圖中 <code>d = 0</code>。箭頭向下是 <code>d=90</code>。</li></ul></li>
</ul>
<p>變數:</p>
<ul>
<li><code>w</code>:abs(ex - sx)</li>
<li><code>h</code>:abs(ey - sy)</li>
<li><code>x2</code>:w * rx2 / (rx1 + rx2)</li>
<li><code>y2</code>:h * ry2 / (ry1 + ry2) / 2</li>
</ul>
<p>所以各點座標為:</p>
<ul>
<li><code>A</code>:(ex, (sy + ey) / 2)</li>
<li><code>B1</code>:(sx + x2, sy)</li>
<li><code>B2</code>:(sx + x2, sy + y2)</li>
<li><code>C1</code>:(sx, sy + y2)</li>
<li><code>C2</code>:(sx, ey - y2)</li>
<li><code>B3</code>:(sx + x2, ey - y2)</li>
<li><code>B1</code>:(sx + x2, ey)</li>
</ul>
<a href="http://blog.dontcareabout.us/2015/07/blog-post.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-89633763745684141382015-04-05T07:07:00.001+08:002015-04-05T14:45:00.276+08:00理解 Finalizer<p>原文網址:<a href="https://plumbr.eu/blog/debugging-to-understand-finalizer">https://plumbr.eu/blog/debugging-to-understand-finalizer</a></p>
<hr>
<p>這篇文章涵蓋了一個 Java 的內建功能:<strong>Finalizer</strong>。這個功能實際上廣為人知卻也鮮為人知,取決於你是否仔細看過 <code>java.lang.Object</code>。在 <code>java.lang.Object</code> 中有一個叫做 <code>finalize()</code> 的 method。它沒有實際的內容,但是它的威能與危險程度都取決於 JVM 內部如何處置這個 method。</p>
<p>當 JVM 偵測到 class 有 <code>finalize()</code> 這個 method,黑魔法就開始了。所以,我們來弄一個有不同 <code>finalize()</code> 的 class,這樣我們就能知道在這種狀況下 JVM 會如何處理這個 object。</p>
<a href="http://blog.dontcareabout.us/2015/04/finalizer.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-2915935608043006962015-02-27T14:10:00.001+08:002015-02-27T14:18:52.940+08:00啥時找 library?啥時自幹?<p>原文網址:<a href="http://games.greggman.com/game/when-to-find-a-library-vs-when-to-write-code/">http://games.greggman.com/game/when-to-find-a-library-vs-when-to-write-code/</a></p>
<p>譯註:我幾乎完全不認同這篇的說法,更不用說 <a href="http://greggman.github.io/HappyFunTimes/">HappyFunTimes</a> 也是一個 library [大笑]。只是拿來恢復一下翻譯的感覺…</p>
<hr>
<p>身為一個 C / C++ 碼農,除非是很大的 project,不然我很少找 library。舉例來說,如果我需要讀 BMP / TGA 檔,帳面上要寫的程式碼不到 100 行。看一下資料格式、寫一些程式、打完收工。要是我需要載入 JPG / PNG 這些格式異常複雜的檔案,我終究會去找一個 library。</p>
<p>我現在寫 JavaScript 就不太一樣,在 JavaScript 的世界中有數以萬計<a href="http://npmjs.org/">針對各種狀況的小型 library</a>,讓我不知道該自幹程式還是找找看有沒有 library。這常常讓我覺得很浪費時間。</p>
<p>例如我要有一個非常簡單的功能:把字串裡頭的關鍵字換掉:</p>
<pre><code>replaceParams("Hello %(name)s", {name: "World"});
// produces:
// Hello World
</code></pre>
<p>後來為了可以這樣搞,所以拓展到 20 行:</p>
<pre><code>replaceParams(
"Hello %(name)s from %(user.country)s",
{
name: "Joe",
user: {
country:"USA",
},
});
// produces:
// Hello Joe from USA
</code></pre>
<p>最近我希望可以用路徑插入其他檔案,像這樣:</p>
<pre><code>replaceParams("->%(insertfile: foo/bar/moo.txt)s<-");
</code></pre>
<p>如果 <code>moo.txt</code> 裡頭是 <code>this-and-that</code>,結果會是:</p>
<pre><code>-->this-and-that<--
</code></pre>
<p>只需要幾分鐘的時間就可以加這個功能,但是… JavaScript 中的 template 系統超級多,我建一個 template 很快。也許我應該去用那些 template 系統而不是重新再造輪。</p>
<p>那麼,第一個問題是:要用哪一個?我聽過 mustache、handlebars、jade、ejs…… 為什麼要選 A 而不選 B?我花了大概 20 分鐘搜尋、試圖比較… 來讓我知道哪一個比較優秀。我看到「ejs = 嵌入 JS」看起來很像 PHP;我看到 handlebars 是以 mustache 為基礎但是快了很多。我決定用 handlebars、花了大概 20 分鐘來改程式碼,它輸出相同的結果,一切看起來很棒。</p>
<p>然後我試著加上我那個 <code>insertfile</code> 指令,靠夭,炸了 AFAICT,除了關鍵字以外都沒辦法傳進 template 中。現在已經過了一小時了,誰能告訴我為什麼我要再作一次這件事情?</p>
<p>這就是為什麼寫這篇文章《啥時找 library?啥時自幹?》。當然,在這個例子中,如果我不去找 library 就可能只會花掉我 5~10 分鐘。我選用的 library 有一些功能,像是可以擴展功能… 自幹版當然也可以加功能。另外它可以選擇要不要轉換跳脫字元,自幹版當然也可以有這個功能。我其實沒有答案……</p>
<p>我知道的是… 找 library 讓我覺得分心、浪費時間。前頭我很誇張地描述許多我下載的熱門 library 證實是爛掉的,時間都花在找尋、設定跟測試。相對地,也有人告訴我應該使用更多 library。像最近在 <a href="http://greggman.github.io/HappyFunTimes/">HappyFunTimes</a> 就有人說我應該用 <a href="https://www.npmjs.com/package/body-parser">body-parser</a> 來自動分析 JSON 而不是自己處理。我的程式有 5… 也許 10 行,但是 body-parser 有 2000 行。好啦好啦,它能處理一堆 case,但是這些 case 在 HappyFunTimes 幾乎都不會遇到。我試了 body-parser 結果發現它也沒有處理我沒法處理的錯誤。如果我能解決這些錯誤,在網路上找答案是不會解決的,只會找到誰也遇到這個問題而且一樣沒辦法解決。</p>
<p>我想用 library,因為我會假設他們處理一些我不知道的特殊狀況。不過它們搞出來的麻煩往往多過它們的價值。</p>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-76790767792290712512015-01-24T18:11:00.001+08:002015-01-24T18:11:02.170+08:002014 年 GWT 調查報告中文摘要<p>原始報告請到 <a href="https://vaadin.com/documents/10187/4238532/GWT_report_2015.pdf">https://vaadin.com/documents/10187/4238532/GWT_report_2015.pdf</a> 下載。
這個連結是在某個 G+ 上頭看到的,
目前 https:/vaadin.com/gwt 的連結還是指向 2013 的版本,
但是 <a href="https://vaadin.com/gwt/report-2015">https://vaadin.com/gwt/report-2015</a> 的東西似乎 ready 了?</p>
<p>這是在 2014 年作的調查,所以雖然 vaadin 是標注 2015 年,
我還是以 2014 為篇名。</p>
<p>基本上都只翻譯數據跟(個人認定的)重點,非逐句翻譯。</p>
<hr>
<h2 id="1-評價">1. 評價</h2>
<p>4.47 分(滿分 5 分)。</p>
<p>這是 1101 份投票的平均分數。有 82% 的人投了 4 分以上。</p>
<a href="http://blog.dontcareabout.us/2015/01/2014-gwt.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-10754163276548765212014-05-18T10:47:00.001+08:002014-05-18T10:48:43.846+08:00Sencha GXT 3.1 發布<p>作為 Sencha GXT 的團隊代表,我很高興宣佈 Sencha GXT 3.1 發布。在公開測試後只有一兩個月的時間,我們收到一卡車的回饋意見。我們已經解決幾個來自公開測試討論區的問題。感謝所有前期測試人員,你們的回饋意見始終是非常寶貴的。</p>
<p>GXT 3.1 導入了新的 Theme Builder(妝點 GXT 程式的新工具)、Neptune 這個佈景主題就是用 Theme Builder 做出來的;另外 GXT 3.1 也增加了對 GWT 2.6 的支援度。</p>
<p>(譯註:省略兩段純粹提供 3.1 各式連結的部份)</p>
<a href="http://blog.dontcareabout.us/2014/05/sencha-gxt-31.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-19316528365193271522014-05-16T08:07:00.001+08:002014-05-16T08:40:32.801+08:00HandlerManager 與兩個 event package<p>我大概是當完兵之後才開始用 <code>HandlerManager</code> 作 event bus,目的當然是降低耦合度。起手 reference 是 tkcn 的這篇《<a href="http://tkcnandy.blogspot.tw/2009/12/handlermanager-event-bus.html">利用 HandlerManager 實作共用的 Event Bus</a>》,然後一直以來就爽爽用,沒出啥問題、也沒想過會出問題。今天在 review 別人的 code 才知道有 <code>SimpleEventBus</code>,然後想知道這兩個到底有什麼差別、該用哪一個比較好?沒想到才剛打開 <code>HandlerManager</code> 的 source code,一開頭的 javadoc 就開始噴血:</p>
<blockquote>
<p>application developers are strongly discouraged from using a HandlerManager instance as a global event dispatch mechanism.</p>
</blockquote>
<p>WTF?不但不建議,而且是強烈不建議?GWT MVP 的文件都還是教用 <code>HandlerManager</code> 阿?</p>
<a href="http://blog.dontcareabout.us/2014/05/handlermanager-event-package.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-47281959818649901562014-05-11T23:50:00.001+08:002014-05-12T00:19:50.136+08:00GWT MVP part1<p>原文網址:<a href="http://www.gwtproject.org/articles/mvp-architecture.html">http://www.gwtproject.org/articles/mvp-architecture.html</a></p>
<p>建立大型 application 都有其障礙,GWT application 也不例外。多個開發人員同時在一份程式碼上作業、維護既有功能,可能短時間內就會讓程式碼一團混亂。為了解決這個問題,我們導入 design pattern 來將 project 劃分出不同的責任區。</p>
<p>有很多 design pattern 可以選擇,例如 Presentation-Abstraction-Control、Model-View-Controller、Model-View-Presenter…… 等等。雖然每個 pattern 有其優點,不過我們發現 Model-View-Presenter(以下簡稱 MVP)架構在開發 GWT application 的效果最好。有兩個主要的原因:首先,就像其他 design pattern,MVP 會降低開發行為的耦合度,這讓多個開發人員可以同時工作。再者,MVP 會盡可能降低 <a href="http://www.gwtproject.org/javadoc/latest/com/google/gwt/junit/client/GWTTestCase.html">GWTTestCase</a> 的使用度。GWTTestCase 會需要 browser,但是大多數程式碼只要輕量、快速、不需要 browser 的 JRE 測試。</p>
<p>這個 pattern 的核心是把功能分散到各個元件,這在邏輯上是有意義的。但在 GWT 中還有一個明確的重點,是讓 <a href="#View">View</a> 的部份盡可能簡單,以減輕對 GWTTestCase 的依賴、降低整體的測試時間。</p>
<p>一旦你瞭解這個 design pattern 的原理,那麼建立以 MVP 為基礎的 application 就會直覺又簡單。我們將用一個簡單的通訊錄系統為例子,協助你聊解這些概念。這個系統可以讓使用者增加、編輯、檢視存放在 server 上的聯絡人清單。</p>
<a href="http://blog.dontcareabout.us/2014/05/gwt-mvp-part1.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-20041170232510494242014-04-25T18:02:00.001+08:002014-04-25T18:11:45.676+08:00死法無法預測<p>原文網址:<a href="https://plumbr.eu/blog/you-cannot-predict-the-way-you-die">https://plumbr.eu/blog/you-cannot-predict-the-way-you-die</a></p>
<hr>
<p>在花了一天對付另一個 <a href="http://en.wikipedia.org/wiki/Heisenbug">Heisenbug</a>:每當我快抓到原因,它就會變了樣;我想我在這個 case 中學到的東西應該有分享的價值。</p>
<p>我寫了一個簡單的範例來展示這個狀況。在這個例子中,我建立一個 <code>Map</code> 然後用無窮迴圈往裡頭狂塞 key-value:</p>
<pre><code>class Wrapper {
public static void main(String args[]) throws Exception {
Map map = System.getProperties();
Random r = new Random();
while (true) {
map.put(r.nextInt(), "value");
}
}
}
</code></pre>
<a href="http://blog.dontcareabout.us/2014/04/blog-post.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-79578913776689771882014-04-24T10:46:00.001+08:002014-04-24T13:40:44.656+08:00外部 JS 呼叫 Java static method<p>內容有點無腦,先把結論寫在前面:</p>
<blockquote>
<p>外部 JS(官方文件稱為「handwritten JS」,其實不同 GWT Module 就滿足這個條件)要呼叫 Java 的 static method,必須先透過 JSNI 設定 <code>$wnd.methodName = @fooPackage.FooClass::javaMethodName(*)</code>,後續使用 <code>$wnd.methodName()</code> 來達到目的。</p>
<p>關鍵在於 JSNI 中:</p>
<ul>
<li><code>javaMethodName()</code> 後頭不需再加 <code>()</code>。</li>
<li><code>javaMethodName()</code> 的參數某些情況下可以省略 field descriptor,直接用 <code>*</code> 代替。</li>
</ul>
</blockquote>
<p>update:感謝 darkk6(ptt.cc)提醒,讓我發現我不但死腦筋,而且還少測了一種寫法… 所以文章就要重新翻修了 (艸</p>
<a href="http://blog.dontcareabout.us/2014/04/js-java-static-method.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-85322480532384199882014-04-05T23:28:00.001+08:002014-04-16T18:39:07.652+08:00NIO.2 的檔案操作<h3 id="前言">前言</h3>
<p>以往 Java 要操作檔案時,總得自己去面對 XXStream、XXReader、XXWriter,一不小心就迷失在 class hierarchy 迷宮中而搞不清楚到底該怎麼寫才好 [淚目]。NIO.2 的出現,提供了簡單好用的 method 來解決這些困擾。</p>
<p>這篇都還在 Java 7 的範圍。已經出的 Java 8 也對 NIO.2 做了一些改善,中文資料可先參考 <a href="http://ingramchen.io/blog/2014/04/java-8-new-api-tips.html">Ingram Chen blog</a> 的 File operation 章節。</p>
<a href="http://blog.dontcareabout.us/2014/04/nio2.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com1tag:blogger.com,1999:blog-2215604885338679329.post-63435149856465244412014-04-01T16:34:00.001+08:002014-04-16T18:40:06.923+08:00GWT RPC 的 deserialize 行為與 IE8<p>原文網址:<a href="http://blog.oio.de/2014/03/28/gwt-rpc-deserialization-vs-ie8/">http://blog.oio.de/2014/03/28/gwt-rpc-deserialization-vs-ie8/</a></p>
<hr>
<p>幾乎每個 web 開發人員都知道,當 JS 執行時間過久 browser 就會跳出討厭的對話框問你要不要取消。在 <a href="http://support.microsoft.com/kb/175500">IE 上頭</a>會顯示「這個網頁的指令碼造成 Internet Explorer 執行速度緩慢」。</p>
<p>這篇文章將說明 IE8 的特殊行為、它如何影響 GWT RPC 的 deserialize 機制、以及如何解決這些問題。</p>
<a href="http://blog.dontcareabout.us/2014/04/gwt-rpc-deserialize-ie8.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-18217981601903866732014-03-27T04:10:00.001+08:002014-04-16T18:40:52.467+08:00GC 對 throughput 與延遲時間的影響<p>原文網址:<a href="https://plumbr.eu/blog/gc-impact-on-throughput-and-latency">https://plumbr.eu/blog/gc-impact-on-throughput-and-latency</a></p>
<hr>
<p>有一類問題是每一個 Java application 都會遇到的,那就是 GC。當 GC 正常運作時,它是一個美妙的發明;當它沒有運作、或是 GC 用出乎意料的方式運作,那你的朋友就會翻臉變成仇人。</p>
<p>這篇文章是關於 GC 造成的暫停時間。或著更精確地說:為什麼你要在意這些暫停時間?</p>
<a href="http://blog.dontcareabout.us/2014/03/gc-throughput.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-30903649481500649742014-03-23T23:39:00.001+08:002014-04-16T18:41:20.498+08:00如何估算記憶體需求?<p>原文網址:<a href="https://plumbr.eu/blog/how-to-estimate-memory-consumption">https://plumbr.eu/blog/how-to-estimate-memory-consumption</a></p>
<p>這個故事得從十年前開始說起,那時我第一次接觸到一個<a href="http://en.wikipedia.org/wiki/Pointy-haired_Boss">尖頭老闆</a>的問題:「我們的產品要佈署的時候,需要買多好的 server?」在產品發表之後,我們花了九個月的時間打造了一個金光閃閃的新系統,顯然公司已經承諾要提供整個解決方案,包含硬體的部份。</p>
<p>囧… 我麻煩大了。我只有短短幾年的經驗,回答這問題跟丟骰子沒啥兩樣。雖然我看起來整個就是缺乏信心,不過我仍然得生出一個答案。在 google 了四個小時後,眼花撩亂的腦袋裡仍然是相同的問題:</p>
<blockquote>
<p>「如何估算所需的運算能力?」</p>
</blockquote>
<a href="http://blog.dontcareabout.us/2014/03/blog-post.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-72082947051506514432014-03-01T13:49:00.001+08:002014-04-16T18:44:01.392+08:00App Engine 1.9.0 上線<p>原文網址:<a href="http://googlecloudplatform.blogspot.tw/2014/02/app-engine-190-now-available.html">http://googlecloudplatform.blogspot.tw/2014/02/app-engine-190-now-available.html</a></p>
<hr>
<p>今天我們宣佈 <a href="http://developers.google.com/appengine/downloads">App Engine 1.9.0</a> 發布,包含 <a href="https://developers.google.com/appengine/docs/python/modules/">Modules API</a> general availability(GA)、新版 Java <a href="https://developers.google.com/appengine/docs/java/dataprocessing/">MapReduce</a> library、以及加強 PHP runtime。</p>
<a href="http://blog.dontcareabout.us/2014/03/app-engine-190.html#more">閱讀更多 »</a>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com0tag:blogger.com,1999:blog-2215604885338679329.post-89532279530656981312013-12-29T14:30:00.001+08:002013-12-29T14:56:21.672+08:00GWT 的 AutoBean<p><a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a> 是目前打算拿來在 GWT 中處理 JSON 的工具。
不過在講正事之前,先扯兩段雜談 [毆飛]</p>
<h2 id="雜談-這樣也可以">雜談 1:這樣也可以?</h2>
<p>要不是要弄 web API,其實也不會想碰 JSON,
GWT RPC 好好的幹麼弄什麼 JSON [遠目]。
不過 server side 要處理 JSON 其實有 <a href="https://code.google.com/p/google-gson/">GSON</a>,
正常 encode / decode 真的都還蠻簡單的,
簡單到不知道能介紹什麼 XD。
是說 LaPass(ptt.cc)因為有一個我覺得有點詭異的需求,
結果挖出了 <a href="http://www.ptt.cc/bbs/java/M.1384102985.A.AC0.html">TypeAdapterFactory 的用法</a>,
看起來真的很乾淨很炫(炫到都快看不懂了 [遮臉]),
只能說好 library 如當是也。</p>
<p>理所當然的,會想看看有沒有 GWT 版的 GSON,
結果看到 <a href="https://github.com/heroandtn3/bGwtGson">bGwtGson</a> 這玩意差點噴出來。
因為他的作法是用 GWT RPC 把東西丟到 server side,
這樣 server side 就有 <a href="https://code.google.com/p/google-gson/">GSON</a> 可以用了… 揪咪…</p>
<p>我都不知道該說牛逼還是坑爹,這世界果然很廣大阿 [握拳]</p>
<p>喔對,順帶一提,<a href="https://code.google.com/p/google-gson/">GSON</a> 在 AppEngine 上也可以使用。</p>
<h2 id="雜談-謎樣裏技">雜談 2:謎樣裏技?</h2>
<p>我搞不太懂 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a> 在 GWT 當中扮演什麼樣的角色?
彷彿還蠻多人在用的(因為大家都炸同樣的問題… Orz),
但是官方指南似乎沒有這個東西(JavaDoc 當然還是有),
教學文件只有出現在 google code 的 wiki 上,
所以這是裏技嗎?</p>
<p>我比較怕這是即將被拋棄的裏技 Orz</p>
<p>畢竟要在 GWT 裡頭處理 JSON 並不是太麻煩。
官方指南建議的 JSNI / Overlay Types 寫起來堪稱簡單直覺,
尤其是跟 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a> 相比的話 [死]。
再不然 <a href="https://github.com/nmorel/gwt-jackson">GWT-Jackson</a> 好像也是種選擇?</p>
<p>剛好兩者的風格我都不愛 [淚目]</p>
<p>最大的哏在於 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a> 並沒有辦法直接處理 <code>List<T></code> 這種東西,
<a href="https://code.google.com/p/google-web-toolkit/issues/detail?id=6904">這個 bug</a> 在 2011.10 被提出之後,
2012.11 最後一個 comment 之後就無聲無息了,
目前最新的 GWT 2.5.1 還是有同樣的問題 Zzzz,只能靠 workaround。
後頭會詳述這些事情 [死]。</p>
<h2 id="怎麼用">怎麼用?</h2>
<p>好了,終於要進入正題了。 [握拳]</p>
<p>GWT 已經內建 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a>,所以不用另外掛 jar 檔,
但是要在 <code>gwt.xml</code> 當中補上:</p>
<pre><code><inherits name="com.google.web.bindery.autobean.AutoBean"/>
</code></pre>
<p>如果你要把下面這個 JSON 字串轉成 <code>Foo</code> 的 instance</p>
<pre><code>{
"uid":"cde6c847-d072-4d33-82bd-93fa4710dc9b",
"limit":50,
"deleted":true,
"update":1388157386000
}
</code></pre>
<p>首先… <code>Foo</code> 得是個 bean 的 interface,定義一堆 getter/setter,
名稱得跟 JSON 裡頭的一致:</p>
<pre><code>interface Foo {
public void setUid(String uid);
public void setLimit(int limit);
public void setDeleted(boolean deleted);
public void setUpdate(Date update);
public String getUid();
public int getLimit();
public boolean isDeleted();
public Date getUpdate();
}
</code></pre>
<p>轉換的時候需要先建立一個 factory,通常會這樣寫</p>
<pre><code>interface MyFactory extends AutoBeanFactory {
AutoBean<Foo> foo();
}
MyFactory factory = GWT.create(MyFactory.class);
</code></pre>
<p>然後… 終於可以 decode 了:</p>
<pre><code>String foo = "{" +
"\"uid\":\"cde6c847-d072-4d33-82bd-93fa4710dc9b\"," +
"\"limit\":50," +
"\"deleted\":true," +
"\"update\":1388157380000" +
"}";
Foo instance = AutoBeanCodex.decode(factory, Foo.class, foo).as();
</code></pre>
<p>encode 的話就是:</p>
<pre><code>String fooJson = AutoBeanCodex.encode(
AutoBeanUtils.getAutoBean(instance)
).getPayload();
</code></pre>
<p>如果願意在 MyFactory 裡頭加一個 method:</p>
<pre><code>interface MyFactory extends AutoBeanFactory {
AutoBean<Foo> foo();
//下面這個是新增的
AutoBean<Foo> genFooBean(Foo foo);
}
</code></pre>
<p>那不用 <code>AutoBeanUtils.getAutoBean()</code> 而是</p>
<pre><code>String fooJson = AutoBeanCodex.encode(
factory.genFooBean(instance)
).getPayload();
</code></pre>
<p>有沒有比較快樂就見仁見智,不過後面會需要用到後面這招,
或著這麼說比較實在:
「請忘記 <code>AutoBeanUtils</code> 吧」。</p>
<h3 id="注意事項">注意事項</h3>
<p>如果到這邊你還能忍受 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a>,
那先講幾個我已經炸到,但可以理解的哏,
主要是跟 <a href="https://code.google.com/p/google-gson/">GSON</a> 的差異。</p>
<ol>
<li><p><code>Gson.toJson()</code> 遇到 false / null 值不會省略該 field,
但是 AutoBean 會。
也就是說,如果 <code>foo.setDeleted(false);</code>,
那麼 <code>AutoBeanCodex.encode()</code> 出來的字串不會看到 <code>deleted</code>。</p>
<p>當然,這其實不妨礙正常運作。
<a href="https://code.google.com/p/google-gson/">GSON</a> 的作法可能有些人還會覺得怪?</p></li>
<li><p>日期(<code>java.util.Date</code>)的處理。
<code>Gson.toJson()</code> 會用 <code>Date.toString()</code> 作值(反之亦然),
但是 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a> 則是用 <code>Date.getTime()</code>(反之亦然)。
只能說還是統統用 long 表示日期就算了
(然後在 JSON 當中最好還把這數字當成字串,
免得像 32bit 的 PHP 還給你耍花招 [怨念ing])。
至於 <a href="http://www.joda.org/joda-time/">Joda</a> 要解決的議題… 遇到再說 XD</p></li>
</ol>
<p>(<em>有遇到會再補上來 Orz</em>)</p>
<h2 id="list-的炸點"><code>List</code> 的炸點</h2>
<p>如果你永遠不會 decode / encode 一個 array 或是 <code>List</code>,
那恭喜你,除了寫法稍稍扭曲一點之外,
<a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a> 是可以接受、也算好用的(應該啦…)。</p>
<p>實際上… 別鬧了,怎麼可能不處理 <code>List</code>?</p>
<p>於是 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a> 就成了茶几──上頭擺滿了悲劇。</p>
<h3 id="decode">decode</h3>
<p>以 <a href="https://code.google.com/p/google-gson/">GSON</a> 吐出來的東西來看,一個 <code>List<Foo></code> 的 instance 會長這樣
(喔對,我把 <code>update</code> 的型態改成 long 了 XD):</p>
<pre><code>[
{"uid":"cde6c847-d072-4d33-82bd-93fa4710dc9b",
"limit":50,"deleted":false,"update":"1388157380000"},
{"uid":"a391dedf-1f81-4380-a712-59eac4d9aea3",
"limit":50,"deleted":false,"update":"1388157380000"}
]
</code></pre>
<p>想依樣畫葫蘆比照辦理時…
等等,<code>AutoBeanCodex.decode()</code> 的第二個參數要給什麼?
然後於是有人弄出了這個 <a href="http://stackoverflow.com/questions/13651068/gwt-autobean-how-to-handle-lists">workaround</a>。</p>
<p>首先,要建一個 interface 來代表 <code>List<Foo></code> 這玩意:</p>
<pre><code>interface FooList {
public void setList(List<Foo> list);
public List<Foo> getList();
}
</code></pre>
<p>factory 的 interface 則是:</p>
<pre><code>interface MyFactory extends AutoBeanFactory {
//下面這個暫時用不到
AutoBean<Foo> genFooBean(Foo foo);
AutoBean<FooList> fooList();
}
</code></pre>
<p>最後,要對拿到的 JSON 字串動手腳,變成這樣:</p>
<pre><code> FooList fooList = AutoBeanCodex.decode(
factory, FooList.class, "{\"list\":" + foo + "}"
).as();
List<Foo> instance = fooList.getList();
</code></pre>
<p>簡單地說,就是 Java 的部份你要讓他有個 class 為依歸,
但是光這樣還不夠,因為 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a> 不知道要從何處理起,
所以 JSON 的部份你也要偽造一下……</p>
<p>等等,還沒完,好戲壓箱底、好酒沈甕底,
encode 的部份那才叫經典。</p><div class="se-section-delimiter"></div>
<h3 id="encode">encode</h3>
<p>要把一個 <code>List<Foo></code> 轉成 JSON,這到底是有多難?
不難,如果把剛剛 <code>AutoBeanCode.decode()</code> 出來的 <code>fooList</code> 再次轉成 JSON,
那麼只要 factory 加上</p>
<pre><code>interface MyFactory extends AutoBeanFactory {
//下面這個暫時用不到
AutoBean<Foo> genFooBean(Foo foo);
AutoBean<FooList> fooList();
//下面這個是新增的
AutoBean<FooList> genFooListBean(FooList instance);
}
</code></pre>
<p>立馬就轉,沒有問題!(也完全沒意義 ==”)</p>
<pre><code>AutoBeanCodex.encode(
factory.genFooListBean(fooList)
).getPayload();
</code></pre>
<p>如果是把既有的 <code>List<Foo></code> instance 轉換,
依照上面的邏輯,得先實做那個毫無意義的 <code>FooList</code>:</p>
<pre><code>FooList fooList = new FooList() {
List<Foo> list = new ArrayList<Foo>();
@Override
public void setList(List<Foo> list) {
this.list = list;
}
@Override
public List<Foo> getList() {
return list;
}
};
//FooImpl 就容許我跳過,反正就是 implements Foo 的東東
fooList.getList().add(new FooImpl());
AutoBeanCodex.encode(
factory.genFooListBean(fooList)
).getPayload();
</code></pre>
<p>執行上面這段程式碼,你就會發現 <code>AutoBeanCodex.encode()</code>
快樂的炸了 NPE,而且完全搞不懂發生了什麼事情。</p>
<p>這是個已知的 bug(<a href="https://code.google.com/p/google-web-toolkit/issues/detail?id=6904">Issue 6904</a>),
雖然不知道會不會有人去解…… Orz。
而世界還真的是很廣大,有人也找出了 <a href="https://groups.google.com/d/msg/google-web-toolkit/nvIotNHy-Io/GkXz_WQXvR4J">workaround</a>,
解法就是你不能直接丟 <code>FooImpl</code> 的 instance,
得用 <code>MyFactory.genFooBean()</code> 產生出 <code>AutoBean<Foo></code>,
再藉由它(<code>as()</code>)取得 <code>Foo</code> 的 instance 才可以……
寫的我自己都亂了,看 code 比較實在:</p>
<pre><code>interface MyFactory extends AutoBeanFactory {
AutoBean<Foo> genFooBean(Foo foo);
AutoBean<FooList> fooList();
AutoBean<FooList> genFooListBean(FooList instance);
}
fooList.getList().add(
//原本是 new FooImpl()
factory.genFooBean(new FooImpl()).as()
);
AutoBeanCodex.encode(
factory.genFooListBean(fooList)
).getPayload();
</code></pre>
<p>套最近流行的句型:
「如果這不叫脫褲子放屁,我還真他媽的不知道什麼才叫脫褲子放屁」</p>
<p>喔對,無論 <code>genFooBean()</code> 還是 <code>genFooListBean()</code>
都不能用官方文件用的 <code>AutoBeanUtils.getAutoBean()</code>。
如果拿他替換 <code>genFooBean()</code>,一樣噴 NPE;
如果拿它替話 <code>genFooListBean()</code>,不會噴 NPE,
而是轉換出來的 JSON 字串會是 null。</p>
<p>WTF</p>
<h2 id="結尾-murmur">結尾 murmur</h2>
<p>拿 <a href="https://code.google.com/p/google-gson/">GSON</a> 跟 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a> 相比是很有趣的。
一個是完美到不需要瞭解內部到底發生什麼事情,
一個則是太糟糕了,所以根本不想瞭解。</p>
<p>短時間之內,我可能還是不會放棄 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a>,
除非 GWT 2.6 就遺棄 <a href="https://code.google.com/p/google-web-toolkit/wiki/AutoBean">AutoBean</a>,
或是找到更好的 tool(而不是 <a href="https://github.com/nmorel/gwt-jackson">GWT-Jackson</a> 那種 style)。
都花了這麼多時間了,就看看能<strike>被炸到</strike>走到什麼程度。</p>
<p>寫到後來,都不知道到底是在介紹推廣還是在吐槽。
只能說,嗯… 我對 GWT 真的很有愛…… [遠目]</p>痞子軍團科技部http://www.blogger.com/profile/10336542764248305637noreply@blogger.com1