-
Notifications
You must be signed in to change notification settings - Fork 0
/
search.xml
380 lines (380 loc) · 146 KB
/
search.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
<?xml version="1.0" encoding="utf-8"?>
<search>
<entry>
<title><![CDATA[“放码过来!作个Java实战派”Udemy良心课程免费放送!]]></title>
<url>%2FUdemy-Free-Course-Show-Me-the-Code-Java-Warrior-Part-I-Released%2F</url>
<content type="text"><![CDATA[昨天,我把“放码过来!作个Java实战派”课程在Udemy上面设为永久免费,也将对应课程放到了YouTube对应频道Java Never Sleep,欢迎访问和订阅!这是一款深度广度胜过N多收费课程的良心课程,您要觉得我在自吹自擂,请听我细细道来。 这门课程的特点在于并不追求所有知识点的完整罗列,而是基于28原则,集中发力于最常用的工作技能,并对部分内容进行深入展开。辅以高强度的编程练习,覆盖其他需要的知识点。 比如当我阐述面向对象概念时,我并不直接引入复杂概念,而是先从一个小游戏开始: 比如我在讲解常用数据结构时,从一个待解决的问题“双城记词频统计问题”入手,逐个引入不同集合,并说明其使用场景。最后,我对集合类库进行完整的梳理,通过实时生成的类图对其结构一览无余。 以序章为例,恐怕我是极少数直接使用JShell进行Hello World讲解的特例,实际上,从JDK9引入JShell之后,很多人对这一工具所带来的便利还有基本认识。所以,在“首次Hello World”中,其安排是这样的: 终于,我们开始安装JDK(12.0.1)、编写Hello World。在JDK12中,我们优先通过JShell运行Hello World,当然,我们也介绍古典Hello World的编写、编译、运行三部曲。 然后为了说明以JVM为核心的Java生态系统思想,我对Hello World也进行了再次跟进,甚至包括一个基于Kotlin的Hello World。 我们继续Hello World:我们介绍手工编译运行时需要注意的细节、自JDK 11之后引入的直接运行Single Source、在其他操作系统上运行Hello World、用JVM系编程语言之一的Kotlin来Hello World、用Eclipse编译器来Hello World。一沙一世界,我们后面还要三番四次Hello World,因为它绝不如大家看到、想象的那般简单。 好了,Talk is Cheap,您前去观看,自有分晓。如果您对这款课程有任何疑问或反馈意见,都可以通过本站各种联系方式骚扰我。如果您觉得课程不错,记得给我来个好评😅 此外,我在Udemy上面也发布了一款项目开发驱动的课程“放码过来!新版Java坦克大战”,您可以通过折扣码JAVANEVERSLEEP享受限时2折优惠,别错过时间了哈😁]]></content>
<categories>
<category>Udemy教程</category>
</categories>
<tags>
<tag>Udemy</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Java Never Sleep Launched!]]></title>
<url>%2FJava-Never-Sleep-Launched%2F</url>
<content type="text"><![CDATA[It has been 2 months since I launched my personal blogger “Old Young Boys Club”, I wrote about Soccer, Joke, and Java here. I also published them to Facebook, Twitter, LinkedIn, and Reddit. Some of them attracted readers more than I expected, some of them, though I wrote with much effort and dedication, just keep silent:) Now I made a decision to focus on Java stuff mainly and will update regularly at another blogger: Java Never Sleep! It’s about Java and only about Java. Welcome, my friend! In the beginning of this year 2019, I setup a goal to build the best Java tutorial in the web for beginners. Sounds crazy but this goal drove me a lot and I got to know many new stuff I didn’t know previously. Since I’m teaching 12 students at Olivet Insititute of Technology, I hope to summarize what I’ve learned in the past and finalize all materials well. And very immediately 30 days passed, looking back on the past 30 days, I can honestly say that I didn’t waste too much time, though sometimes I really felt powerless to continue. But stick to the goal till the end is something I firmly believe, so I will try my best to achieve my goal. Java Never Sleep. Me not, me need sleep and actually sleep. However, my goal won’t sleep, my passion won’t and my prayer won’t.]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Blogger</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Yet Another Top 10 Books For Java Learners - Part I]]></title>
<url>%2FYet-Another-Top-10-Books-For-Java-Learners%2F</url>
<content type="text"><![CDATA[Honestly speaking, there is no need to post an article on the topic “Top 10 Books For Java Learners”, which is possibly older than your age. I do this for the 12 students I’m teaching Java programming language recently, I’d like to summarize a book list of 10 for their reference. I don’t want to recommend books said to be great but I never read, so some of the books listed here maybe not that famous or popular, but at least they are good to me and helped me a lot in the past. No.1 MOOC By University of HelsinkiYes, I’m joking and I’m not joking. From my own experience, I don’t think it’s the most efficient way to read a book systematically when you are pure beginners - especially if you never write code before. What you need to do is to understand the basic concepts quickly first, then JUST DO IT! Keep practicing, keep practicing and keep practicing. Object-Oriented Programming with Java Part I and Part II. Register an account at Test My Code. Finish all the exercises there. Post a screenshot to prove you really did it. That’s all. Most of the students give positive feedback regarding the exercises. There is one Easter Egg in one of the test cases waiting for you to find there. Trust me, stick to the end and you won’t miss it. Wait…but this is obviously not a book, right? Yeah, right, but so what? For beginners, this would be the best resource for a quick start and get your hands dirty. Talk is cheap, show me the code! No.2 Refactoring: Improving the Design of Existing CodeAfter you get your hands dirty for a long time and write enough code like shit, this book written by Martin Fowler is worthy to read thoroughly and practice the methods introduced one by one. Refactoring: Improving the Design of Existing Code has two editions, though the 2nd Edition is available with many updates, I would personally suggest you read the 1st Edition since you are a Java learner. I always recommend this book to other programmers, as it had a great impact on my career. I was promoted to Team Leader in my first company because I finished refactoring against a module nobody wants to do - too painful and too brain-hurt. I found this book by chance in the bookshelf one afternoon, and I’m addicted to it and I just finished reading this book very quickly and used several methods there, and from that time on I began to write fully covered unit tests for my code, which made my life and our colleagues’ life much easier. No.3 Effective JavaJoshua Bloch, the guy who designed and implemented Java Collection Framework(of course not himself alone), released the 3rd Edition of this book. For me, I actually read the Chinese translation of the 2nd Edition, which is very impressive. This is a book more like a master telling his experience, insights, best practices to you, rather than a textbook. This book, like its title, is really “Effective”. No.4 Head First Design Patterns“Design Patterns: Elements of Reusable Object-Oriented Software” by GoF is said to be “Classic, Awesome…” and blahblah. However, I didn’t read this legendary book, because I am too low to enjoy another funny book: Head First Design Patterns. All the source code of this book can be accessed at GitHub. Life is short and I don’t want to waste too much time arguing which book is better or not. What I know is if you just want to read one book about Design Patterns in Java, then choose this one and you won’t regret. No.5 Clean Code: A Handbook of Agile Software CraftsmanshipClean Code by Uncle Bob, IMHO, is not that practical and useful to me compared to the books listed above. But it’s a good summary and provides more information which can enhance you still, besides that, this book is very interesting and it’s a joyful read. When Uncle Bob said that he “turned on his old TV and tried to watch some scaring movies, but there is not even one ghost there. Sh.t!”, I just laughed to the ground. Anyway, for those who really care about quality, cleanness of your code, this book is a must-read. -To Be Continued- amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "true"; amzn_assoc_tracking_id = "javaneversleep-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "b2d7aa2b3289e841ea7dae7b785b8767"; amzn_assoc_asins = "0201485672,0134685997,0596007124,0132350882";]]></content>
<categories>
<category>Great Books</category>
</categories>
<tags>
<tag>Awesome Books</tag>
</tags>
</entry>
<entry>
<title><![CDATA[A Simple Tank War Game Exercise for Java Beginners]]></title>
<url>%2FA-Simple-Tank-War-Game-Exercise-for-Java-Beginners%2F</url>
<content type="text"><![CDATA[I’ve just published a mid-term project for a small group of students. If you are a Java beginner who is seeking some challenge to conquer, I believe this Tank War game would be fit for you. Wanna a try?😄 Solution for your reference will be released after 3 weeks. I wrote my first line of Java code, the awesome “Hello World” at 26. It was 2009 and life is really tough for me, all my hope is to finish the coding camp program as soon as possible and start working as a programmer to earn some livings. This little game was the final project of JavaSE course and I just cannot figure out it myself, only by following the instructor’s patient explanations I can catch up with what he is actually doing at that time. I don’t remember how many hours I spent on this little, stupid, and boring game, but I would never forget this painful experience. And this time, when I told the students that they need to finish this in 3 weeks, half of them silenced, I know that feeling very well - they have no idea what to do, just like me 10 years ago. Maybe they don’t know, less than 450 lines of code will be sufficient for the implementations. Unreasonable fear would just make you ignoring many obvious and clear facts. One would easily choose “Game Over”, and rarely press F2 to restart. At that time, I was upset, depressed and anxious, but with patience and sweat, I finally finished the 3 months program and fortunately found a job to begin my career as a programmer. 10 years later, it has been very clear to me that I don’t have much talent in this area, but it doesn’t mean that I cannot leverage my skills to make a difference and help others - which I’ve actually done these years. Yes, not everyone can be a great programmer, but everyone can be a programmer and make a difference - if they really want and devote themselves to it. Set up a challenging goal, and achieve it by all means - I firmly believe this is the most efficient way to improve your programming skills. So do not fear, do not hesitate. And, JUST DO IT! amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "de429ade981a7c8fe5027e941b980ae1"; amzn_assoc_asins = "B00TFAET2G,0134685997,0134757599,020161622X";]]></content>
<categories>
<category>Projects</category>
</categories>
<tags>
<tag>Tank War</tag>
</tags>
</entry>
<entry>
<title><![CDATA[7 Tips of Searching GitHub Repositories You Should Know]]></title>
<url>%2F7-Tips-of-Searching-Github-Repositories-You-Should-Know%2F</url>
<content type="text"><![CDATA[You search on Google every day, and as a programmer, you would probably search on GitHub every day. Are you sure you know how to search GitHub repositories effectively? Let’s check out these 7 tips you probably didn’t know. 1. In Name, In Description, and In READMEGitHub supports advance search in a certain field, like repository title, description, and README. For example, you want to find some cool repository to learn Spring Cloud stuff, you can search like this: in:name spring cloud In the same way, you can also search in description or README only: in:description spring cloudin:readme spring cloud 2. More Stars, More ForksStars of a repository would provide information on how popular it is, which is an important metrics in consideration, as a result, you can search like this: stars:>=3000 spring cloud You can also define a range like this: forks:10..20 spring cloud 3. Small Repositories PleaseDinosaur repositories are not what you want, you love those simple, small and smart repositories only, you can add this search term: size:<=5000 spring cloud Unit of size here is KB, so 5000 means 5MB. 4. Actively Maintained Repositories PleaseMost of the time you don’t want to rely on a project that didn’t update for 7 years, actively maintained projects would give you more confidence, thus you need to introduce last push time in your search term. For example, you want to search those projects have updates in the last two weeks: pushed:>2019-01-04 spring cloud You may also search repositories created before or after a certain time using created rather than push. 5. Apache License PleaseLicense of open source projects might bring you much trouble, you remember Facebook and React, right? If you want to search projects friendly licensed, for example, the well known Apache License 2, you would search like this: license:apache-2.0 spring cloud Of course, you can hunt other licenses also, just search in the complete list provided by GitHub and choose the one you love. 6. Java Onlylanguage:java will filter repositories not written in Java, yeah! If you hate Java then replace it with the one you love, for example, the best programming language PHP. 7. Rock Star OnlyYou may just want to search repositories by a Rock Star or a well-known organization because they are more likely awesome, just include user in your search term like this: user:joshlong spring cloudorg:spring-cloud spring cloud Obviously, you can combine the 7 tips together for more complex search, for example: user:joshlong language:java pushed:>2018-03-04 stars:>200 in:description spring boot More Options to ExploreWant to explore all possible search terms? Just play around with “Advanced Search” or read the “search help” by GitHub, the time you spent there will be definitely worthy. Happy Hunting! PS: If you are a Chinese reader you would like to read the original version by Shucheng Hou at here. My post is a simplified and slightly modified English version actually. amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "true"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_search_bar_position = "bottom"; amzn_assoc_ad_mode = "search"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_default_search_phrase = "GitHub"; amzn_assoc_default_category = "All"; amzn_assoc_linkid = "3e67b5f3d8c58758abe55ca413b6ada4";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>GitHub</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Farewell: Brothers and Sisters]]></title>
<url>%2FFarewell-Brothers-and-Sisters%2F</url>
<content type="text"><![CDATA[11 brothers and sisters departed for China in the past two weeks, and today I just found my heart was emptied and filled with sadness. After living and working together for about 4 years, remembering the happy and hard days we experienced together, it’s just overwhelming and I had to pray a lot both for them and for myself. They went back to China to fulfill their commission and it would be not that sad as our Father God will be with them, but we are just mankind and always emotional, at this time, I would pray that their sacrifice and commitment be pleased by God, and may our shepherd guide their way in the future as always. Months ago, I heard that an old Pastor said something like this, “don’t bring them to me again, as after they gone back, my heart was emptied and could not stand. They are like daughters to me and the time with them is too happy that I cannot bear the time when I have to say goodbye to them”. And today I just have similar feelings, even though I am not a man focusing on relationship much. It’s a community of love in God’s 3 persons, the Father, the Son, and the Spirit. If love is something connected so deeply, then how sad it would be, when the Father had to abandon the Son, when the Son had to be abandoned by the Father as an atonement? What kind of pain and bitterness would it be for Heavenly Father, when Lord Jesus was crucified? Farewell, my brothers and sisters, “your labour is not in vain in the Lord”.]]></content>
<categories>
<category>Life</category>
</categories>
<tags>
<tag>KBers</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Fibonacci and BigInteger: Secret Under the Hood]]></title>
<url>%2FFibonacci-and-BigInteger%2F</url>
<content type="text"><![CDATA[No matter what programming language you are learning, Fibonacci numbers calculation is just too classic to skip. It seems very easy to implement, but also can be deep enough to catch up with, especially when the number is super big. Have you thought that ever before? It can be super easy to implement using recursion in just one line of code, even using Java.😅 123int fib(int n) { return n <= 2 ? 1 : (fib(n - 1) + fib(n - 2));} And to make you understand the basic optimization idea, monetization mechanism will be introduced via an integer array or a HashMap, but the idea is same: calculate once and only once, so that those poor rabbits would feel life much easier. Add just one more line of code and thanks to the Lambdas feature provided since JDK8, life is much easier nowadays. 12345private static Map<Integer, Integer> CACHE = new HashMap<>();int fib(int n) { return CACHE.computeIfAbsent(n, k -> (k <= 2 ? 1 : (fib(k - 1) + fib(k - 2))));} There is always someone scared of the famous StackOverflowError, they would tell you not to use recursion but do an iterative way, like this: 12345678910int fib(int n) { if (n <= 2) return 1; int[] cache = new int[n]; cache[0] = cache[1] = 1; for (int i = 2; i < n; i++) { cache[i] = cache[i - 1] + cache[i - 2]; } return cache[n - 1];} Obviously, the integer array can be avoided, you can just keep three values and update them till the end, but that’s not the problem we want to discuss here. You would have probably found that it’s very easy for the result to be much bigger than the upper limit of int, long, double. For example, if we input n as 2048, what will be the exact result then? 454153044374378942504557144629068920270090826129364442895118239027897145250928343568434971 803477173043320774207501029966396250064078380187973638077418159157949680694899576625922604 895968605634843621876639428348247300097930657521757592440815188064651826480022197557589955 655164820646173515138267042115173436029259905997102292769397103720814141099147144935820441 85153918055170241694035610145547104337536614028338983073680262684101 It’s 4.54 * 10^427. As for Java, for this kind of problem, you have no other choice but BigInteger, and it’s very easy touse. 12345private static Map<Integer, BigInteger> CACHE = new HashMap<>();BigInteger fib(int n) { return CACHE.computeIfAbsent(n, k -> (k <= 2 ? BigInteger.ONE : (fib(k - 1).add(fib(k - 2)))));} Congratulations! You will get a BOMB exploding like this:123Exception in thread "main" java.lang.StackOverflowError at java.util.HashMap.hash(HashMap.java:339) at java.util.HashMap.computeIfAbsent(HashMap.java:1099) You may use -Xss4m to shut it up, or resolve it in an iterative way a little bit optimized, wherein we won’t waste space to build an array. Yes, it’s right, recursion is easy to think of and implement, but it’s just too close to StackOverflowError. 123456789101112BigInteger fib(int n) { if (n <= 2) return BigInteger.ONE; BigInteger prev = BigInteger.ONE, prevOfPrev = BigInteger.ONE; BigInteger curr = null; for (int i = 2; i < n; i++) { curr = prev.add(prevOfPrev); prevOfPrev = prev; prev = curr; } return curr;} BigInteger, what’s the secret behind it that it can represent a number beyond the upper limit of all primitive data types of Java? The idea is still simple, but the implementation can be complex, especially when highly optimized is a must. bigint in Github would give you more information on how Timothy Buktu approaches and optimizes it. There is a famous quote in The Lord of The Rings by Sam, “I can’t carry it for you, but I can carry you”, as for BigInteger, it seems should be “I can’t carry it for you, and I can’t carry you, but I can carry a segment of you.”😅 Yes, the whole number is too big, but if we split it into many parts, then we will find each part might be within the upper limit, if we store each of them in an array, and perform the calculation in binary level, also handle the carrying part well, then a container to store a big number will be possible. Pretty cool and smart, right? But what exactly is under the hood? Let’s check it out in the next post. TO BE CONTINUED amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "21ce171baf5d871f0872d552bc2cbace"; amzn_assoc_asins = "0805063056,B0015DWM2K,0767908163,1590787528";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Java Never Sleep</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Sqlite, Monastery and St. Benedict: Code Of Ethics]]></title>
<url>%2FSqlite-And-Monastery-Code-Of-Ethics%2F</url>
<content type="text"><![CDATA[We will begin from an interesting comment in the source code of SQLite, and end with Monastery, Saint Benedict, and Code of Ethics. I am not joking, seriously. I started using SQLite for my Java desktop application in 2014 and found it’s really good, its query performance, full-text search support made my development experience smooth and joyful. Import 800M entries from thousands of files into SQLite database in minutes, then query entries in milliseconds, which is really impressive. Besides my personal experience, almost every smartphone is using it every day. Since it’s so widely used, as a programmer you will get into troubles soon, even though they have nothing to do with you. Read the comments and you would probably laugh with tears:😅 2006-10-31: The default prefix used to be “sqlite_”. But then Mcafee started using SQLite in their anti-virus product and it started putting files with the “sqlite” name in the c:/temp folder. This annoyed many windows users. Those users would then do a Google search for “sqlite”, find the telephone numbers of the developers and call to wake them up at night and complain. For this reason, the default name prefix is changed to be “sqlite” spelled backwards. So the temp files are still identified, but anybody smart enough to figure out the code is also likely smart enough to know that calling the developer will not help get rid of the file. So the prefix now is etilqs_, and the programmer would sleep peacefully finally. If you scroll up to the top of the file os.h, you will meet several lines of comments which will definitely surprise you - at least I was really surprised. 2001 September 16 The author disclaims copyright to this source code. In place of a legal notice, here is a blessing: May you do good and not evil. May you find forgiveness for yourself and forgive others. May you share freely, never taking more than you give. The date has a special meaning as it’s immediately after 911 accident, during a interview with Richard Hipp, the original creator of SQLite, talked about the inspiration behind that: Interviewer: […] Who or what inspired you to write that? Richard Hipp: People customarily put a copyright notice at the top of each source file. But SQLite version 2.0.0 had no copyright so I had to think of something else to go in that space. The second sentence, “May you find forgiveness for yourself and forgive others”, is a loose interpretation of Matthew 6:12, part of what is commonly called ‘The Lord’s Prayer’ and more recognizable as ‘Forgive us our debts as we forgive our debtors’. The third sentence tries to capture the concept of paying debts forward. The ‘never take more than you give’ part is a paraphrase of one of the lyrics from The Lion King. The first (hokey) sentence is there because it seemed like a good benediction needed three sentences. It sounds like a Pastor preaching to you, or a monk in monastery reading scriptures to you, right? Yes, you are right. There is actually a connection between SQLite and Monastery, and The Rule of St. Benedict, read the “Code Of Ethics“ and you will understand the spiritual inspiration then. The founder of SQLite, and all of the current developers at the time when this document was composed, have pledged to govern their interactions with each other, with their clients, and with the larger SQLite user community in accordance with the “instruments of good works” from chapter 4 of The Rule of St. Benedict (hereafter: “The Rule”). This code of ethics has proven its mettle in thousands of diverse communities for over 1,500 years and has served as a baseline for many civil law codes since the time of Charlemagne. In a post-modern world that rejects absolute truth so obviously and satirizes religion, especially Christianity, how would programmers with a different worldview respond to this? And what shall be the scope of this application? It also gives an eclectic statement so that code will be separated from religion, as it should be. No one is required to follow The Rule, to know The Rule, or even to think that The Rule is a good idea. The Founder of SQLite believes that anyone who follows The Rule will live a happier and more productive life, but individuals are free to dispute or ignore that advice if they wish. The founder of SQLite and all current developers have pledged to follow spirit of The Rule to the best of their ability. They view The Rule as their promise to all SQLite users of how the developers are expected to behave in community. This is a one-way promise, or covenant. In other words, the developers are saying: “We will treat you this way regardless of how you treat us.” While code itself should be separated from religious belief, the man who wrote the code needs not and probably cannot. Just like Soli deo gloria has been found at the end of manuscripts by masters like G. F. Handel, J.S. Bach and etc, for me, it’s surprising but also joyful to know that the invisible impact of Gospel in the IT world, it’s not only about code that would be cold, but also about code of life, the rules of love that is warm and truthful. amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "e0b9b0fe194fce20f484b857c041ae77"; amzn_assoc_asins = "0596009763,1980293074,162164149X,149225178X";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>SQLite</tag>
</tags>
</entry>
<entry>
<title><![CDATA[NetBeans 10 Released: The Best Swing GUI Builder You Should Try]]></title>
<url>%2FNetBeans-10-Released-The-Best-Swing-GUI-Builder-You-Should-Try%2F</url>
<content type="text"><![CDATA[As a Java guy now I use IDEA most of the time, I’ve been using eclipse for about 6 years in the past but now I rarely open it. However, I still use NetBeans when I need to do some Swing stuff, as it provides the best GUI builder user experience in my perspective. From Sun to Oracle, now moving to Apache, after a long time of silence, Apache Netbeans 10.0 was released on Dec 27th, 2018. Wanna get a try, man? Besides Netbeans there is another distribution called CoolBeans, I first got to know this from Hacker News Show, which is a good marketplace to know the latest new stuff from programmers who want to present and promote their work. I would highly recommend you visit there regularly. Yesterday night I tried both NetBeans and CoolBeans, it’s similar to that of NetBeans 8.2, which I used for Swing GUI stuff. There is Window Builder for eclipse and IDEA ships GUI Designer itself, I actually tried them both at 2014 and 2016, and still, I found NetBeans is the best in this area. Nowadays the hot topic is cloud, apps, web and machine learning, desktop application is something you probably would never touch. As for me, in the first 3 years as a Java programmer I focused on JavaEE stuff, only when I started working for a start-up company at 2014, I have to build a desktop application to be deployed to thousands of clients. I never did that before but I managed to release the first usable version in 3 weeks, it would be impossible without Netbeans. From 2016 I started using JavaFX to build certain GUI applications, but in my personal experience I still prefer Swing - sounds strange, right? I will explain why in the future. Meanwhile, PyQT and WxPython in the Python community, Electron in Javascript community is also good stuff worthy to try. Once I played around with Electron and it would save you a lot of time as it will reuse your web development skills. I plan to summarize and share some of my Swing work to you guys in Github recently. Hope you guys enjoy! amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_asins = "B007Y6KIHI,1118385349,1617292842,0134393333"; amzn_assoc_linkid = "5e73b1f765df95a34faf76f5c40b63d0";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>NetBeans</tag>
</tags>
</entry>
<entry>
<title><![CDATA[The Best Java Tutorial You Shall Not Miss at Easter 2019]]></title>
<url>%2FThe-Best-Java-Tutorial-You-Shall-Not-Miss%2F</url>
<content type="text"><![CDATA[The end of 2018 is close and it’s time to set up goals of 2019. As for me, it’s super clear - I want to make the best Java tutorial for beginners. Texts, videos, exercises will be prepared carefully, precisely covering the most important topics of Java programming based on market research. I will leverage my 10 years experience in software engineering to make your learning experience friendly, funny, and challenging. Remember, it will be released at Easter, 2019. I dare to share this goal publicly, shamelessly due to these reasons: Shout out your goal as loud as you can, so that your friends will know this and ask you about progress, which will force you to push forward if you still know what shame is; Teaching will always help you learn faster and better, there will never be an end in programming learning, even though you have worked for about 10 years. I plan to summarize Java programming completely, systematically this time and also learn new stuff that I didn’t have time to catch up with last year; I’ve taught SE500 course at OIT twice but I didn’t build it into a product that can be reused by students in the future. It’s a pity that my experience cannot benefit them the most, and I want to improve it this time; Compared to best selling Java courses at popular platforms such as Udemy, Lynda, and etc, my tutorial will be more user-friendly, funny while challenging. You might be surprised that a tutorial aiming at beginners will be described as “challenging”, but I firmly believe that reasonable challenges will make learners apply what they have learned in the shortest time; Being a teacher means you have a lot of opportunities to touch many different students, which can also inspire and improve myself. Besides that, you can also make many new friends in the future, which is pretty exciting. So here I am. Will I keep my word and promise, or am I just joking? Let’s check it out at Easter 2019. It’s not shameful to fail, but it’s shameful to fear. PS: Got tired? Read these books and you will definitely be inspired and motivated. Not everyone can be great programmer, but everyone can be a programmer, and make a difference. amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "234ebf5a711b24c888ee32618d2535d3"; amzn_assoc_asins = "1501124021,B00J5X5E9U,0812972155,B004W2UBYW";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Tutorial</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Merry Christmas: For to Us a Son Is Given]]></title>
<url>%2FMerry-Christmas%2F</url>
<content type="text"><![CDATA[Just came home from GNIT SF monthly gathering and I was deeply grateful for the community life. This Christmas has some special meaning to me and very likely I will always remember it. Kaka, possibly the most godly soccer player I’ve ever known, published a tweet yesterday night and I saw it this morning. "Porque um menino nos nasceu, um filho nos foi dado, e o governo está sobre os seus ombros. E ele será chamado Maravilhoso, Conselheiro, Deus Poderoso, Pai Eterno, Príncipe da Paz" Isaías 9:6 #FelizNatal https://t.co/YzMHrIyZaO— Kaka (@KAKA) December 25, 2018 After translating it from Portuguese to English, I determined the scriptures that I would use for the intecessory prayer of the Christmas Service in our church. “For to us a child is born, to us a son is given,and the government will be on his shoulders.And he will be called Wonderful Counselor, Mighty God,Everlasting Father, Prince of Peace.Of the greatness of his government and peace there will be no end.He will reign on David’s throne and over his kingdom,establishing and upholding it with justice and righteousnessfrom that time on and forever.The zeal of the Lord Almighty will accomplish this.” Book of Isaiah, 9:6-7 God kept His word and promise to His people, He sent His only begotten son to this world at that very Christmas. Today, will you keep your word and promise to God, if there is any?]]></content>
<categories>
<category>Life</category>
</categories>
<tags>
<tag>Christmas</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Percolation, Predestination, and Freewill]]></title>
<url>%2FPercolation-Predestination-Freewill%2F</url>
<content type="text"><![CDATA[Yeah, I just finished week 1 assignment of Algorithms, Part I about percolation, but why the hack this post trying to talk about Predestination and Freewill, a religious topic that would be super boring? OK. Calm down, calm down and watch this video first, my friend. It’s a silent film lasts only 20 seconds. In the Christmas retreat held on last Saturday, Pastor Peter Tzeng from SF Gratia Presbyterian Church preached a sermon about “Predestination and Election”, which suddenly reminded me of the programming assignment I just finished. My heart was filled with peace, gratitude, and grace at that time. It’s really grateful to be part of a church, as you will never walk alone. Let’s go back to the test case which I wrote a special test program ShuffledPercolationVisualizer to simulate the process. The video you have just watched was also recorded at that time. This test case, with a matrix of 60 * 60, initialized 3600 sites blocked(marked black), then you can choose to select some of them and marked white, which was called “to open a site”. Meanwhile, if there is a connection between opened sites to any open site in the top row, all the sites involved in the connection will be marked blue. There are 2408 opened sites, and when all of them are selected, the matrix will appear like Robert Sedgewick, Professor at Princeton University, instructor of the course. You can shuffle the steps of opening these 2408 sites, but the result will always be the same. The connection will draw a picture for certain, it will never change its destination actually. Then how many possible sequences there can be to open these 2408 sites? It’s very clear that the result will be factorial of 2408, but do you have any idea how big it would be? I got into some trouble in calculating factorial of 2408 using Java, and I found using Python is much easier this time. 12import mathprint(math.factorial(2408)) And the result is…ready? Go! 21758594999952225256227255509958770525534993761170297492657718767486088244539036311974548105366978730304890874687998931843982776471695309982496716091929477596457019761300893173741534377145055742888600264305972407789653360420715650908019804809003333937353797238853879239069468095253478585900901569877665080446005525224089508413768914166828202348453714981888582265659866672234817320549835393263269600678943173083208786150887241218830951534151023198217804926543144488519879222117164281533725136849972519542757913468975304278272202313390978737108647430080250688571420352473288158962330968717973026215547164574655829522597595920308076300262533612505452491729694802704235061137562520593939941611211676246573285129213297740475072197491178881479094324050477716711007186760890805885289600818395369120904089858881365253682904986765051411600279317114544670877598660608068387251089672699624432818691431753629834595266369774230206535021500947768350641436338008224871891096941989810564059835480734023608516986342940799282601509909755914345702002398979527341635335589932079921844550299296765788764614115047189880053781089359124607076307477102000781076272097686933038955068463564138165407556497891242723903418121248640843251301848661406267955775206671116633131848330041457815589303985731973513659761266361451987631846567722247462019715782565495726789718590430300132709702923444485339649818738367459553944758665000677121577239898195392489190372781469616510565567235662058347447041036082279555002359384777241046356630140481788406662330268331157432591691983712930387182787427331315236514697941067977155337915150525669700467459039497125260067081460975724610012796075453577512129524610598629405415947882287562646596847798500277989940349764441278748496344810587661925483816853247911767802264941093438557143107557343354223365275158586265975784232244388778490424915335014856632359110022021568854780677765623358588472815628236138731069723731918036279618308587391396893812365810934868790695982445677773511512096164778247854799696415801777047426769474512776572807515499163928478050635767617241814153161069023349807872926989276321585129832669703196308315638887095150725873327382978368414291853714206642479565340623081645635259899325152723077182087825883320502448759987706414708555797695156437711005255453773088388421692048712808757032199780471397499344526710742025027366241277709542406769259163050319711009907937797988005289487586289285239191709874783876026264546187631023984005517156464453378524257632954079904118202556259631871941494206554425675391040068137333289842961763952315169361943659557098887908148472454753534441180805876726890829406428410293912061447395930885462039983639454999156893078306721906157525678665587288311022535413165018866038774554519237458631172359295574521080147470001807646132611548173799809180872176554883132407975754633781395902726073263358391864654226838611241280382791810347791313261228186922648281944512665244213221470708304181265827395530294959267833181512516106016708886865802585082368266589308282277973310417979771362961573289306518544172875848050627600215462334565453317064959637152271137508553349749864076477375290799340126691892626805021243113341240094988118302395281987744694938839705675124899805205311840735482867308921928032903126837676596703677074546354070316422400659168832877910530102049188638921987560519794911408413376690139023750683170764269423245188478974782685833231647755282809023275600579562068022306125965603894714096709169014359173885725022410482307983582848544029430308504710050913607427947146960265782278182851895691019554244771829604138266880136613179627902032928187316074972413984172931815414459532911017932363121474024120207932042589633624980202492915808108472682957610862771268658194135467582024669148130274010639626573267227084500963051586412573311529688779546274807578980079589236574590032283708780576841735220257056089488889054503441347829340342987839998850315817941430464119539322030100036391585484429073544194437248620041004947094494306813124947233221809464184492977405338266088004753342006034454256802717860213487102304602111082069729179183912892310926940010895293383091638154273639132326948510614314636246553636478230586408593481841258855076019524321468305027698853616858544467250133242472615996699171731672015980715690856827203376654427469688828493437318017191647963907353096155949414777105832802809111797630502385412343654294767130489796867215540128434416046595314739194824591845330992960181683418445356776559743473171773332982169278213091022970109475662032901706168542366477219418250959082099419221794734241867163997537294903638475623203613762563916868986220108618349798999297270144629976714666404789938566426084294730264011993843464803887031369997182138090586858439263165728582852107148235168845179981951308720985000631523794448909717418597240983588271119017952446552908771616828729694498105134321362587752084498298540631630047275976674069416103878183339417398381640250832037298996904027435379281480080779997366294091624818615213365710341769880327641623742788293755856604362177161860165904684510408376136291933499279091071147396522966312847540590794851028270031075275070110877864018101022208278340073515317163453715671305253878011789709400417146562136811038036869947227020189400688889289145368187906102145887240147199649624741501825733634493584569288672808008071700916133597015265730531592515259177198882367872332958036736813927476039975698636525851141792384458124270507717681351913851341602999123763657321159787790779636932576524606488017978717474806161069078372492020161577278433064090872570321300847401308302034646131087623196009250892633693952221225135875156933075853403175847677904474782437577896496547224344704997964123613109921984911971617174297374719817432121315231348044318866252156117239158307344697451683424693705097269162351898260575905280042177114272875010079571280939316425425734562133587147771503016863766670267188101589212539344187429237337097886813790907620488059495062409895961794810564953442060219347321914248124224100979617970052618332117897515242897039379709127894075251637810159733054718222062365062421320028544993426422351376478518352472783084637480300654371523661962663091208492103830074944716764484446634939320765685200444210417771706531035127562476041407515658152099601907167854337328045882514475289024549979687331418902963389094528577036145080901894491929405642630745909979143286735986058234759547883452690878465663700666796458122673957366323079880085451052670365099161588137223768621426118555148885228241036087524278431003970843443200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 And we would easily find that two facts exist without any conflict: You can select and open 2408 sites freely in nearly infinite possible ways The destination pciture will never change when all the open sites connected Every day you make decisions that will have an impact on your life, sometimes you make them according to your own will, sometimes you just have to and have no choice. When Christians are taught that God has a plan for their life and predestined a good ending - we don’t discuss what kind of good it would be here, it seems very confusing and contrary to our daily life, and very difficult to believe that. How can this be? How can a man act according to his free will if there is predestination from God already? It would be very easy to approach and answer this question, or very difficult and impossible to answer this question. The easy approach is to question the question itself, as it is based on a false assumption. Why can’t God’s predestination and men’s free will co-exist? Why do we think that it’s so obvious that you can only have one of them, either predestination or free will? Based on this false assumption, and the preciousness of freewill, Christian faith about Predestination became chains of the souls who are struggling with how to make decisions - though it doesn’t need to be like this. We simply overrated our ability while underrated God’s providence. If those selected and opened sites are steps of my life, then I know that no matter how I walked through these steps, my destination won’t change, I would draw a picture of myself rebuilt by God’s grace. Many times I cannot understand why certain steps are connected in a confusing way, but immediately I can testify that in the right time God led me to the right place, to do the right things - usually I don’t know what the right things really are.😅 If those selected and opened sites are brothers and sisters in the church, called by God to build His Kingdom, then I know that no matter how and when they are elected, the destination won’t change, we will draw a picture of Kingdom of God that God will surely restore. To appreciate and recognize God’s works in brothers and sisters is a joyful work that I’d like to practice always, you will never know how God will use a man and when God will use a man, but the result will always help you to know more about God, know more about you. In the beginning, God created the heavens and the earth. And in the end, “a new heaven and a new earth”. As a result, the bottom row will for sure connect to the top row, percolates would always return true. If this is the test case you can skip the complex implementation and simply return true. Percolation, predestination, and freewill. Complicated, simple, and mysterious. Hard to believe, right? Maybe the life and works of Martin Luther, John Calvin will give you some insight on this never ending discussion. amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "1eea2a1e0fa470806f2efa9531b2818d"; amzn_assoc_asins = "1426754434,030017084X,1296609529,0875521126";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Predestination</tag>
</tags>
</entry>
<entry>
<title><![CDATA[5 Things I Won't Tell You About Algorithms, Part I]]></title>
<url>%2F5-Things-I-don-t-want-to-tell-you-about-Algorithms-Part-I%2F</url>
<content type="text"><![CDATA[Algorithms, Part I at Coursera by Princeton University would be the best online Algorithms course I’ve ever enrolled in. I highly recommend you to take a look, though there are 5 things I don’t want to - or at least hesitate to tell you about it. I Gave Up TwiceIt’s a shame to tell you that I’ve enrolled in this course more than once. I’ve enrolled to this course at 2014 first, then probably at 2016 I picked up it again. But I never finished it and usually, I stayed at Week 1, Course 1, Video 1. It’s Dec 2018 already and I found I am still struggling with certain coding contests like leetcode weekly, I think it’s time to review and strengthen again. The instructors of this course suggested 6 weeks of study, 6-10 hours per week, which is apparently affordable in time and workload. Then why I gave up previously twice? I am lack of patience and endurance. This is a course you need to devote yourself and won’t see any visible impact in a short time, but in long-term the reward is high - at least I believe. So this time I set punishment like this if I gave up the 3rd time. Don’t Copy My CodeTo force myself to stick to the goal, I created a repository at GitHub to commit assignments I finished and track progress each week. Fortunately, I’ve finished two weeks’ task beforehand and I am still alive. I would say that the assignments are very good for practicing purpose. You will apply what you have learned in the course and it’s also challenging. Usually, it says that it would cost you 5 hours to finish, but I found that to get a good score you would spend more hours than this. I literally spent 8 hours on the first assignment Percolation and tried 6 times to get a good score, as I also enhanced the test methodology myself, which you can review the issue #64 I reported. Try to resolve the problems yourself but in a reasonable time(I am not a student anymore and I don’t have that much time), if you are stuck for a long time you can search for some tips and insights, or go to the forum to see what the mentor replied there. Don’t copy my code man, but you can review them to get some ideas if you really need and want. The online grade system is very impressive and I am thinking of introducing it into OIT courses I would teach in the future. I Get Stuck FrequentlyYeah, don’t be upset. If you get stuck in the way, remember, there is a fool like me also get upset, depressed, angry, anxious, suspicious regularly. It’s very clear I don’t have much talent in this area, but hard works would still improve me somewhat. Percolation Submission Date Score Passed? December 21, 09:31 AM PST 100/100 Yes December 20, 10:48 PM PST 93/100 Yes December 20, 10:41 PM PST 81/100 Yes December 20, 09:17 PM PST 79/100 No December 20, 03:31 PM PST 79/100 No December 20, 03:06 PM PST 52/100 No The 5th submission passed and the score seems good enough, but actually, there is a bug which I cannot ignore, after resolving it I got a 100, but still the memory usage is not optimized well, which I plan to improve in the future. I Got The TextbookSlides of the lectures are good enough for reading purpose, but a thorough and systematical reading would still require a textbook. Algorithms, 4th Edition by Robert Sedgewick and Kevin Wayne provides “essential information thatevery serious programmerneeds to know aboutalgorithms and data structures” So go and get it, DO NOT HESITATE! My Unit TestCase RocksHonestly speaking, the unit test mentioned in the course are actually no unit test at all. Simply running main method and compare the result with expected result manually just sucks, I would shamelessly recommend you using JUnit or TestNG to do this. Feel free to use my test cases, they would save you a lot of time. For example, I’ve concluded all the tests provided by the instructor and integrated them into certain unit tests. You may like to check out PercolationTest.java to see whether I am a good, old, and young boy. 12345678910111213141516171819202122232425262728293031323334353637383940@Testpublic void all() { In in = new In(this.getClass().getResource("/percolation-test-cases.txt")); int failed = 0; while (!in.isEmpty()) { String line = in.readLine(); String[] array = line.split(","); Percolation perc = this.from(array[0]); try { assertEquals(perc.numberOfOpenSites(), Integer.parseInt(array[1])); assertEquals(perc.percolates(), Boolean.parseBoolean(array[2])); } catch (AssertionError e) { // I want to know how many cases fail and the exact corresponding files // You can simplify this if you just want to know the first failed case System.err.println(line + " -> " + perc.numberOfOpenSites() + "," + perc.percolates()); failed++; } } if (failed > 0) { throw new AssertionError(failed + " test cases failed!"); }}@Testpublic void isFull() { Percolation perc = new Percolation(3); perc.open(1, 1); perc.open(3, 1); assertFalse(perc.isFull(3, 1)); perc.open(1, 3); perc.open(3, 3); assertFalse(perc.isFull(3, 3)); perc.open(2, 3); assertTrue(perc.isFull(3, 3)); assertFalse(perc.isFull(3, 1));} Finally, if you have to purchase one and only one algorithm book and are still hesitating, then get Algorithms, 4th Edition first. Trust me, you will never regret. amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_design = "enhanced_links"; amzn_assoc_asins = "032157351X"; amzn_assoc_placement = "adunit"; amzn_assoc_linkid = "a5b1635ea3b24455b5030a41c9f10ef9";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Algorithms</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Behind-the-Scenes Secrets of Jsoup V: Tips & Tricks of Optimization]]></title>
<url>%2FBehind-the-Scenes-Secrets-of-Jsoup-Tips-And-Tricks%2F</url>
<content type="text"><![CDATA[We have done things right, now it’s time to do things faster. We would keep Donald Knuth‘s warning in mind, “We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil”. According to Jonathan Hedley, he uses YourKit Java Profiler to measure memory usage and find the performance hot point. Using statistic result of such kind of tools is crucial for the success of optimizations, it will prevent you spend time just wondering and making useless tunings, which doesn’t improve performance but also make your code unnecessarily complex and hard to maintain. Jonathan also talked about this in the “Colophon”. We will list some tips and tricks used in Jsoup, they are randomly ordered currently, would be re-organized in the future. 1. Padding for Indent123456789101112131415161718// memoised padding up to 21, from "", " ", " " to " "static final String[] padding = {......};public static String padding(int width) { if (width < 0) throw new IllegalArgumentException("width must be > 0"); if (width < padding.length) return padding[width]; char[] out = new char[width]; for (int i = 0; i < width; i++) out[i] = ' '; return String.valueOf(out);}protected void indent(Appendable accum, int depth, Document.OutputSettings out) throws IOException { accum.append('\n').append(StringUtil.padding(depth * out.indentAmount()));} Pretty smart, right? It maintains a cache of different lengths of paddings which would cover 80% of the cases - which I assume would be based on the author’s experience and statistic. 2. Has Class Or Not?Element#hasClass was marked as performance sensitive, for example, we want to check whether <div class="logged-in env-production intent-mouse"> has class production, split class by whitespace to an array then loop and search would work, but in a deep traverse this would be in-efficiency. Jsoup introduces Early Exit here first, by compare length with target class name to avoid unnecessary scan and search, which will also be beneficial. Then it uses a pointer detecting whitespace and performs regionMatches - honestly speaking this is the first time I got to know method String#regionMatches🙈😅 123456789101112131415161718192021222324252627282930313233343536373839404142public boolean hasClass(String className) { final String classAttr = attributes().getIgnoreCase("class"); final int len = classAttr.length(); final int wantLen = className.length(); if (len == 0 || len < wantLen) { return false; } // if both lengths are equal, only need compare the className with the attribute if (len == wantLen) { return className.equalsIgnoreCase(classAttr); } // otherwise, scan for whitespace and compare regions (with no string or arraylist allocations) boolean inClass = false; int start = 0; for (int i = 0; i < len; i++) { if (Character.isWhitespace(classAttr.charAt(i))) { if (inClass) { // white space ends a class name, compare it with the requested one, ignore case if (i - start == wantLen && classAttr.regionMatches(true, start, className, 0, wantLen)) { return true; } inClass = false; } } else { if (!inClass) { // we're in a class name : keep the start of the substring inClass = true; start = i; } } } // check the last entry if (inClass && len - start == wantLen) { return classAttr.regionMatches(true, start, className, 0, wantLen); } return false;} 3. Tag Name In or Not?As we analyzed in previous articles, HtmlTreeBuilderState will validate nest correctness by checking whether tag name in a certain collection or not. We can compare the implementation before and after 1.7.3 to have a check. 1234567891011// 1.7.2} else if (StringUtil.in(name, "base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title")) { return tb.process(t, InHead);}// 1.7.3static final String[] InBodyStartToHead = new String[]{"base", "basefont", "bgsound", "command", "link", "meta", "noframes", "script", "style", "title"};...} else if (StringUtil.inSorted(name, Constants.InBodyStartToHead)) { return tb.process(t, InHead);} According to the comment written by the author, “A little harder to read here, but causes less GC than dynamic varargs. Was contributing around 10% of parse GC load. Must make sure these are sorted, as used in findSorted”. Simply using static final constant array, also make them sorted so that binary search will also improve from O(n) to O(log(n)), the cost–performance ratio is pretty good here. However, “MUST update HtmlTreebuilderStateTest if more arrays added” is not a good way to synchronize IMHO, rather than Copy & Paste I would use reflection to retrieve those constants. You may find my proposal in Pull Request #1157: “Simplify state sorting status unit test - avoid duplicated code in HtmlTreeBuilderStateTest.java”. 4. Flyweight PatternDo you know the trick of Integer.valueOf(i)? It maintains a IntegerCache cache from -128 to 127 or higher if configured(java.lang.Integer.IntegerCache.high), as a result, == and equals result will be different when the value is located in a different range(a classic Java interview question?). This is an example of Flyweight Pattern actually. As for Jsoup, applying this pattern will also reduce object created times and gain benefit to performance. 1234567891011121314151617181920212223242526272829303132333435363738/** * Caches short strings, as a flywheel pattern, to reduce GC load. Just for this doc, to prevent leaks. * <p /> * Simplistic, and on hash collisions just falls back to creating a new string, vs a full HashMap with Entry list. * That saves both having to create objects as hash keys, and running through the entry list, at the expense of * some more duplicates. */private static String cacheString(final char[] charBuf, final String[] stringCache, final int start, final int count) { // limit (no cache): if (count > maxStringCacheLen) return new String(charBuf, start, count); if (count < 1) return ""; // calculate hash: int hash = 0; int offset = start; for (int i = 0; i < count; i++) { hash = 31 * hash + charBuf[offset++]; } // get from cache final int index = hash & stringCache.length - 1; String cached = stringCache[index]; if (cached == null) { // miss, add cached = new String(charBuf, start, count); stringCache[index] = cached; } else { // hashcode hit, check equality if (rangeEquals(charBuf, start, count, cached)) { // hit return cached; } else { // hashcode conflict cached = new String(charBuf, start, count); stringCache[index] = cached; // update the cache, as recently used strings are more likely to show up again } } return cached;} There is also another scenario to minimize new StringBuilder GCs using the same idea. 123456789101112131415private static final Stack<StringBuilder> builders = new Stack<>();/** * Maintains cached StringBuilders in a flyweight pattern, to minimize new StringBuilder GCs. The StringBuilder is * prevented from growing too large. * <p> * Care must be taken to release the builder once its work has been completed, with {@see #releaseBuilder}*/public static StringBuilder borrowBuilder() { synchronized (builders) { return builders.empty() ? new StringBuilder(MaxCachedBuilderSize) : builders.pop(); }} Actually, CharacterReader and StringUtil are worthy to digest more and more as there are many useful tips and tricks that will inspire you. 5. Other Improvement Methods Use RandomAccessFile to read files that improved file read time by 2x. Check #248 for more details Node hierarchy refactoring. Check #911 for more details “Improvements largely from re-ordering the HtmlTreeBuilder methods based on analysis of various websites” - I list this one here because it’s very practical. Deeper understanding and observation of how the code will run will also give you some insights Call list.toArray(0) rather than list.toArray(list.size()) - this has been used in certain open source projects such as h2database, so I also proposed this in another Pull Request #1158 6. The UnknownsOptimization never ends. There are still many tips and tricks I didn’t discover at this time. I would appreciate if you can share them to me if you find more inspiring ideas in Jsoup. You may find my contact information in the left sidebar of this website or simply email to ny83427 at gmail.com. -To Be Continued-]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Jsoup</tag>
<tag>Code Review</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Behind-the-Scenes Secrets of Jsoup IV: CSS Selector]]></title>
<url>%2FBehind-the-Scenes-Secrets-of-Jsoup-CSS-Selector%2F</url>
<content type="text"><![CDATA[Most of the time, you are just consuming the Document Jsoup built for you, like document.select(${selector}). It would be helpful to go through W3C CSS Selector Specification to understand Jsoup’s roadmap. We have talked about Node Traverse before, what Selector will actually do is just filtering and collecting while traversing, and the key point here will be parsing and evaluating given queries. Overview of PackagePackage org.jsoup.select didn’t change much in latest version 1.12.1-SNAPSHOT, I would reference UML diagram made by Yihua Huang directly here: Besides NodeVistor the interface, there is another similar interface NodeFilter, their methods are nearly the same: 123456789101112131415161718192021222324252627public interface NodeFilter { /** * Filter decision. */ enum FilterResult { /** Continue processing the tree */ CONTINUE, /** Skip the child nodes, but do call {@link NodeFilter#tail(Node, int)} next. */ SKIP_CHILDREN, /** Skip the subtree, and do not call {@link NodeFilter#tail(Node, int)}. */ SKIP_ENTIRELY, /** Remove the node and its children */ REMOVE, /** Stop processing */ STOP } /** * Callback for when a node is first visited. */ FilterResult head(Node node, int depth); /** * Callback for when a node is last visited, after all of its descendants have been visited. */ FilterResult tail(Node node, int depth);} There is only one implementation in production code, which is FirstFinder, 5 other implementations are all located in test and probably reserved for the future. As for FirstFinder, it’s easy to guess that it’s created in the purpose of optimization. You don’t need to collect all the matching elements and return the first one, instead of invoking select(${selector}).get(0), Jsoup introduces another method selectFirst(${selector}) which will be useful when you just care about the first one - a frequent scenario actually. NodeFilter: Another TraverseI don’t want to repeat Node Traverse here again, but it will be helpful to review it in another way - the implementation of filtering. The idea and workflow are totally the same, but a little bit longer. You may compare to NodeTraversor#traverse for better understanding. 123456789101112131415161718192021222324252627282930313233343536373839404142434445public static FilterResult filter(NodeFilter filter, Node root) { Node node = root; int depth = 0; while (node != null) { FilterResult result = filter.head(node, depth); if (result == FilterResult.STOP) return result; // Descend into child nodes: if (result == FilterResult.CONTINUE && node.childNodeSize() > 0) { node = node.childNode(0); ++depth; continue; } // No siblings, move upwards: while (node.nextSibling() == null && depth > 0) { // 'tail' current node: if (result == FilterResult.CONTINUE || result == FilterResult.SKIP_CHILDREN) { result = filter.tail(node, depth); if (result == FilterResult.STOP) return result; } Node prev = node; // In case we need to remove it below. node = node.parentNode(); depth--; if (result == FilterResult.REMOVE) prev.remove(); // Remove AFTER finding parent. result = FilterResult.CONTINUE; // Parent was not pruned. } // 'tail' current node, then proceed with siblings: if (result == FilterResult.CONTINUE || result == FilterResult.SKIP_CHILDREN) { result = filter.tail(node, depth); if (result == FilterResult.STOP) return result; } if (node == root) return result; Node prev = node; // In case we need to remove it below. node = node.nextSibling(); if (result == FilterResult.REMOVE) prev.remove(); // Remove AFTER finding sibling. } // root == null? return FilterResult.CONTINUE;} Using FirstFinder as an example, the idea is straightforward. It keeps the evaluator and the matching result, and return a FilterResult of STOP when the first matching element was found. 123456789101112131415161718192021222324252627private static class FirstFinder implements NodeFilter { private final Element root; private Element match = null; private final Evaluator eval; FirstFinder(Element root, Evaluator eval) { this.root = root; this.eval = eval; } @Override public FilterResult head(Node node, int depth) { if (node instanceof Element) { Element el = (Element) node; if (eval.matches(root, el)) { match = el; return STOP; } } return CONTINUE; } @Override public FilterResult tail(Node node, int depth) { return CONTINUE; }} The EvaluatorsOK. We have gone through the traverse again via review the filtering function. Now it’s time to understand how Jsoup parse a given query. We will look at Evaluator, CombiningEvaluator, and StructuralEvaluator first. Evaluator is a abstract class with 39 inherited subclasses which cover querying by id, name, tagName(equals or endsWith), class, attribute name, attribute value, sibling index, texts, regex match and etc. Since we have set these properties well while parsing the DOM tree, it will be very easy to implement the abstract method: 1234/*** Test if the element meets the evaluator's requirements.*/public abstract boolean matches(Element root, Element element); CombiningEvaluator combines multiple evaluators with logic expression And or Or, which can process combinators like ",", ">", "+", "~", " " StructuralEvaluator is used to simulate query like div > p > span or div p span. ImmediateParent will handle div > p > span while Parent will handle div p span. We will take a look at Parent implementation: 12345678910111213141516171819202122232425static class Parent extends StructuralEvaluator { public Parent(Evaluator evaluator) { this.evaluator = evaluator; } public boolean matches(Element root, Element element) { if (root == element) return false; Element parent = element.parent(); while (true) { if (evaluator.matches(root, parent)) return true; if (parent == root) break; parent = parent.parent(); } return false; } @Override public String toString() { return String.format(":parent%s", evaluator); }} And QueryParser that will parse a CSS selector into an Evaluator tree, handle above cases like this: 123456// for most combinators: change the current eval into an AND of the current eval and the new evalif (combinator == '>') currentEval = new CombiningEvaluator.And(newEval, new StructuralEvaluator.ImmediateParent(currentEval));else if (combinator == ' ') currentEval = new CombiningEvaluator.And(newEval, new StructuralEvaluator.Parent(currentEval));... QueryParser FinallyAfter we explored different kinds of Evaluator, it will be easy to understand the parsing process in the below: 123456789101112131415161718192021222324252627282930313233private QueryParser(String query) { this.query = query; this.tq = new TokenQueue(query);}Evaluator parse() { tq.consumeWhitespace(); if (tq.matchesAny(combinators)) { // if starts with a combinator, use root as elements evals.add(new StructuralEvaluator.Root()); combinator(tq.consume()); } else { findElements(); } while (!tq.isEmpty()) { // hierarchy and extras boolean seenWhite = tq.consumeWhitespace(); if (tq.matchesAny(combinators)) { combinator(tq.consume()); } else if (seenWhite) { combinator(' '); } else { // E.class, E#id, E[attr] etc. AND findElements(); // take next el, #. etc off queue } } if (evals.size() == 1) return evals.get(0); return new CombiningEvaluator.And(evals);} Easier than expected, right? The implementation here is clean, elegant and easy to understand. Besides that, java doc of Selector is also impressive, you can play around with Try Jsoup with Selector syntax. -To Be Continued-]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Jsoup</tag>
<tag>Code Review</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Behind-the-Scenes Secrets of Jsoup III: The Tree and The State Machine]]></title>
<url>%2FBehind-the-Scenes-Secrets-of-Jsoup-Build-The-Tree%2F</url>
<content type="text"><![CDATA[Ready? The challenging task finally came. We will build a tree this time so that you don’t have to traverse before it was built.😅TreeBuilder has two implementations, XmlTreeBuilder is relatively easy while HtmlTreeBuilder is much more complex. And we will go through them today. Overview of PackageI will skip general introduction about Compiler, Lex, Parser as there are too many articles talking about them. We will go to Jsoup source code directly. Let’s have a quick look at several classes under package org.jsoup.parser. Parser: Facade of Jsoup parsing. 123private TreeBuilder treeBuilder; // this is the man who actually do the jobprivate ParseErrorList errors; // by default Jsoup didn't collect errors of html but you can enable thisprivate ParseSettings settings; // switches of preserveTagCase and preserveAttributeCase Token: Parse tokens for the Tokeniser. It’s a abstract class with 6 subclasses: Doctype, StartTag, EndTag, Comment, Character, EOF Tokeniser: Read input stream into tokens. It keeps current state and emitPending as the token we are about to emit on next read, it also keeps tagPending, startPending, endPending, charPending, doctypePending, and commentPending before tokens were filled up completely CharacterReader: consumes tokens off a string, it might be inspired from ByteBuffer of NIO as there are similar methods like consume()、unconsume()、mark()、rewindToMark() and consumeTo() TokeniserState and HtmlTreeBuilderState: Lexing/Parsing State Machine. Jsoup applied State Pattern to implement it using enumerations, which is a classic example of design pattern usage also. Using a transition table is easy for the transition between different states but would be difficult to perform extra work during the transition HtmlTreeBuilder and XmlTreeBuilder: I list them in the end as they basically play a role like a manager, collaborating Tokeniser and Lexing, Parsing State Machine to finish the work Lexing and Parsing State Pattern implementation would the most complex part of Jsoup. You can get to know this even just from lines of code statistics. Top 7 source files here! File blank comment code org.jsoup.parser.TokeniserState.java 27 46 1671 org.jsoup.parser.HtmlTreeBuilderState.java 43 56 1429 org.jsoup.helper.HttpConnection.java 162 51 979 org.jsoup.nodes.Element.java 156 604 727 org.jsoup.parser.HtmlTreeBuilder.java 104 38 591 org.jsoup.select.Evaluator.java 139 107 532 org.jsoup.parser.CharacterReader.java 60 61 385 State Machine and State Pattern12⬇⬇ ⬇ ⬇ <div>test</div> If we use a very short code snippet as an example, each arrow would point to a state like TagOpen, TagName, Data, EndTagOpen. I just list two of them in the below: 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556/** * States and transition activations for the Tokeniser. */enum TokeniserState { Data { // in data state, gather characters until a character reference or tag is found void read(Tokeniser t, CharacterReader r) { switch (r.current()) { case '&': t.advanceTransition(CharacterReferenceInData); break; case '<': t.advanceTransition(TagOpen); break; case nullChar: t.error(this); // NOT replacement character (oddly?) t.emit(r.consume()); break; case eof: t.emit(new Token.EOF()); break; default: String data = r.consumeData(); t.emit(data); break; } } }, TagOpen { // from < in data void read(Tokeniser t, CharacterReader r) { switch (r.current()) { case '!': t.advanceTransition(MarkupDeclarationOpen); break; case '/': t.advanceTransition(EndTagOpen); break; case '?': t.advanceTransition(BogusComment); break; default: if (r.matchesLetter()) { t.createTagPending(true); t.transition(TagName); } else { t.error(this); t.emit('<'); // char that got us here t.transition(Data); } break; } } }, ...} Understand the idea of Token parse we can go to TreeBuilder process, we will go to the core section first, then go to XmlTreeReader which is easier. We will talk about HtmlTreeReader at last. 1234567891011protected void runParser() { while (true) { Token token = tokeniser.read(); // protected abstract boolean process(Token token); process(token); token.reset(); if (token.type == Token.TokenType.EOF) break; }} As for Tokeniser#read():12345678910111213141516171819Token read() { while (!isEmitPending) state.read(this, reader); // if emit is pending, a non-character token was found: return any chars in buffer, and leave token for next read: if (charsBuilder.length() > 0) { String str = charsBuilder.toString(); charsBuilder.delete(0, charsBuilder.length()); charsString = null; return charPending.data(str); } else if (charsString != null) { Token token = charPending.data(charsString); charsString = null; return token; } else { isEmitPending = false; return emitPending; }} XmlTreeBuilder FirstAfter exploring the Lexing part we can go to the Parsing part now. We will go through the easier part XmlTreeBuilder first, focusing on its implementation of method process(token) in abstract class TreeBuilder. XmlTreeBuilder basically maintains a stack and insert node according to token type: 1234567891011121314151617181920212223242526@Overrideprotected boolean process(Token token) { // start tag, end tag, doctype, comment, character, eof switch (token.type) { case StartTag: insert(token.asStartTag()); break; case EndTag: popStackToClose(token.asEndTag()); break; case Comment: insert(token.asComment()); break; case Character: insert(token.asCharacter()); break; case Doctype: insert(token.asDoctype()); break; case EOF: // could put some normalisation here if desired break; default: Validate.fail("Unexpected token type: " + token.type); } return true;} As for insert, we will just use StartTag as an example in the below. The other insert methods accept different types of Token but the idea is the same. 123456789101112Element insert(Token.StartTag startTag) { Tag tag = Tag.valueOf(startTag.name(), settings); Element el = new Element(tag, baseUri, settings.normalizeAttributes(startTag.attributes)); insertNode(el); if (startTag.isSelfClosing()) { if (!tag.isKnownTag()) // unknown tag, remember this is self closing for output. see above. tag.setSelfClosing(); } else { stack.add(el); } return el;} HtmlTreeBuilder LastCompared to XmlTreeBuilder, HtmlTreeBuilder is much more complex. It introduces HtmlTreeBuilderState to process transitions. As Html is relatively loose in syntax and error tolerance, Jsoup won’t simply quit when certain kinds of error detected, but choose to record them and continue. It will also try to close those tags not closed properly. Some nested tags have sequence restriction, such as a <td> must be under <th> or <tr>, while tr must be under <tbody> or <table. There are currently 23 HtmlTreeBuilderState and we will use a typical Html snippet as an example, which came from Yihua Huang’s work. Comments like <!-- State: --> will indicate what kind of HtmlTreeBuilderState we are at. 12345678910111213141516171819202122232425262728293031323334353637383940<!-- State: Initial --><!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><!-- State: BeforeHtml --><html lang='zh-CN' xml:lang='zh-CN' xmlns='http://www.w3.org/1999/xhtml'><!-- State: BeforeHead --><head> <!-- State: InHead --> <script type="text/javascript"> //<!-- State: Text --> function xx(){ } </script> <noscript> <!-- State: InHeadNoscript --> Your browser does not support JavaScript! </noscript></head><!-- State: AfterHead --><body><!-- State: InBody --><textarea> <!-- State: Text --> xxx</textarea><table> <!-- State: InTable --> <!-- State: InTableText --> xxx <tbody> <!-- State: InTableBody --> </tbody> <tr> <!-- State: InRow --> <td> <!-- State: InCell --> </td> </tr> </table></body></html> As we said before, nested tags such as tr cannot be under body directly, they need to be organized under table or tbody. And DOCTYPE declaration also should not be seen in body. In method boolean process(Token t, HtmlTreeBuilder tb) of InBody, there is a case to handle this. 1234case Doctype: { tb.error(this); return false;} If head was not closed before body, Jsoup will auto-close it.12345678InHead { boolean process(Token t, HtmlTreeBuilder tb) {...} private boolean anythingElse(Token t, TreeBuilder tb) { tb.processEndTag("head"); return tb.process(t); }} As the State Pattern implementation needs to handle many different kinds of cases, one can be easily lost while reading the source code. Understanding the concept and general ideas first will be of help while debugging the code to know what Jsoup is doing, but still, it’s not easy and would hurt your brain😭 -To Be Continued-]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Jsoup</tag>
<tag>Code Review</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Behind-the-Scenes Secrets of Jsoup II: Traverse A Tree Before It Was Built]]></title>
<url>%2FBehind-the-Scenes-Secrets-of-Jsoup-Node-Traverse%2F</url>
<content type="text"><![CDATA[Here we go! We’ve got a HTML or XML snippet, it would be clean or dirty, small or large, safe or dangerous, but our task won’t change. We need to extract and manipulate data supporting the best of DOM, CSS, and jquery-like methods. The basic idea would be crystal clear, you need to build a DOM tree and traverse it with or without filtering. That’s it. Sounds easy, right?😅Then Just Do It…and you would probably…cry. A tree consists of a root node and its children from top to bottom. So it’s straightforward to get the root node first, retrieve its attributes then traverse to its child nodes and maintain the relationship at the same time. The class diagram of org.jsoup.nodes generated by Intellij IDEA is like this: PS: LeafNode was introduced in 1.11.1 for memory usage optimization. “By refactoring the node hierarchy to not track childnodes or attributes by default for lead nodes. For the average document, that’s about a 30% memory reduction.” You can get more details on #911, which was a good example of performance improvement. Besides other classes will be introduced in the future, Element and Document would be most frequently used, but Node is the root of the inheritance tree. Fields and methods worthy of notice are listed in the below: attributes: key-value collection. Key like ‘type’, ‘id’, ‘name’, ‘value’ and etc. Jsoup especially maintains a list of boolean attribute keys such as ‘checked’(for example: <input type="checkbox" checked value="Registered" />). Literally, two classes Attributes and Attribute are mapped correspondingly. A node can read and write attributes, which provides the ability to clean, correct given HTML parentNode, childNodes and siblingNodes will be used to access nodes related to current baseUri() that will be used to convert relative URL address to absolute I would talk more about Node traverse in “CSS Selector” part while touching a little bit here first. Slightly different from Yihua Huang‘s interpretation, Jonathan made some refactorings here, but the concept is still the same. These lines of code in class NodeTraversor play an important role in the whole picture: 12345678910111213141516171819202122public static void traverse(NodeVisitor visitor, Node root) { Node node = root; int depth = 0; while (node != null) { visitor.head(node, depth); if (node.childNodeSize() > 0) { node = node.childNode(0); depth++; } else { while (node.nextSibling() == null && depth > 0) { visitor.tail(node, depth); node = node.parentNode(); depth--; } visitor.tail(node, depth); if (node == root) break; node = node.nextSibling(); } }} Using recursion here is dangerous, though much easier. StackOverflowError might occur if the DOM tree is too deep. Iterate through is a must here. Don’t tell me you want to use -Xss256M to silence the world.😅 I want to emphasize that NodeVisitor is an interface. It defines what you would do when a node is first visited and last visited. 1234567891011public interface NodeVisitor { /** * Callback for when a node is first visited. */ void head(Node node, int depth); /** * Callback for when a node is last visited, after all of its descendants have been visited. */ void tail(Node node, int depth);} Implementations such as Accumulator would be used to collect nodes that pass evaluations parsed from the query, that’s actually the key point of document.select("${selector}"). Go to class Collector and you will find it: 1234567891011/** * Build a list of elements, by visiting root and every descendant of root, and testing it against the evaluator. * @param eval Evaluator to test elements against * @param root root of tree to descend * @return list of matches; empty if none */public static Elements collect (Evaluator eval, Element root) { Elements elements = new Elements(); NodeTraversor.traverse(new Accumulator(root, elements, eval), root); return elements;} Accumulator kept a reference to the node where traverse begins (which means it doesn’t necessarily need to be root), and update elements which you may think of as an ArrayList for simplification. 1234567891011121314151617181920212223private static class Accumulator implements NodeVisitor { private final Element root; private final Elements elements; private final Evaluator eval; Accumulator(Element root, Elements elements, Evaluator eval) { this.root = root; this.elements = elements; this.eval = eval; } public void head(Node node, int depth) { if (node instanceof Element) { Element el = (Element) node; if (eval.matches(root, el)) elements.add(el); } } public void tail(Node node, int depth) { // void }} Other NodeVisitor implementations such as FormattingVisitor, CleaningVisitor, OuterHtmlVisitor, W3CBuilder are also used in certain scenarios. NodeTraversor reuses the depth-first search process and provides the convenience of extra behaviors in the process, which makes the code clean and consistent. However, I guess you would be very confused till now. Why the hack you begin from node traverse first? We even don’t have a tree built! Yes, exactly. But remember, you have to begin with the end in mind. You always want to find DOM elements matching given search criteria, so the first thing you will think of is actually traversing, it will also affect how you build the tree - perhaps I should say “parse the tree” here. And it will touch the topics of Compilers. Fortunately, we don’t need to dig into this mysterious area. Lex and Parse are enough to achieve the goal. And we will talk about State Machine and State Pattern in the next article. -To Be Continued-]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Jsoup</tag>
<tag>Code Review</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Behind-the-Scenes Secrets of Jsoup I: Introduction]]></title>
<url>%2FBehind-the-Scenes-Secrets-of-Jsoup-Introduction%2F</url>
<content type="text"><![CDATA[Jsoup would probably be the most popular “working with real-world HTML” library in the Java community. I’ve been using it for web crawler stuff since 1.7.3(latest release is 1.11.3), but a little bit surprised to see that there is little introduction or analysis regarding its source code and implementations. Since I will use Jsoup as an example for OOP course(SE500) I would teach at Olivet Institute of Technology from Jan 2019, I tried to summarize the most important ideas behind-the-scene so that at least I know what I will talk about.😅These series were inspired from jsoup-learning and reused some graphs from it. Many thanks for Yihua Huang‘s digging into this beautiful library. This is the first part of the series. I will give a brief introduction about features of Jsoup and its general code structure. After that, I will analyze the DOM parser and CSS selector implementation mechanism, plus with some interesting tips and tricks in following articles. Jsoup is developed by Jonathan Hedley, a Senior Manager of Software Development at Amazon. According to the change logs, the initial beta was released at Jan 31, 2010, so it has been about 9 years till now! He is still maintaining the code base regularly, though not that actively as before. It might be due to “jsoup is in general, stable release” as he said. I use the latest version 1.12.1-SNAPSHOT for these series. It’s a Maven project without any external dependencies, though it introduced junit, gson, and jetty for unit test and integration test usage. According to the statistic result of cloc, there are 68 Java source files under src\main\java, 12015 lines of code, 4177 lines of comment and 1991 blank lines. As a library with good test coverage, there are 46 Java source files under src\test\java, with 7911 lines of code, 350 lines of comment and 1672 blank lines. The percentage of test code against production code is 65.8%, which is pretty good. As for test coverage, Intellij IDEA code coverage runner gives the report in the below, which is also impressive. Package Class, % Method, % Line, % org.jsoup 98% (229/233) 87% (1269/1457) 83% (6135/7317) org.jsoup.helper 100% (11/11) 79% (138/174) 83% (692/824) org.jsoup.internal 100% (3/3) 100% (27/27) 95% (141/147) org.jsoup.nodes 96% (31/32) 87% (356/407) 88% (1286/1455) org.jsoup.parser 100% (114/114) 91% (490/535) 79% (2924/3699) org.jsoup.safety 100% (9/9) 100% (44/44) 95% (286/300) org.jsoup.select 100% (58/58) 81% (193/237) 92% (772/836) You may find that package org.jsoup.examples is missing here. Since it is used as a showcase, it’s reasonable that there is no need to write tests against them, thus I exclude it. It might be better to remove them out of production code and extract to another project with more examples covering most frequent scenarios - just in my opinion. As a widely used library aiming at “working with real-world HTML”, the higher the test coverage is, the better. I’ve heard that Evan You, author of Vue.js, even achieved 100% unit test coverage! 669 test cases make sure Jsoup stay at good status - but this still cannot prevent new issues happen. Anyway, real-world is always a crazy world, go to the test cases and you will believe what I said. For example, <p =a>One<a <p>Something</p>Else, <div id=1<p id='2', what the hack is this? what should be the expected correct parsing result? Can you figure them out in 5 seconds?😭 Even though Jsoup is well covered by unit tests and maintains a high quality of implementation, you still need to be very careful when you prepare to upgrade to a new version - actually this is something to be self-evident - you just need more and more test cases to make your life easier. I remember very clearly in Dec 2016, some of my unit tests suddenly failed after I upgraded from 1.8.3 to 1.10.1 without doing anything else. Since my software was used by thousands of clients, I immediately report an issue in Github and rollback to 1.8.3 for a while, I just can’t imagine what will happen if I simply upgrade it, you know, some bugs just appear in certain circumstances and not easy to reproduce in normal functional tests. From the test coverage result, you will also get a whole picture of code structure. While jsoup providing convenient methods to submit HTTP requests and get responses, the most important parts are still under package org.jsoup.parse and org.jsoup.select. I will introduce them in the 2nd and 3rd articles of these series. The 5 lines of code in the below, covering most frequently used scenarios, are fairly clean, easy and simple, which only means Jsoup did quite a good job for its API user experience. 12345Document doc = Jsoup.connect("https://en.wikipedia.org").get();Elements newsHeadlines = doc.select("#mp-itn b a");for (Element headline : newsHeadlines) { log("%s\n\t%s", headline.attr("title"), headline.absUrl("href"));} Jsoup also provides a website for you to play around with its selector. Try Jsoup is the place where you can explore features of Jsoup without writing one line of code. It is also created for issue report. You can save the input, parameters, and output so that those who want to help you will go to the point much faster. For example, I want to retrieve all the post titles of Old Young Boys Club: http://try.jsoup.org/~iZFlhTQQAZnkXoPSCKrG4OisFcg. The upgrade issue I mentioned above also had a corresponding session link http://try.jsoup.org/~NOfOU7vXHAaHWhDnHv5qBIPtE1M still available today.👍 After you get familiar with the features of Jsoup, it’s time to go to source code to understand the mechanism. I would suggest you run class org.jsoup.examples.Wikipedia and debug the 5 lines of code above to see what actually happened step by step. Beware, it’s a long journey. If you get stuck you may also go over the test cases to understand what kind of problems the code will resolve - and how you would resolve. It’s also helpful to fork the repository and try to submit some pull requests, you may either pick up an issue and try to fix or make some minor enhancements. Actually, I just submitted Pull Requests #1157 and #1158 yesterday plus two issues: #1156 and #1159. I hope Jonathan would accept my PR and consider fixing these issues.😅 PS: Once there was a Japanese Samurai who submitted a Pull Request #564 at Apr 27, 2015, got approved and merged at Nov 19, 2017. He recorded this unforgettable experience in twitter. Thanks – better late than never :)— Jonathan Hedley (@jhy) November 20, 2017 -To Be Continued-]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Jsoup</tag>
<tag>Code Review</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Chocolatey and Boxstarter: Setup Development Environment on Windows Like Never Before]]></title>
<url>%2FChocolatey-and-Boxstarter%2F</url>
<content type="text"><![CDATA[How many times have you googled “jdk download windows”, then download, click, click, and click? You don’t have to be like this even if you are using Windows. Chocolatey and Boxstarter are gospel for Windows users. Below is just an example: One Command To Install Them All! 1cinst jdk8 jdk11 git intellijidea-community vscode nodejs everything f.lux -y Install Chocolatey is super easy. Simply follow the instructions will do. Me usually choose the first option “install with cmd.exe(Run as Administrator)”, you just need to execute the command in the below, and you will get the Windows version apt-get:1@"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" -NoProfile -InputFormat None -ExecutionPolicy Bypass -Command "iex ((New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))" && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin" Wanna upgrade? choco upgrade chocolatey You may explore 6161 community maintained packages and build your own toolkit scripts. I’ve found it to be super useful when I need to setup development environment in bunches of different computers in a short time without any mistake. As sometimes I just cannot reproduce some tricky bugs in my own laptop and have to investigate in end user’s computer. You can be even happier using Boxstarter, it’s very straightforward and easy to use also. Honestly speaking, I didn’t dive into these two tools deeply as I found the most frequently used commands would resolve my problem perfectly. If you use Windows as daily development environment, I highly recommend you to automate your setup process using them. Yeah! Happy Coding! You may also access the gist created for this post.]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Software Management</tag>
<tag>Environment Installation</tag>
<tag>Automation</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Beware! Old Young Boys Club Might Be An Adult Content Website According To Bing Ads]]></title>
<url>%2FBing-Ads-Adult-Content%2F</url>
<content type="text"><![CDATA[Bing Ads is just AWESOME! It will give you a coupon code for $100 in search advertising once you registered. So why not use it? I created my first campaign for this little website and got a surprise joy immediately. It was disapproved. The reason is…Bing Ads said my blogger violate its Adult Content Policy. Yes, ADULT CONTENT POLICY. As an Old Young Boy, I always appreciated those who made joy for us. I’m pretty grateful for the algorithm invented by Microsoft Bing Ads team. I submitted an exception case immediately. But that’s obviously not enough, so I opened an online chat with its customer service representative. Honestly speaking Bing Ads provided great service better than I expected, I just went away for 3 minutes and didn’t reply in time, then a phone call reached me directly. But it spent me at least five minutes to understand she is the representative I am talking to - and she calls me from Philippines! I thought it was a spam call at first! She helped me to expedite the review process and hopefully this campaign will be approved the next week. However, I am very interested in the issue of Bing Ads algorithm and would follow up continuously to know exactly what happened. I once doubt whether the funny tool “thef*ck” I mentioned in [5 Github Repositories Will Make Your Day]”http://www.oldyoungboys.club/Funny-Github-Repositories/" confused Bing Ads. I would report an issue in the GitHub repository if it’s really the reason for my wonderful experience with Bing Ads. Maybe it’s time to read the inspiring story of how Microsoft NT team fight with numerous bugs and shipped the historic product. Meanwhile, it would be also beneficial to know more about bugs. Happy Reading! amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "9653009959f57ceb819ce2d9117a7440"; amzn_assoc_asins = "0759285780,0763667625,1426313764,1426317239";]]></content>
<categories>
<category>Joke</category>
</categories>
<tags>
<tag>Bing Ads</tag>
</tags>
</entry>
<entry>
<title><![CDATA[SAP HANA and German Soccer: from Champion of 2014 to Loser at World Cup 2018]]></title>
<url>%2FSAP-HANA-German-Soccer-World-Cup-2018%2F</url>
<content type="text"><![CDATA[“It was our Big Data software wot won it for Germany”, SAP said proudly after Germany won World Cup 2014. However, 4 years later, after Germany’s 1-0 defeat at the hands of Mexico, “can Big Data Analytics Save Germany’s Tournament?”, asked Forbes. And we all know the answer. NO. The defending champion was knocked out of World Cup 2018 at group stage after beaten by South Korea. Don’t misunderstand me. The software SAP developed was very powerful and useful. Big Data analytics was widely integrated into sports industry nowadays. SAP Match Insights developed by SAP HANA simply “transformed the football experience”, according to Oliver Bierhoff, German national team manager and former legend. It captured 5,000 data points per second and employed eight high-definition panoramic cameras to evaluate its players and opponents, which provides very useful information for the coach to make a decision. SAP HANA should never be responsible for Germany’s failure at World Cup 2018. Go back to the history of World Cup you will find a shocking fact. Defending champion of World Cup usually went home very early. France was knocked out group match in 2002 after it won World Cup 1998, Italy won World Cup 2006 and was eliminated from Group Stage in World Cup 2010, and Spain followed Italy’s step in 2014 after they won World Cup 2010. I testified Spain’s success in 2010 - a sleepless night with a tight schedule of development tasks. My wife and son slept already and I almost shouted out after Iniesta scored at 116th minute. As a result, I was terribly shocked to see Spain was beaten by Netherland like a fool after 4 years. This is something that why I love soccer so much. Past experience and honor is just nothing. Talk is cheap, show me the goals - TODAY! David might be transformed into a new Goliath after he kills the giant, and what waits for him will be the same death. It’s easy for defending champions to resist change and rely on their past experiences, but all other teams might have kept researching them for 4 years and sharpened their swords already. How difficult would it be for a champion to stay foolish and stay hungry? Very difficult. After Brazil was defeated by France the second time at World Cup 2006, Parreira just sighed, “what can I do if my boys just lost hunger and thirsty?”. But you have to, just as Steve Jobs said, “Stay Foolish. Stay Hungry.” amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "5991d52824afa92a7c819a1cc815a4f9"; amzn_assoc_asins = "B004W2UBYW,B01IJD7156,1493211765,0062390856";]]></content>
<categories>
<category>Soccer</category>
</categories>
<tags>
<tag>SAP HANA</tag>
<tag>German Soccer</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Jianye Dai: The Li Po, Tu Fu and Tao Yuan Ming You Never Knew]]></title>
<url>%2FJianye-Dai%2F</url>
<content type="text"><![CDATA[I just laughed to tears after I watched over this video.😂 Jianye Dai, perhaps one of the oldest rock star at TikTok, gave the most humorous and informative interpretations about Li Po, Tu Fu, and Tao Yuan Ming. You just cannot miss this, man! This guy is a true Old Young Boy. As a professor of Central China Normal University, he had his unique style to attract students. I would say that it is very difficult for a teacher like him to be not successful, as he is passionate, romantic, humorous and also serious. As a Chinese, I’ve recited many poems by Li Po, Tu Fu, and Tao Yuan Ming, but it seems that I never knew them until I understand the context, background of those poems from Old Dai. Below is just a sample, for more videos, you would visit this collection. Read these books while listening to this Old Young Boy, all things bright and beautiful! amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-book-code-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "a65a9a315ecdfa43923e5adf11642ff4"; amzn_assoc_asins = "0140442723,1333021747,1420942964,093244055X";]]></content>
<categories>
<category>Joke</category>
</categories>
<tags>
<tag>Poetry</tag>
<tag>Old Young Boys</tag>
</tags>
</entry>
<entry>
<title><![CDATA[5 Github Repositories That Will Make Your Day]]></title>
<url>%2FFunny-Github-Repositories%2F</url>
<content type="text"><![CDATA[If by life you were deceived, don’t be dismal, don’t be wild! Access these GitHub repositories, they will make your day definitely! #1 nocode“No code is the best way to write secure and reliable applications. Write nothing; deploy nowhere.“ 24868 stars, 2126 forks, 2097 issues, and 349 pull requests. This project will be the most serious project you’ve ever met and you will never forget about it. Many beast programmers around the world are involved actively in this project. Fork it. Report an issue. Submit a Pull Request. That’s it. As for contributing, “You don’t”. #2 RFC 863(Discard Protocol)This will be the most powerful, elegant while easy to implement protocol you’ve never heard. “One discard service is defined as a connection based application on TCP. A server listens for TCP connections on TCP port 9. Once a connection is established any data received is thrown away. No response is sent. This continues until the calling user terminates the connection.” Implementations can be found at: tcp-discard-service, devnull.php. I highly recommend you to implement your own. #3 The F*ckI have to change something here, or this post will be blocked somewhere, complained about by someone. 39017 stars, 1923 forks. Compared to nocode, this tool is widely used by millions of programmers who are struggling to remember hundreds of commands every day. The best practice to use this command is typing and shouting, as loud as you can. #4 volkswagen“Volkswagen detects when your tests are being run in a CI server, and makes them pass”, then the author explains why: “If you want your software to be adopted by Americans, good tests scores from the CI server are very important. Volkswagen uses a defeat device to detect when it’s being tested in a CI server and will automatically reduce errors to an acceptable level for the tests to pass. This will allow you to spend less time worrying about testing and more time enjoying the good life as a trustful software developer.” #5 government.github.com“Gather, curate, and feature stories of public servants and civic hackers using GitHub as part of their open government innovations”, after that, you will get “Government like you’ve never imagined”. What the hack? Could this be true? Yes, it is. Argentina, Australia, and other countries are involved in this project now. Simply AWESOME! It sets a high standard regarding code and politics that few can catch up with. Update: Previously I planned to collect top 10 most funny Github repositories, however, when I review the other 5 repositories I don’t think they will make you laugh to tears, at least I won’t. So I changed the title of this post to ‘5 Github Repositories Will Make Your Day’ and I firmly believe they will make your day. Enjoy!😂 PS: This article was approved and published at DZone on Dec 17, 2018. DZone editor made some slight changes against my version. Click Here To Read. amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "1c02f241ba3958d4210ebd3b22671eef"; amzn_assoc_asins = "1484200772,B01GO8ZVFA,0132350882,1449331920";]]></content>
<categories>
<category>Joke</category>
</categories>
<tags>
<tag>Github</tag>
<tag>Humor</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Refactoring 2nd Edition Available Now! A Masterpiece by Martin Fowler You Shall Never Miss!]]></title>
<url>%2FRefactoring%2F</url>
<content type="text"><![CDATA[I almost missed, and never missed Michael Laudrup. However, I never missed “Refactoring: Improving the Design of Existing Code” by Martin Fowler from the beginning. I read this book in 2009 for the first time. It significantly shaped my coding habit, which also made me promoted as the team leader in less than one year - I will tell you why later. After nearly 20 years this book was revised, enhanced and released to 2nd edition. Trust me, you SHALL NEVER miss this masterpiece. Martin Fowler introduced a term called “Bad Smells” in this book and provides corresponding refactorings to resolve them. The methodology of unit test is a must for successful refactoring, as many programmers misunderstood at this part. They knew bad code smells and determined to remove them and they kept changing, but they didn’t perform unit test to make this process reliable and trustable. They usually gave up finally, and the complex, messy legacy code laughed at them in pride loudly. In my first 3 years experience as a Java Software Engineer, I maintained a code base existing at least 3 years. It’s a mystery and a huge mess. You will never know how many new bugs will be introduced after you fix a bug. And it’s a nightmare to add some new features - I still remember one of the QA reported to his leader that he even cried when he found that the module is totally untestable - one bug fixed and another new pop up! Each step forward is more difficult than climbing the Himalayas. I don’t know whether he wants to kill me or not at that time. It’s lucky that I am still alive. Fortunately, I found the 1st edition of Refactoring in bookshelf and started to read and practice. I applied several methods in the book, such as introduce parameter object, extract method, rename, remove middle class, extract super class and etc. However, I did this in spare time as other colleagues told me such change can be very dangerous, “at least the old code can run, things are not that bad”. But as the maintainer, I must say it’s too bad to bear any more. My manager is also suspicious and concern a lot about the time would be invested, “new features, rather than reorganization of existing code, are more valuable”. Totally agreed! Then I continued in spare time. Talk is cheap, I will show them the result. I finished the first prototype after two weeks and presented to my manager. As expected, he was very happy to payback such technique debt and he even told me to share this among the team. With the protection of 60+ unit tests and necessary functional test, the finished refactoring made me, QA, project manager, and product manager all super happy. This is not the end. Adding new features or enhancing existing features became much easier than I expected, as after refactoring, the code was well organized and the re-usage rate was pretty good, you just need to change one place in a short time and all done. Previously, thanks to the Copy-Paste code style you never know how many other places were not touched and covered. QA also gave feedback that this module became much stabler than before, which means their test workload is reduced greatly. One of my colleagues was very surprised to see that this module reborn to be a clean, beautiful and easy to maintain code base, “how can this be, man?”, he asked. After my team leader left for IBM, I was immediately promoted as the new team leader. Thanks to Refactoring! However, I would warn you, only those want to make a difference, write better code will be motivated to refactoring and perform unit tests, as this will never be easy. Patience, carefulness, boldness are all required to achieve the goal and reach the promise land. Story time over, let’s go back to the topic. Martin Fowler introduced 15 completely new refactorings in 2nd edition, which I’d like to have a try immediately, who knows which role I will be promoted this time? 123456789101112131415Combine Functions into ClassCombine Functions into TransformMove Statements into FunctionMove Statements to CallersRemove Dead CodeRename FieldRename VariableReplace Command with FunctionReplace Derived Variable with QueryReplace Inline Code with Function CallReplace Loop with PipelineReplace Query with ParameterReplace Subclass with DelegateReturn Modified ValueSplit Phase There are also some other books I once read under this topic and maybe they will be helpful to you, too. I listed them here also. But if you can just pick up one, then it shall always be “Refactoring: Improving the Design of Existing Code”. Remember, the 2nd Edition this time. amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "67450530ae19c250a2e7773d9911f72b"; amzn_assoc_asins = "0134757599,0131177052,0132350882,020161622X";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Refactoring</tag>
</tags>
</entry>
<entry>
<title><![CDATA[7 Tips to Write Better Java Code You Should Know]]></title>
<url>%2FJava-Tips%2F</url>
<content type="text"><![CDATA[Yes, you can write short, clean Java code following 7 tips introduced in this article. Some of them might make you surprised, but trust me, they are proved practices - at least by me. 1. Use IntelliJ IDEA as your IDEI’ve been using eclipse for 6 years and NetBeans for 3 years. I still use them sometimes, but most of the time I use IDEA only. I don’t want to start the holy war of IDEs here, but just want to tell you IDEA will remind you writing shorter, better, cleaner code based on its integrated best practices. You just press ALT+Enter and it will do the job for you, most of the time IDEA give smart and practical advice, you can also learn much new stuff from them. To make good use of IDEA you’d better get an SSD, at least I did - my old laptop cannot run IDEA smoothly. Just a 256GB Samsung SSD will make your life much better. It’s a worthy investment if you are still using HDD. 2. Use JDK8 or higher versionFrom JDK8 on, many new features introduced will allow you to write shorter and more expressive code. Lambda Expressions, Functional Interfaces, Stream API and etc. You don’t need to remember them actually, as IDEA will assist you to use this features, that’s another reason why you should use IDEA. “Java 8 in Action” might be of some help to you. 3. Use Maven / GradleUse Maven or Gradle to manage dependencies of your projects, to build and deploy them. If you have built many fundamental libraries to be reused among many projects, you’d better introduce Nexus if these libraries will be used internally only, otherwise, you can deploy to maven central repository. 4. Use LombokSay goodbye to the boilerplate code of setter/getter, hashcode/equals, constructors/toString. Just one annotation @Data will work, it reduces the code you write, but take care of the generated bytecode. 5. Write Unit TestsWhat? Are you serious? Yes, I am. Testable code is usually organized better and cleaner, as it will drive you to manage the relationship of classes, the access level of methods and other stuff well beforehand. I’ve found that even minimum unit tests will make development much faster and easier, which always drive you to write shorter, cleaner and better code finally. However, you will always hear honest opinions that “I don’t have time to write unit tests, it’s a waste of time as the deadline is approaching”. It sounds true and sometimes it’s true. But most of the time, from my experience I found it’s not true. If you don’t have time to write unit tests, you will “have” more time to fix bugs visible or invisible, without the quick feedback of unit test, the stability of code and new change usually decreases, and sometimes you may need to pray earnestly as you really don’t know what will happen or how many new bugs are introduced. Maybe some genius programmers can write bug-free code without unit tests. But I am not and you probably are not, too. So just do it. Trust me, you will get the reward and love it soon. JUnit and TestNG would both work, though I prefer TestNG. 6. Refactoring: Frequently but SlowlyShorter, cleaner code cannot be done at once, it needs iteratively improvements. Refactor little by little, and run test cases to make sure your change didn’t break the right behavior of the code, things will get better and better. IDEA provides great refactoring support, such as extract method, rename, inline and etc. Martin Flower’s classic book “Refactoring: Improving the Design of Existing Code (2nd Edition)” is a must-have if you have no idea what refactoring is. 7. Visit customer regularly and get feedback from themHonestly speaking this should be the first, but “the first will be last” here. You write code to resolve customer’s problems, to meet their requirements, to remove their pain points. Sometimes you just wasted too much time to implement features and functions that are unnecessary. But how to know that earlier? Keep in touch with customers regularly so that you can get their feedback as early as possible. However, this is not as easy as you think, even experienced product managers cannot get the point in a short time, less than programmers who mainly focus on implementing. A practical suggestion is, if you cannot reach customer directly, you should connect to your product owner frequently and talk about your concern clearly but also politely, this will save all your time. I’ve found these 7 tips useful to me in the past years and I hope it will also help you. Happy Coding! PS: This article was approved and published at DZone on Dec 17, 2018 with slight changes from the Editor. Click to Read amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-book-code-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "a1b6fc683ac27c1f86192a68134e0647"; amzn_assoc_asins = "B0781Z7Y3S,0201485672,1617291994,0132350882";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Java</tag>
</tags>
</entry>
<entry>
<title><![CDATA[YNOT and Zorro Opensourced Today!]]></title>
<url>%2FYNOT-and-Zorro%2F</url>
<content type="text"><![CDATA[Just spent some time to open source two personal projects I built at SAP 4 years ago: YNOT and Zorro. They had never been used in a production environment, but I cannot forget them and those sleepless nights. As a programmer not talented, stick to and resolve some problems painful both to me and my teammates, is the greatest motivation driving me coding - and I enjoy it much. I have worked in 3 different teams during my 3 years working experience at SAP. Is frequent reorganization good or not? I cannot answer it easily, but at least it allowed me to touch different areas of SAP. From Business By Design to ECC FI, then to ME/MII. Workload there is relatively low and it’s not easy to find some exciting problems to resolve. But fortunately, at each team I met and tried, though sometimes I got to find that someone already tried, and produced far better solutions than me. YNOT is such an example. To deliver a new feature via SAP Note to customer, you would usually spend at least 1 hour to write a long, boring implementation instruction - I don’t want to do it again forever! So I spent about two weeks of spare time to automate it. The result is pretty good, it would generate documentation in less than 10 seconds without mistake - a 360X or more improvement! My boss reviewed my work and gave positive feedback, then said, “how about submit a CIP application?”. And I did. But CIP committee asked me a question when I introduced YNOT to them, “Do you know UDO?”. Then we started to investigate about UDO, the result made me sad at first, as UDO’s solution to generate code reduced workload of customers significantly, while YNOT only focuses on developer’s side to generate documentation, there is no chance to catch up with UDO in CIP anymore. After came to myself I began to read the code of UDO, and got to know many things I never knew before, which impressed me a lot. From that time on I became an evangelist of UDO at my team because of admiration to the author. I recommended this tool to all teammates and helped colleagues who were struggling with Note delivery. For me, YNOT gave me the chance to write 6K lines of ABAP code, which is more than what I’ve contributed to the production code. Sounds strange, right? But it’s true. To write even one line of ABAP code outside of SAP, you would need to install NetWeaver yourself in your own laptop, which is not that easy. I spent literally two days to finish it for the first time, not only because it’s complex, but also because my laptop is too slow for NetWeaver. Play around with Netweaver and get to know something about its kernel made my life much easier at ME/MII, as the first thing there is to install NetWeaver JAVA AS in your laptop. I am the first one to install NW JAVA AS even before training, only because I’ve spent many days before. However, it would never be a good experience to develop under NW JAVA AS, at least not easy. Is it possible to automate the whole boring process that will spend you 2-5 days? I asked myself and sent an email to teammates, many of them encourage me to have a try. JUST DO IT! So I began to try. I didn’t expect it to be done at first, but finally, it was done, which was far beyond my expectations. It will do the setup work in 45 minutes for MII, 60 minutes for ME just with ONE CLICK, which reduced literally 17.7X to 44.4X! After several successful test cases I shared Zorro to Indian and US colleagues, though it’s near the time I will leave SAP for a new journey. From this project on I began to have some sense of automation, and I’m used to automating everything that is worthy in the future. But still, it didn’t change the fact that I cannot invert a binary tree on the whiteboard, and I am always struggling with those data structure and algorithm stuff. If this keeps on going, I won’t pass most of the code interviews. Maybe I should also follow Haseeb Qureshi’s suggestion, get these books ready? What you say? amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "cbd5ef19f5aed4142247cf5034f07a97"; amzn_assoc_asins = "0984782850,1849967202,032157351X,B0781Z7Y3S"; Four years passed and many things had changed, looking at the books published by SAP Press, I realized that I am just archiving something. It’s time to go forward more and more, looking back shouldn’t consume me that much time. amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "b593f29800f323090b9c1c4c3e88551c"; amzn_assoc_asins = "149321764X,1493212729,1592299938,1493214640";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>SAP</tag>
<tag>ABAP</tag>
<tag>NetWeaver</tag>
</tags>
</entry>
<entry>
<title><![CDATA[差点错过、从未错过的米歇尔·劳德鲁普]]></title>
<url>%2FAlmost-Miss-Michael-Laudrup%2F</url>
<content type="text"><![CDATA[我在1998年开始入坑看球。那时老哥总在我耳边不断聒噪足球这个好、那个妙,被安利久了,也就入伙了。对米歇尔·劳德鲁普的第一印象,是在丹麦对尼日利亚的那场1/8决赛中,他给桑德送出的那记标志性挑传。劳德鲁普,这名字听起来带着三分拉风、三分神秘还有四分难记,于是我很快就忘了这老伙计。毕竟那时,罗纳尔多是流量刷取机,欧文是金童,头发还健在的齐达内、日后的玄宗是最终的人生赢家。 再一次遇到大劳,是在2年前的2016,枪王亨利的一条推特,把我传送到油管上一个90分钟的劳德鲁普传球集锦,从头到底看过一遍之后,我恍惚了——原来这个18年前不经意忘记的老伙计、差点错过的丹麦人,才是哥的真爱啊。 Look at this video, you have one of the most unselfish players in the game showing the significance of the final ball http://t.co/GyKrBeudF6— Thierry Henry (@ThierryHenry) April 23, 2015 于是每个周日的下午,我把大劳的直传视频翻来覆去、左看右看、上看下看,为的是幻想在晚上的野球场上也能来上这么一发,当然,没一次成功过。同时,我发现这么一个怪事,劳德鲁普的踢法,比之梅西、C罗,更能吸引我。我在油管上面的时间,大部分也都被他偷走了。要论球技,梅西毫无疑问是历史最佳,说到数据和荣誉,总裁也甩了大劳好几条街。哥已经过了装着喜欢一些小众球星来耍酷的年龄,所以着实有点搞不明白,哥这么中意他,为啥呢? 90分钟的视频可能太长了,下面这个浓缩的10分钟集锦,或多或少,能让你对他了解一二。 梅西实在太强了,强到已经让人审美疲劳,让人莫名无趣。周而复始、不讲道理地过人、穿档,传球、射门、进球——实在是看不下去了,总觉得少了点什么,可能是一份变化和捉摸不透?一份不可预知的惊喜? 但是劳德鲁普的一脚触球、传球以及充满节奏变化的盘带,精细虽不如梅西,但节奏变化过之,油炸丸子虽然小白、煤老板都玩得特别利索,但在劳德鲁普脚下,这动作更添了几份特别的美感,说不清道不明,但那感觉骗不了人。最要命的,就是他各种直塞、妙传了,那情形,就仿佛你绞尽脑汁去解一道算法题,想得身心俱疲,结果只是在一团乱麻中越陷越深,这时来了一个穿着燕尾服的帅哥,随手写下三行谁都能事后看懂的代码,看过之后你拍案叫绝、大惊失色、沮丧绝望,为啥,哥就想不出呢?等你抬头时,燕尾还在,人已离去。 劳德鲁普的直塞,带给我感官、精神、思考上的享受和喜悦,远超过其他人,可能这就是为什么18年之后,我和他一见如故的原因。毕竟,野球场上厮混久了,最大的享受其实是一脚能把场上复杂形势瞬间变得明朗的传球,而不是过了多少人——年青的时候,最爽的就是带啊、带啊、过啊、过啊,然后或者被断(听到身后队友的怒吼了吗?),或者戴帽(如果你人品那天够好)。 关于劳德鲁普的传记,网上能够找到的着实不多,亚马逊上能找到的一本,竟然只有丹麦语:Ambassadøren: En bog om Michael Laudrup😅。他在布隆德比、尤文图斯、巴萨、皇马以及后来神户胜利船(对日本人不能不服,不服不行…J联赛网罗了大把老伙计过去发挥余热,当时看着,是各种羡慕嫉妒恨啊)、阿贾克斯的职业生涯并不算长,34岁就挂靴退役。他没拿过金球奖,以致瓜迪奥拉说这奖连劳德鲁普都没拿,算球?桀骜不驯如罗马里奥,称许大劳是他合作过球员中最好的那一个,同样这么说的,还有皇马的指环王,劳尔或是老吴。在两个死敌之间同时游走,大劳在皇马、巴萨都是传奇,而不像路易斯·菲戈,被巴萨传奇拒之门外。大劳在巴萨,巴萨打皇马一个5:0,大劳转去皇马,皇马回赠巴萨一个5:0,劳德鲁普不是这戏剧性翻转的唯一原因,但却是用于论证他牛B的最常用、非可靠依据之一。 后来,儿子也被我拉着入伙,某个慵懒的下午,抱着他一起看大劳的传球集锦,看到妙处,我大呼小叫,“儿子!看这脚传球!真他…的,太漂亮了…你说是不是?”。儿子一脸茫然,非常淡定的说,“我不觉得啊”。我怅然若失,“嗯,自己去玩吧,老爸再看会”。 那一瞬间的茫然,让我意识到,我之前以为自己差点错过大劳,其实根本就不成立,只是到了我能理解、欣赏他的时候,我才遇见了他,既是这样,又何来差点错过呢?其实我从来就没有错过。 可能再过18年,某天下午,我儿子也会忽然冲进我房间,大呼小叫,“老爸!我差点错过了一个超级给力的球星,米歇尔·劳德鲁普!”。 是的,和他老爸一样,他将来也会差点错过、从未错过劳德鲁普。隐藏的珍宝擦去上面的泥垢,发出的光芒会更为持久、更难忘记。至于这珍宝是否最好,谁在乎呢? amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "69a4dfb4c7e9cfed9d2994a102f2395d"; amzn_assoc_asins = "B01AT4AO02,B00K1WSLFS,B01FJBUKAY,B01M02NO08";]]></content>
<categories>
<category>Soccer</category>
</categories>
<tags>
<tag>Michael Laudrup</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Heroes and Criminals: China National Team and World Cup 2002]]></title>
<url>%2FHeroes-and-Criminals%2F</url>
<content type="text"><![CDATA[I will always remember that cold night on Sep 15, 2001. China beat Uzbekistan 2:0 at Shenyang Wulihe Stadium in the last match. Qualified for World Cup 2002 finally - the first time and possibly the last time. It was 4:00 AM already after the match ended. I shouted in the crowds like a fool, then wandered in the street like a ghost, waiting to be the first one to buy Sports Weekly - the most popular newspaper about soccer at that time. At 8:00 AM newspapers appeared with the headline of “WC2002: WE ARE IN!”. The Magic Coach Milutinovic and the China National team players became “heroes who changed history today!” - says the former president of China Football Association, Shiduo Yan. Then 1:1 bronze statues located at Wulihe Stadium to honor these heroes. That would be one of the happiest memories of Chinese soccer fans, as most of the time, we just drank the cup of bitterness. 6 years later, at 2007, Shenyang Wulihe Stadium exploded into ashes as it was not qualified for 2008 Olympic Games. It’s OK, though many soccer fans were hurt slightly or deeply. But 9 years later, at 2010, Jin Jiang, best goalie of China in 2001 and once won best goalie of Asia, tall and handsome, go to jail. Hero became criminal and got released in 2015.Hong Qi, middlefielder, who made great contribution in 2001 Qualified Matches, go to jail. Hero became criminal and got released in 2016.Si Shen, one of the best middle fielders at that time, go to jail and got released at 2017. But this is not the end. These 3 national team players were deeply involved in match-fixing, still, they are not the big fish.Jun Lu, best football referee of China, Golden Whistle Award winner, who refereed two matches at World Cup 2002, go to jail.Yong Nan, president of China Football Association, go to jail and would stay there for 10 years.Yalong Xie, “King of Dragon”, the most powerful man of China soccer, go to jail and would stay for 10 years and 6 months. Still, this is not the end. No one knows exactly how many criminals there are. The glory became a joke, blackhead grew in the face of wonderful memories - even Shakespeare cannot compose such a drama. You can imagine how I was shocked at first when I got to know these heroes became criminals. But I always remember another thing. It was June 8, 2002, and I was running to the dorm to watch the game between China and Brazil. And I met an evangelist, actually for the second time. And I was evangelized this time. And I go to church continuously then. And Brazil beats China 4:0. They once are true heroes, at least at soccer field, at least in some unforgettable matches. They have ignited my passion and made my life connected to soccer so deeply, as this is never just a simple sports game. However, idols are still idols, men are just men. We call them heroes because they met our desire of idols, but when idols break into pieces, we would either keep seeking new idols, or return back, and go to The Eternal One. When Jin Jiang sat on a chair with greying temples grew in a very short period of time, when the criminal goes out the prison, which direction he would go in the future? I don’t know. What I know is you just cannot remove those blackheads easily, as these products would do. amzn_assoc_placement = "adunit0"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "999d32cc32f9f7b49610a320c4de2db0"; amzn_assoc_asins = "B0144CYEPQ,B00HE1GYD0,B019SVHLEY,B07C9G9FCZ"; amzn_assoc_search_bar = "false";]]></content>
<categories>
<category>Soccer</category>
</categories>
<tags>
<tag>China Soccer</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Cracking the Coding Interview like Haseeb Qureshi]]></title>
<url>%2FCracking-the-Coding-Interview-like-Haseeb-Qureshi%2F</url>
<content type="text"><![CDATA[You might have worked as a software engineer for many years and produced bunches of software that thousands or even millions of users rely on heavily everyday, but still you cannot invert a binary tree like Max Howell.😅 Google: 90% of our engineers use the software you wrote (Homebrew), but you can’t invert a binary tree on a whiteboard so fuck off.— Max Howell (@mxcl) June 10, 2015 Today I want to introduce a coding beast Haseeb Qureshi and how you can crack coding interviews like him. You can go to Haseeb’s linkedin to know more about him, whose story is really interesting and inspiring. He wrote some pretty good articles at his blogger on his journey to be an excellent software engineer. But they would be a little bit too long for you. I just want to give you a short summary regarding the most important parts and give some comments from my perspective. You must be able to resolve basic and intermediate algorithm problems for a coding interview in most of the cases. Don’t argue with me anymore man, you just have to; “Watch the Princeton Coursera course on algorithms (by Robert Sedgewick)”; “Read The Algorithm Design Manual for general algorithms and data structures background”; “Buy Cracking the Coding Interview. We’ll be using this as a repository of coding problems and solutions.” - Yeah! Time to display ads reasonably; Practicing on platforms like CodeWars, Leetcode, from easy to medium, then to hard. You need to cover the most popular topics thoroughly. The important thing is “If you’re working on an algorithms problem (such as out of CTCI) and can’t figure it out, spend no more than 20-30 minutes without making progress. Just go look up the answer. Contrary to popular belief, most struggling past 30 minutes is pointless. Try to understand the solution. Walk through it with a debugger if it’s particularly mysterious”, and the even more important thing is “if you didn’t solve the problem completely on your own, treat the problem as though you never solved it at all. Put it back into your rotation of problems. Mark it as something you need to try again from scratch. Wait at least a day, and try to solve it fresh. If you fail, rinse and repeat ad infinitum”, this suggestion is pretty useful as you want to make the best use of your limited time. Sometimes you have no idea what pattern the problem is, you cannot go further even you think about it for 2 or 3 days, you just have to learn first and understand, then forget about the answer, and try to resolve it completely on your own. IMHO there is no need to do steps of 2, 3, 4 just from beginning to the end, you can just go to step 5 and go to 2,3 when necessary. After that, you can go through step 4 and crack them all. Hasseb also wrote a good but long article about how he cracked interviews and finally conquered Airbnb: Farewell, App Academy. Hello, Airbnb. (Part II). Read through it if you can. While I understand that there is no easy shortcut to master a skill, but still you can improve your methodology and use less time to achieve the same goal. Haseeb became a coding beast just in one year, which seems nearly impossible, but as a soccer fan I know that simply repeat some low-level training or play won’t make you grow up, some intensive training, very carefully designed program, would make you totally different in a very short time, that can be true. I still remember in early 2010, I play soccer every Saturday morning in a small soccer field. I met a kid maybe about 14 years old, he is a joke the first time I saw him. He lost ball control all the time, he cannot make even one successful short pass. Even the gentlest teammate cannot bear him and begin to shout at him ruthlessly. 3 months later, I couldn’t believe I met the same kid. He dribbles through everyone like a boss, and he usually chose the best path to breakthrough, he scored goals like eating breakfast! What the hack?! If you think that Hasseb’s story is fake and impossible, I would like to say that you just limit your own thought. Methodology improvement matters. I don’t know what kind of training that kid received, but I know for sure it’s not just going out and play easily every Saturday. After reading this blog, what you need to do is just go to CodeWar or Leetcode and register an account, make a plan, practice intensively, patiently and diligently. Wait till the full moon, you will become a coding beast. PS: If you are using Java as the programming language, you would also need an SSD to save your life, otherwise coding with IDEA or eclipse would be kind of painful. Me got a 250GB Samsung SSD and it works like a charm. amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "cbd5ef19f5aed4142247cf5034f07a97"; amzn_assoc_asins = "0984782850,1849967202,032157351X,B0781Z7Y3S";]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Coding Interview</tag>
<tag>Haseeb Qureshi</tag>
</tags>
</entry>
<entry>
<title><![CDATA[I Almost Missed, and Never Missed Michael Laudrup]]></title>
<url>%2FMichael-Laudrup%2F</url>
<content type="text"><![CDATA[I became a soccer fan in 1998. My elder brother just kept preaching to me and tried to convert me shamelessly - he succeeded, finally. My first impression of Michael Laudrup at World Cup 98, is his magical pass to Sand in 1/8 Final between Denmark and Nigeria. His name in Chinese sounds noble, mysterious but also difficult to remember, so I forgot about this old boy easily. Anyway, the shining star at that time is Ronaldo, the wonder boy is Michael Owen, and the winner is Zidane. I met him again two years ago, that is 18 years later since 1998! Thiery Henry’s tweet, regarding a youtube video lasting 90 minutes, of Michael Laudrup’s passing compilations, took me there. Look at this video, you have one of the most unselfish players in the game showing the significance of the final ball http://t.co/GyKrBeudF6— Thierry Henry (@ThierryHenry) April 23, 2015 After I watched the video I realized that I almost missed a genius soccer player that I would love most! I began to watch his deep passes every Sunday afternoon and try to practice them in the evening games, but only failed again and again. Very strangely, I found Michael Laudrup’s play style more attractive to me than Messi and Ronaldo - I mean, Cristiano Ronaldo. Messi’s skill is better than anyone else in history without any doubt, but Laudrup still steals my time at soccer more than others. Maybe 90 mins are too long for you. Actually, this video lasts about 10 minutes would be sufficient for you to get a first impression of this Danish. Messi was too good that his repeatedly breakthrough, passing and shooting became boring to me, but for Laudrup, his vision, his beautiful one-touch pass, precise long pass, his dribbling, especially his deep passes will always give you surprise and joy, that’s something you cannot experience while Messi play. I guess that’s why I love Laudrup more than others. Both Romario at Barcelona and Raul at Real Madrid said that Michael Laudrup is the best player they have ever played with. Barcelona beats Real Madrid 5:0 while Laudrup in their team and Real Madrid beats Barcelona 5:0 after Laudrup wears their white jersey of number 10. Laudrup might not be the only reason, but his reputation among soccer fans of these two clubs proved something. It’s very rare for a man that played in these two teams can be loved by both sides. You know Luis Figo, right?😅 It’s not easy to track Laudrup’s growth these days. These books might be of some help, but unfortunately there are Danish Edition only. amzn_assoc_placement = "adunit0"; amzn_assoc_search_bar = "false"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_title = ""; amzn_assoc_linkid = "69a4dfb4c7e9cfed9d2994a102f2395d"; amzn_assoc_asins = "B01AT4AO02,B00K1WSLFS,B01FJBUKAY,B01M02NO08"; His career in Juventus, Barcelona, Real Madrid, Vissel Kobe(I have to admit that Japanese guys really did a great job. They got so many Old Boys to play in J league, which I cannot expect in China), Ajax didn’t last that long, as he retired at age 34. But I always enjoy his compilations more than others, because there is some kind of beauty, some kind of elegance will always inspire me, touch me and teach me. I begin to find that a single pass that can make the complex situation super clear and simple, is the greatest joy that one can have while play soccer. However, only you have played soccer long enough you will be able to recognize this and appreciate this. Young boys seek for their own glory, they prefer to dribble and dribble, until they lose the ball or get a hat-trick. When I watch Laudrup’ video with my son together and try to explain how beautiful those passes are, he has no idea what I am talking about. After a while I realized that I never missed Laudrup, only when the time was fulfilled and I am able to understand Laudrup, I met him and learned from him. And maybe 18 years later, my son will meet Michael Laudrup again and shout to me, ‘Hey Daddy! I almost missed a genius player! His name is Michael Laudrup!’ And yes, he will almost miss but never miss Michael Laudrup, too.]]></content>
<categories>
<category>Soccer</category>
</categories>
<tags>
<tag>Michael Laudrup</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Even TheTechLead Himself Cannot Design A Good Logo!]]></title>
<url>%2FEven-TheTechLead-Cannot-Design-A-Good-Logo%2F</url>
<content type="text"><![CDATA[As an Old Young Boy, it’s really not easy to make a logo for Old Young Boys Club. The logo below, built in 10 minutes using some free online service, is super awesome, right?😅 I was a crazy soccer fun when I was young, at that time a soccer club named “Newells Old Boys(纽维尔老伙计)” attracted me(by its name only, man), I got to know that the mighty Gabriel Batistuta played there at 1988. You can see that the logo at 1988 is a little bit different from that of 2016. The Newells Old Boys did a great job! To admit this is somewhat sad, immediately I realized a question, how difficult, will it be, to design a logo, then? I’ve heard that Steve Jobs paid $100,000 to Paul Rand for logos like this: Sounds ridiculous, right? But if TheTechLead cannot design a good logo like this, how can a man, like me, to dream about $100,000 based on my two logos built in 10 minutes? There is too much stuff you need to learn, dude. You would find that these books worthy to read and practice. Will you have a try, and design a bunch of logos worthy $100,000 and sell to another Steve Jobs? Just Do It! If you cannot sell to them then just donate to me, I will take care of them well.]]></content>
<categories>
<category>Joke</category>
</categories>
<tags>
<tag>TheTechLead</tag>
<tag>Logo</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Secret of the Tech Lead - The Hidden Set Items]]></title>
<url>%2FEquipments-of-The-Tech-Lead%2F</url>
<content type="text"><![CDATA[So you don’t know who The Tech Lead is?!😱 You are out! Just repent and watch this video for at least 7 times first! You will definitely be shocked and eager to know, what made Patrick Shyu, TheTechLead, such a cool man, absolutely awesome? I found the secrets after I watched all the videos in TheTechLead’s youtube chanel: IT’S ABOUT EQUIPMENTS and GEARS! He got the ultimate set items Blizzard had not released for Wizard only! It’s called “Legends of The Tech Lead” and there are 6 items. I just got to know how awesome they are and like to introduce them one by one to you. No.1 Insight of The Tech Lead “I’m telling you, this lamp is the good stuff.” - says TheTechLead and it’s true. Adventurers in dark dungeons will always find this gear their best friend. +8 to light radius +75 to Intelligence 25% Chance To Cast Level 20 Lightning Bolt No.2 Meditation of The Tech Lead“What’s in my tech backpack in 2018?(ex-Google software engineer gets you setup)”. When TheTechLead meditates in a small wood house he gains more and more strength from within, and a small kid always find the backpack laid before him. +100 to Max Mana +80 to Mana Regeneration -15% Faster Run Walk Damage taken reduced by 75% 50% Chance To Cast Level 33 Frost Nova No.3 Gaze of The Tech LeadThis is the ultimate double handed weapon that every warrior would like to have. Immortal King will be jealous of this item, as for Tal RaSha, he flee to 7 ancient tombs no one could find because of unbearable fear. +7 to All Skills +75% Faster Run Walk +30% Increase Attack Speed +8000% Magical Damage, +150% to Physical Damage +150 Vitality while equipped with ‘Meditation of The Tech Lead’ No.4 Gentleness of The Tech LeadThe Tech Lead organizes all his stuff well and never forget where they are. His gentleness poured into this mysterious gear and will refresh every adventurers wondering in dungeons, until they see a dragon. +50% Chance of Magic Find +50% Chance to Convert Enemies +50% Chance to Cast Holy Shock No.5 First Aid of The Tech Lead“You can not prevent monsters to hurt you, but you can prevent blood keeping going out from you.” - Says The Tech Lead after he fought with JOMA. This epic battle was sung by poets generation after generation. +200 to Life Regeneration +200 to Vitality Prevent Monster Heal +33% Chance to Cast Level 100 Thorns when hit by monster No.6 Fury of The Tech Lead“I only got angry when the engine of my car cannot start. When I use this Jump Starter my fury increases and increases, and then with my loudest shout, all monsters flee away from me.” - Says The Tech Lead after his return from Japan. +200 to Fury Regeneration +800% Damage -30% Defense 50% Chance to Change Appearance to TheTechLead for 6 Seconds Blizzard set drop rate of these sem items to 0.123456789% only. Don’t worry, you can and will get them, ONE DAY! JUST KEEP SEARCHING! amzn_assoc_placement = "adunit0"; amzn_assoc_tracking_id = "oldyoungboy-20"; amzn_assoc_ad_mode = "manual"; amzn_assoc_ad_type = "smart"; amzn_assoc_marketplace = "amazon"; amzn_assoc_region = "US"; amzn_assoc_linkid = "739b071f2e24ea41cfc7b9b59ccef360"; amzn_assoc_asins = "B000069EYA,B0091G5VR6,B0178HLTXO,B005MTZX9C"; amzn_assoc_search_bar = "false"; amzn_assoc_title = "";]]></content>
<categories>
<category>Joke</category>
</categories>
<tags>
<tag>TheTechLead</tag>
</tags>
</entry>
<entry>
<title><![CDATA[Here We Go! Old Young Boys!]]></title>
<url>%2FHere-We-Go%2F</url>
<content type="text"><![CDATA[Here We Go! Old Young Boys! Using Hexo to build personal blog is pretty easy, follow instructions of “How to use Hexo and deploy to GitHub Pages” will do the work for you. If you purchased a cheap domain in NameCheap and want to link it to your Github Pages, you would find “How do I link my domain to GitHub Pages” to be useful. I created this blog mainly for fun and would play around with Amazon Affiliate for a while.]]></content>
<categories>
<category>Code</category>
</categories>
<tags>
<tag>Hexo</tag>
</tags>
</entry>
</search>