<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:thr="http://purl.org/syndication/thread/1.0" gd:etag="W/&quot;AkMCSHk4eip7ImA9WhRRFU0.&quot;"><id>tag:blogger.com,1999:blog-36484905</id><updated>2011-11-28T20:27:49.732+01:00</updated><title>Pawel Badenski's IT Realms</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/" /><link rel="next" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default?start-index=26&amp;max-results=25&amp;redirect=false&amp;v=2" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>35</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="self" type="application/atom+xml" href="http://feeds.feedburner.com/ObjectOrientedRealms" /><feedburner:info xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" uri="objectorientedrealms" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com/" /><entry gd:etag="W/&quot;AkMCSHk_eyp7ImA9WhRRFU0.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-7815895891173736313</id><published>2011-11-28T20:12:00.001+01:00</published><updated>2011-11-28T20:27:49.743+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-28T20:27:49.743+01:00</app:edited><title>A serious take on Data-Rich Development - Part 2</title><content type="html">In the last part I explained how
I managed to prepare the histogram of class changes across issues. This was
certainly not everything that you can do with the data that I generated. The
next step was to get more detailed information on each class. I decided that
for sure I want to see how number of modifications changed over time and to
achieve this I prepared a chart you can see below; it shows how many issues
“changed” this class at a specific moment in time (month being the resolution)&lt;span class="MsoPageNumber"&gt;&lt;sup&gt;&lt;span style="font-family: &amp;quot;Calibri&amp;quot;,&amp;quot;sans-serif&amp;quot;;"&gt;1&lt;/span&gt;&lt;/sup&gt;&lt;/span&gt;:&lt;br /&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-TTewLWIYq9A/TtPeWZ-ynLI/AAAAAAAAAMU/Qz3vJ2fJQY8/s1600/modifications-1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-TTewLWIYq9A/TtPeWZ-ynLI/AAAAAAAAAMU/Qz3vJ2fJQY8/s1600/modifications-1.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
Note that in this case I decided
to use standard line chart since the information that I wanted to present is not
really that complex – I certainly don’t want the “cool charts” to become my
golden hammer. It is also worth noting that after using this data for some time
I decided to normalize Y-axis, so I can compare metric on different classes at
a glance. See for instance second example below, where you can clearly see that
over time number of both modifications and defects decreased – it’s not marked
as sharply as on stock market, but if you see a number of these charts (one
above being an example), the existence of a trend becomes obvious.
&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://4.bp.blogspot.com/-T-U2qxma8-k/TtPeXxl86rI/AAAAAAAAAMc/egH_1daQ1Ak/s1600/modifications-2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://4.bp.blogspot.com/-T-U2qxma8-k/TtPeXxl86rI/AAAAAAAAAMc/egH_1daQ1Ak/s1600/modifications-2.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
It’s still hard to say whether
this trend means good or bad – it is obvious that this class doesn’t get
changed, but it still can mean that certain problems exist, eg. the class got
too big and rarely any modification is justifiable by a business reason.&amp;nbsp; To nail down the cause, you’d need other
metrics to provide you more context. I’ve been already thinking of possible extensions
that could exploit more sophisticated ways of visualization, when for example one
could be able to see how size of a class changes on the same timeline.
Theoretically it would be awesome to see coverage there as well but this is
unfortunately not possible in our case – if you however can do it, go for it,
I’d be thrilled to see that. And if I were to choose how to visualize that I’d
probably go for a chart a’la &lt;a href="http://www.gapminder.org/"&gt;GapMinder&lt;/a&gt; which sort
of out of the box would enable having combined view of metrics for many classes
at the same time. Anyhow, I’m not sure which information would benefit you the
most, but it’s very much worth exploring &lt;span style="font-family: Wingdings;"&gt;:)&lt;/span&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
I was not planning to explore
this problem in an orderly fashion of any sort, because when I research a topic
I like to do a bit of jumping from one thing to another which helps me get a
better grasp on all aspects of the particular problem). I decided that for a
next step I want to go more into the correlations of classes across issues (I
again got inspired my Michael Feathers – &lt;a href="http://michaelfeathers.typepad.com/michael_feathers_blog/2011/09/temporal-correlation-of-class-changes.html"&gt;http://michaelfeathers.typepad.com/michael_feathers_blog/2011/09/temporal-correlation-of-class-changes.html&lt;/a&gt;).
The first visualization that got created out of this concept was a graph of all
possible correlations (ie. classes that get changed together as a part of the
same issue) above certain threshold for whole project and it looked like that:
&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://1.bp.blogspot.com/-ciC2NkH-6OA/TtPeVq36g6I/AAAAAAAAAMM/MT_9YK5EL78/s1600/graph.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-ciC2NkH-6OA/TtPeVq36g6I/AAAAAAAAAMM/MT_9YK5EL78/s1600/graph.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
The size of a node (representing
a class) is proportional to the aggregate number of issues when a class was
changed together with other class, and correlation is depicted as a link
between the two. This visualization certainly looks cool and also is
interactive – you can pan the area, zoom, move nodes around… actually &lt;a href="http://mbostock.github.com/protovis/ex/force.html"&gt;look foryourself on Protovis site&lt;/a&gt;.
What’s the downside then? There’s just too much information – it does show you
an overview of areas having a strong coupling (see yellow), it will highlight
boundaries of application modules (see blue), but it’s almost impossible to get
more specific information out of it. So it’s good as a start but you need a
next step here, something that would let you dig into the details why the
situations is as it is and whether you should do something about it.&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
I’m planning on describing ways
of resolving this in Part 3 so for now let me just show you another way of
visualizing the same information. What I’m going to present is IMHO much more
useful when you need to focus on the correlations (especially identify where
they don’t make any sense) rather than classes (correlations lower than 3 were
filtered out):
&lt;/div&gt;
&lt;br /&gt;
&lt;div class="separator" style="clear: both; text-align: center;"&gt;
&lt;a href="http://3.bp.blogspot.com/-bjIyLcf6jB4/TtPeUt0Sd2I/AAAAAAAAAME/oNkCVVk-Tko/s1600/circle.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"&gt;&lt;img border="0" src="http://3.bp.blogspot.com/-bjIyLcf6jB4/TtPeUt0Sd2I/AAAAAAAAAME/oNkCVVk-Tko/s1600/circle.png" /&gt;&lt;/a&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
The concept is quite similar to a
previous one: nodes are classes, links are correlations. Then, around the whole
circle classes are positioned in a specific sort order – by package name.
Having them in such an order let’s you apply a simple heuristic – whenever
there’s a link between a two remote locations of a circle there is potential
unnecessary coupling between two separate packages… and while there may be a
relationship in the code it’s at least suspicious if these classes get changed
together too often (change frequency is represented by color, increasing from
green to red). On the other hand even if the correlations are close (in the
same package), but there are lots of it, it still can have negative meaning – for
example the package may be too large. I didn’t play much with this
visualization so there may be many other ways of analyzing and getting valuable
information out of it. Moreover there’s an amazing tool for doing &lt;a href="http://circos.ca/"&gt;much morepowerful visualization of this kind&lt;/a&gt;, and as soon as I learn
how to use it, I’ll write more on its potential.&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
In the next part… right, I’m not
gonna lie to you, I have absolutely no clue about the next part, besides that
there’s going to be one. Maybe I’m going to get more into the detail how I
decided to present information for a single class… or maybe I’ll describe
possible use cases to you can employ these charts for… or something totally
different. Not sure – stay tuned.&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;hr /&gt;
&lt;span style="font-size: x-small;"&gt;1.&amp;nbsp; If you happen to have the length and scope of
different issues wide-spreaded this metric will count all changes within single
issue as one and result in overestimating importance of “quick fixes” and
underestimating “long enhancements”. Because of that recently I modified this
metric not to count all modifications in a single issue as one, but instead do
it per-day basis. Then if a file is modified many times on different days, the
number of days when it’s modified is the number we’re looking for.&lt;/span&gt;&lt;/div&gt;
&lt;span style="font-size: x-small;"&gt;
&lt;/span&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-7815895891173736313?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/7815895891173736313/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2011/11/serious-take-on-data-rich-development_28.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/7815895891173736313?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/7815895891173736313?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2011/11/serious-take-on-data-rich-development_28.html" title="A serious take on Data-Rich Development - Part 2" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/-TTewLWIYq9A/TtPeWZ-ynLI/AAAAAAAAAMU/Qz3vJ2fJQY8/s72-c/modifications-1.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;A0EBSHY9eyp7ImA9WhRSFEo.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-2982285033575000719</id><published>2011-11-09T21:21:00.000+01:00</published><updated>2011-11-16T22:40:59.863+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2011-11-16T22:40:59.863+01:00</app:edited><title>A serious take on Data-Rich Development - Part 1</title><content type="html">&lt;div style="font-family: Georgia,&amp;quot;Times New Roman&amp;quot;,serif; text-align: justify;"&gt;
&lt;blockquote class="tr_bq"&gt;
&lt;span style="font-size: small;"&gt;“It's about taking the data that we
have at hand in our development work and really using it.&amp;nbsp; If we are
making a decision about whether to refactor a piece of code, we should be able
to see its churn and complexity trends, and tie them back to events that
happened over time, and the actual features which triggered the work.&amp;nbsp;
Right now, it seems that we often look at our decisions through the pinhole of
the present, ignoring what we can learn from our code's past.”
&lt;/span&gt;&lt;/blockquote&gt;
&lt;/div&gt;
&lt;div align="right" class="MsoNormal" style="text-align: right;"&gt;
&lt;span style="font-size: x-small;"&gt;Michael Feathers, &lt;a href="http://michaelfeathers.typepad.com/michael_feathers_blog/2011/03/data-rich-development.html"&gt;Data-Rich Development&lt;/a&gt;&lt;/span&gt;&lt;/div&gt;
&lt;br /&gt;
&lt;div style="text-align: justify;"&gt;
A few weeks ago I had a very fruitful
conversation with my colleague Bogdan Lachendro
from the team at &lt;a href="http://www.sabre.pl/"&gt;Sabre Poland&lt;/a&gt;. Yet again we started
discussing Technical Debt and I can assure you it is not an easy topic if you
consider project of our magnitude (15 years of development, millions line of
code). The crux being that you want the best way there can be to identify code spots
you need to fix, as your time is limited and the potential areas to clean up is
almost infinite.&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
&lt;br /&gt;&lt;/div&gt;
&lt;div style="text-align: justify;"&gt;
&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
What to do... what to do…&lt;/div&gt;
&lt;br /&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
You might think – boy-scout rule!...
and yeah sure that’ll help, but on a humongous codebases it got a nasty habit
of working rather like a shotgun – sometimes you fix the code that really
needed it, and for the most of the time you don’t… continuing with a metaphor, if
you shoot long enough you might get lucky and hit the target more often than
not. So it’s fine to do it, yet IMHO it helps to keep the entropy from increasing,
but it’s not really as helpful as you would want it to be.&lt;/div&gt;
&lt;br /&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
At this point I can hear you
screaming – code metrics bro’, code metrics! PMD, Sonar, FindBugs! Ok, cool –
they’re fun to use, but if you’ve ever worked on a project of that size you
know how that ends up. You get sooo many warnings that you don’t even know
where to start. Again – cool stuff, but without extra cues, it won’t fly.&lt;/div&gt;
&lt;br /&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
What we really needed, was a
method that’d tell us how we can get the best bang for the buck. We needed to
have something that’d help us deliver faster, easier, have less bugs in the
software (preferably in the places that customers use most often). Yes I do
mean all of it when I’m saying “reduce technical debt”, for the very reason that
technical debt is not really so much “technical” as the name would suggest. At
this point we already knew that we needed a whole truck of fortune cookies to
tell us what that freakin’ business would want 10 years on from now and where
our clients would find most bugs, so we can go ahead and clean it up… or,
maybe, just maybe we could extrapolate from historical data. After all we are
able to extract data for over 6 years of development and there should be enough
information to get meaningful conclusion out of it.&lt;/div&gt;
&lt;br /&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
And what we came up with was to use
the information from issue tracking system&lt;sup&gt;1&lt;/sup&gt; (we use ClearQuest) and
the source code (we used ClearCase and are currently on SVN) and consolidate
it. That way we would knew which areas of the code were changed the most and
could predict that they might be the main targets of modification in upcoming
months (I’m using months, ‘cause I’m not really sure if much more time got left
– because of that thing with Mayans and their calendar...). Sounds familiar, right?
Yeah, I won’t lie to you; we were under strong influence of what Michael
Feathers is preaching about for some time now (eg. &lt;a href="http://www.stickyminds.com/s.asp?F=S16679_COL_2" name="coltop"&gt;Getting Empirical about Refactoring&lt;/a&gt;).
&lt;/div&gt;
&lt;br /&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
The hacking started and after not
that long a time I managed to get my data out of ClearQuest (thank you CQPerl!)
and combine both SVN and Clear Case information to get list of tuples in this
format: [ISSUE_NUMBER, CHECKIN_DATE, FILENAME]. The next step was to visualize
it somehow... actually I was pretty skeptic about using yet another
line/bar/pie chart and craved for a picture which meaning just gets to you. In
fact I strongly believe that in a today’s world it is more important than ever
that you not only pick the right information from the data, but also choose a
right way to present that, and with the right tools this can actually be pretty
easy to achieve. After a moment of googling I came onto &lt;a href="http://mbostock.github.com/protovis"&gt;Protovis&lt;/a&gt;
– really amazing visualization library that let you do very powerful graphics almost
out-of-the-box. And after not more than 15 minutes the graph below was brought
the world:&lt;/div&gt;
&lt;br /&gt;
&lt;table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto; text-align: center;"&gt;&lt;tbody&gt;
&lt;tr&gt;&lt;td style="text-align: center;"&gt;&lt;a href="http://1.bp.blogspot.com/-BftowAiEDrE/TsQlqBgqMbI/AAAAAAAAAL4/WBv0nIeDJ40/s1600/bubbles.jpg" imageanchor="1" style="margin-left: auto; margin-right: auto;"&gt;&lt;img border="0" src="http://1.bp.blogspot.com/-BftowAiEDrE/TsQlqBgqMbI/AAAAAAAAAL4/WBv0nIeDJ40/s1600/bubbles.jpg" /&gt;&lt;/a&gt;&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td class="tr-caption" style="text-align: center;"&gt;Histogram depicting number of defect fixes across which classes were changed (bubbles represent files, the size of bubble is directly proportional to number of defect fixes file was modified in)&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;&lt;/table&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;br /&gt;
I was not entirely honest with you…
A few more little details about what I did:&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-family: Symbol;"&gt;&lt;span style="font: 7pt &amp;quot;Times New Roman&amp;quot;;"&gt; &lt;/span&gt;&lt;/span&gt;filtered out files that does not appear in more
than N issues,&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Symbol;"&gt;&lt;/span&gt;made size of a bubble a quadratic function of
number of issues that a file was modified in (ie. size_of_bubble =
number_of_issues ^2),&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Symbol;"&gt;&lt;/span&gt;grouped colors of bubbles by a package (or it
might have also been a part of code from an original example, I don’t remember)&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Symbol;"&gt;&lt;/span&gt;I don’t want to share too many details about my
project, but trust me these are really the places in the code that you would
expect to appear on this graph (and now we have data to defend to our position
which is pretty cool).&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
I myself had two most obvious
conclusions after looking at this “rich histogram”:&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-family: Symbol;"&gt;&lt;/span&gt;There is around 15-20 files that stand out (if
you consider we have tens thousands of files in a VCS, this is pretty strong) –
you probably start your technical debt discussion from this classes, ie. make
them smaller, clean up the implementation, increase coverage,&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Symbol;"&gt;&lt;/span&gt;files in an “orange” package are changed more
often than other – this needs more analysis, on whether the package is that
large, or they are often changed all together… and then maybe because of
coupling&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
What next you can do with this
graph? Possibilities are plenty… things that I did already or am planning to in
a near future is to let user:&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style="font-family: Symbol;"&gt;&lt;/span&gt;let user see histogram either on class level or
on package level&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Symbol;"&gt;&lt;/span&gt;filter out specific modules or packages&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Symbol;"&gt;&lt;/span&gt;filter out test code&lt;/li&gt;
&lt;li&gt;&lt;span style="font-family: Symbol;"&gt;&lt;/span&gt;let user calculate the histogram only for
selected date range&lt;/li&gt;
&lt;/ul&gt;
&lt;br /&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
Now this graph alone does not
tell you yet whether these are the files that needs your care, but it is one
step forward from being completely ignorant about the historical context of
changes in your codebase and its potential impact on the business in the future.
&lt;/div&gt;
&lt;br /&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
In the next posts I will continue
to explore various ways you can use this information to exploit your data to
the limits.&lt;/div&gt;
&lt;div class="MsoNormal" style="text-align: justify;"&gt;
&lt;br /&gt;
&lt;hr /&gt;
&lt;span style="font-size: x-small;"&gt;1) We might have also considered
to pull the information VCS, but we used ClearCase for a long time and only
recently switched to Subversion - and since on ClearCase you don’t really have
a concept of a commit that was a blocker.&lt;/span&gt;&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-2982285033575000719?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/2982285033575000719/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2011/11/serious-take-on-data-rich-development.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/2982285033575000719?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/2982285033575000719?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2011/11/serious-take-on-data-rich-development.html" title="A serious take on Data-Rich Development - Part 1" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/-BftowAiEDrE/TsQlqBgqMbI/AAAAAAAAAL4/WBv0nIeDJ40/s72-c/bubbles.jpg" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C04NR3c4fCp7ImA9WxNbGEk.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-6201684880319571112</id><published>2009-11-21T23:13:00.002+01:00</published><updated>2009-11-21T23:19:56.934+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-11-21T23:19:56.934+01:00</app:edited><title>Hibernate lifecycle</title><content type="html">Because I'm very busy lately I'll keep it short. Having been annoyed by Hibernate, all the magic happening under the hood and rarely any information on what is really going on I decided to do a little research on hibernate lifecycle. I don't think any document of that sort exists on the web so I decided to share it with you. I tried my best to double check everything but I might have omitted something. If you spot an error - please let me know.&lt;br /&gt;&lt;br /&gt;&lt;a href="http://docs.google.com/View?id=ddnqz853_10rd8b6fdn"&gt;See Hibernate lifecycle document&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-6201684880319571112?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/6201684880319571112/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/11/hibernate-lifecycle_21.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/6201684880319571112?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/6201684880319571112?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/11/hibernate-lifecycle_21.html" title="Hibernate lifecycle" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;AkUASXY7cCp7ImA9WxJVFEo.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-5819972750932463409</id><published>2009-07-01T20:02:00.006+02:00</published><updated>2009-07-01T21:57:28.808+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-07-01T21:57:28.808+02:00</app:edited><title>Design patterns in Scala: Adapter</title><content type="html">One might think that when considering &lt;a href="http://en.wikipedia.org/wiki/Adapter_pattern"&gt;Adapter pattern&lt;/a&gt; the ol' good Java implementation is 'as good as it gets'. But as you're probably already guessing I believe it is not. Surprisingly (ye.. right) Scala shines also on this front.&lt;br /&gt;&lt;br /&gt;Say the code we're dealing with is:&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;class Communism { def makePropaganda = ... }&lt;br /&gt;&lt;br /&gt;class Capitalism { def usePublicRelations = ... }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you wanted to adapt '&lt;span style="font-style:italic;"&gt;Communism&lt;/span&gt;' to behave as '&lt;span style="font-style:italic;"&gt;Capitalism&lt;/span&gt;' (say we need it during visits of important foreign ministers ;)) in Java typically you'd do it like:&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;class CapitalismAdapter(val communism : Communism) extends Capitalism {&lt;br /&gt; def usePublicRelations = communism.makePropaganda();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Usage:&lt;br /&gt;new CapitalismAdapter(new Communism).usePublicRelations&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;If you're in control of '&lt;span style="font-style:italic;"&gt;Capitalism&lt;/span&gt;' class it'd be even better to do '&lt;span style="font-style:italic;"&gt;Capitalism&lt;/span&gt;' a trait or create '&lt;span style="font-style:italic;"&gt;ICapitalism&lt;/span&gt;' trait which'd be implemented by '&lt;span style="font-style:italic;"&gt;Capitalism&lt;/span&gt;' class.&lt;br /&gt;&lt;br /&gt;Anywho.. Let's do it Scala way.&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;implicit def systemTransformation(communism : Communism) : Capitalism = new Capitalism {&lt;br /&gt;def usePublicRelations = communism.makePropaganda();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Usage:&lt;br /&gt;new Communism.usePublicRelations&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That may seem like a one simple and insignificant improvement - but in fact it's pretty powerful stuff. After all an explicit conversion you did in Java is nothing but noise (by now you most probably noticed that Scala is the noise-annihilator). &lt;br /&gt;Also it saves you from all that extra keystrokes and postpone &lt;a href="http://en.wikipedia.org/wiki/Repetitive_strain_injury"&gt;RSI&lt;/a&gt; ;). &lt;br /&gt;&lt;br /&gt;And with more difficulty it gets only better. Consider following problem:&lt;br /&gt;&lt;br /&gt;For reasons unknown (&lt;a href="http://www.martinfowler.com/ieeeSoftware/whoNeedsArchitect.pdf"&gt;Architectus Reloadus&lt;/a&gt; asked us to do so) we want to extend some lists in our system with a '&lt;span style="font-style:italic;"&gt;fancyMethod&lt;/span&gt;'. These conversion should apply only to the lists that contain elements able to be converted to a '&lt;span style="font-style:italic;"&gt;String&lt;/span&gt;'.&lt;br /&gt;To do it in Scala you implement an implicit conversion of a '&lt;span style="font-style:italic;"&gt;listToStringList&lt;/span&gt;' and put a requirement on a user of providing an implicit conversion of each element to '&lt;span style="font-style:italic;"&gt;String&lt;/span&gt;'.&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;trait StringList { val list : List[String]; def fancyMethod = () }&lt;br /&gt;&lt;br /&gt;// implement implicit conversion of 'List[A]' to 'StringList'&lt;br /&gt;implicit def listToStringList[A](aList : List[A])&lt;br /&gt;// require to provide (another) implicit conversion method (A =&gt; String) in a scope of this conversion usage&lt;br /&gt;(implicit aToString : A =&amp;gt; String) = {&lt;br /&gt;  new StringList { val list = aList.map(aToString) }&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// Usage:&lt;br /&gt;def foo(s : StringList) = ()&lt;br /&gt;&lt;br /&gt;// should cause error:&lt;br /&gt;foo(List(1, 2, 3))&lt;br /&gt;&lt;br /&gt;implicit def intToString(i : Int) = i.toString&lt;br /&gt;&lt;br /&gt;// and now it works:&lt;br /&gt;foo(List(1, 2, 3))&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;I won't provide the Java solution for this problem just because I care about my sinews..&lt;br /&gt;&lt;br /&gt;An important thing to remember is that implicit conversions in Scala are not transitive. It is still possible to do such conversion (with calling any method explicitly) but it must be 'requested' with ':' operator.&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;class A; class B; class C; class D&lt;br /&gt;&lt;br /&gt;implicit def aToB(a : A) = new B&lt;br /&gt;implicit def bToC(b : B) = new C&lt;br /&gt;implicit def cToD(c : C) = new D&lt;br /&gt;&lt;br /&gt;// Usage:&lt;br /&gt;val a = new A&lt;br /&gt;println((a:B):C) // A =&amp;gt; C&lt;br /&gt;println(((a:B):C):D) // A =&amp;gt; D&lt;br /&gt;&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-5819972750932463409?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/5819972750932463409/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/07/design-patterns-in-scala-adapter.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/5819972750932463409?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/5819972750932463409?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/07/design-patterns-in-scala-adapter.html" title="Design patterns in Scala: Adapter" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CkICR3Y_fCp7ImA9WxJVE0w.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-8934784833642733940</id><published>2009-06-29T21:47:00.004+02:00</published><updated>2009-06-29T23:22:46.844+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-29T23:22:46.844+02:00</app:edited><title>Design patterns in Scala: Command</title><content type="html">Many people say that Command pattern in languages of functional paradigm is not really a pattern but actually an inherent feature of a language itself. I don't know about other languages but in Scala it is not entirely true. While it is rather quite easy to come up with Command pattern implementation - you write a closure and it's done ;) - but variety of possibilities that language gives you is pretty amazing.&lt;br /&gt;&lt;br /&gt;Let's start from the very beginning. &lt;br /&gt;I believe that the three following points represent the most important aspects to consider when choosing appropriate implementation of Command Pattern in Scala.&lt;ul&gt;&lt;li&gt;what the signature of "Command" used as a parameter looks like&lt;/li&gt;&lt;li&gt;how do you construct a "Command" instance&lt;/li&gt;&lt;li&gt;how do you assign a "Command" instance to a value&lt;/li&gt;&lt;/ul&gt;The most straightforward solution to Command pattern implementation is:&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;// Example 1&lt;br /&gt;def command(i : Int) = println(i);&lt;br /&gt;&lt;br /&gt;// Usage:&lt;br /&gt;// 1&lt;br /&gt;def invoker(cmd : Int =&gt; Unit) = cmd(1) &lt;br /&gt;// 2&lt;br /&gt;invoker(command _)&lt;br /&gt;// or&lt;br /&gt;invoker(command)&lt;br /&gt;// 3&lt;br /&gt;val savedCommand = command _&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;However concise and elegant it has important shortcomings. Firstly you get very wide and crude interface - (Int) =&gt; (Unit) means nothing after all. You won't communicate a lot of information with that and a user can pass any command to an "invoker" method (including ShutDownReactor procedure ;]). The second thing is a nasty wildcard you have to use when assigning an instance of a command to a variable. (which you may optionally use in 2. - and if you don't compiler will do it for you).&lt;br /&gt;&lt;br /&gt;You can have a bit cleaner solution with following piece of code.&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;// Example 1&lt;br /&gt;def command = (i : Int) =&gt; println(i);&lt;br /&gt;&lt;br /&gt;// Usage:&lt;br /&gt;// 1&lt;br /&gt;def invoker(cmd : Int =&gt; Unit) = cmd(1) &lt;br /&gt;// 2 a) prepared command&lt;br /&gt;invoker(command)&lt;br /&gt;// 2 b) ad hoc command&lt;br /&gt;invoker((i : Int) =&gt; println(i))&lt;br /&gt;// 3&lt;br /&gt;val savedCommand = command&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The method presented above is actually the partially applied function of a function from the previous example. You gain the advantage of not writing the '_' (placeholder) when assigning an instance to a variable - what IMHO both simplifies and makes it a little less magical :). And if you wonder what would happen if you've added it anyway, the answer is simple - you'd get a partially applied partially applied function ;P with following signature:&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;() =&gt; (Int) =&gt; Unit&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;To solve the issue of wide interface you might use the more classical example of a Command pattern with a bit of functional language coolness on the top ;)&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;// Example 3&lt;br /&gt;trait Command { def apply(i : Int) }&lt;br /&gt;object DefaultCommand extends Command { def apply(i : Int) = println(i) }&lt;br /&gt;&lt;br /&gt;// Usage:&lt;br /&gt;// 1&lt;br /&gt;def invoker(cmd : Command) = cmd(1) &lt;br /&gt;// 2&lt;br /&gt;invoker(DefaultCommand)&lt;br /&gt;// 2 b) ad hoc command construction&lt;br /&gt;invoker(new Command { def apply(i : Int) = println(i) })&lt;br /&gt;// 3&lt;br /&gt;val savedCommand : Command = DefaultCommand&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Pretty nice - it gives you very clean nice interface with possibility of extending it with whatever responsibility you like (what was obviously missing in first two examples). Nothing comes for free though - the ad hoc construction of a command class is more verbose than a simple command function.&lt;br /&gt;&lt;br /&gt;If you're cra^M^M^Mbrave enough you might even try something like this:&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;class CrazyCommand extends (Int =&gt; Unit) { def apply(i : Int) = println(i) }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;And now the nice thing is that you may both use it as in 3. example and also pass it to a function defined in previous code snippets. Though I have no idea why anyone would like to do that ;)&lt;br /&gt;&lt;br /&gt;While I'm at it I'd remind you about a cool Scala feature that let you extend class behaviour at instantiation and thus you can do the same with:&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;new Command with (Int =&gt; Unit) { def apply(i: Int) = println(i) }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Fun Exercise! ;)&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;type CoolCommand = (Int =&gt; Unit) with (String =&gt; Unit)&lt;br /&gt;&lt;br /&gt;def coolFunction(cmd : CoolCommand) { cmd(1); cmd("one") }&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The implementation of a class that may be passed as a parameter to a 'coolFunction' is left to a reader and may be impossible :P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-8934784833642733940?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/8934784833642733940/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/06/design-patterns-in-scala-command.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/8934784833642733940?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/8934784833642733940?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/06/design-patterns-in-scala-command.html" title="Design patterns in Scala: Command" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUICQXY9eip7ImA9WxJWF0o.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-457961130928699758</id><published>2009-06-18T20:19:00.011+02:00</published><updated>2009-06-23T18:12:40.862+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-23T18:12:40.862+02:00</app:edited><title>Design patterns in Scala: Singleton</title><content type="html">I am always keen on improving my knowledge of &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt;. Second thing is that I really enjoy to share what I learned with everyone (I do really hope people eventually gain much more interest in Scala :D). That's why I decided to make series on .. &lt;a href="http://en.wikipedia.org/wiki/Design_Patterns_(book)"&gt;GoF design patterns&lt;/a&gt; in Scala.&lt;br /&gt;&lt;br /&gt;For starters I've chosen our old friend - &lt;a href="http://en.wikipedia.org/wiki/Singleton_pattern"&gt;Singleton&lt;/a&gt;. Let's go then!&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;object Singleton&lt;br /&gt;&lt;br /&gt;// Usage:&lt;br /&gt;val singleton = Singleton&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Done! Thx for reading.. &lt;br /&gt;&lt;br /&gt;..just kidding, let's dig a little deeper into that.&lt;br /&gt;&lt;br /&gt;You are probably curious about thread safety of this solution. The actual code generated in bytecode and decompiled with &lt;a href="http://www.varaneckas.com/jad"&gt;JAD&lt;/a&gt; looks like that:&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;public final class Singleton$&lt;br /&gt;    implements ScalaObject&lt;br /&gt;{&lt;br /&gt;&lt;br /&gt;    public Singleton$()&lt;br /&gt;    {&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public int $tag()&lt;br /&gt;        throws RemoteException&lt;br /&gt;    {&lt;br /&gt;        return scala.ScalaObject.class.$tag(this);&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    public static final Singleton$ MODULE$ = this;&lt;br /&gt;&lt;br /&gt;    static &lt;br /&gt;    {&lt;br /&gt;        new Singleton$();&lt;br /&gt;    }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;There are 3 things to consider:&lt;ul&gt;&lt;li&gt;Singleton object is initialized in static block so thread safety is guaranteed by JVM&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Every time you reference Singleton object in your code, Scala compiler translates this call into 'Singleton$.MODULE$',&lt;/li&gt;&lt;br /&gt;&lt;li&gt;This implemention has also quite cool semantics of access modifiers (which is a bit more advanced topic; search for 'companion module' to learn more).&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;An important thing to notice is that Singleton is eagerly initialized so if you try: &lt;br /&gt;&lt;pre name="code" class="java"&gt;java.lang.Class.forName("Singleton$")&lt;/pre&gt; it'll cause initialization to be performed. For now I have no idea how to force 'object' in Scala to be lazy initialized. The only solution I came up with would be:&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;// &lt;b&gt;Incorrect (see the bottom of article)&lt;/b&gt;&lt;br /&gt;&lt;s&gt;class LazySingleton private () {&lt;br /&gt;  def apply() = this&lt;br /&gt;}&lt;/s&gt;&lt;br /&gt;&lt;br /&gt;// &lt;b&gt;Correct&lt;/b&gt;&lt;br /&gt;class LazySingleton private () {&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;object LazySingleton {&lt;br /&gt;  lazy val INSTANCE = new LazySingleton();&lt;br /&gt;  def apply() = INSTANCE&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;// &lt;b&gt;Usage:&lt;/b&gt;&lt;br /&gt;val singleton = Singleton()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;The trick is to make default constructor private and have apply method of 'object' class type return the only instance of LazySingleton class.&lt;br /&gt;&lt;br /&gt;Disadvantage of second implementation is a small but noticable difference in usage. First - requires '()' [apply[ operator to be used. Second - it returns different type of class depending on whether '()' is used (class LazySingleton) or not (object LazySingleton):&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;scala&gt; C()&lt;br /&gt;res1: C = C@304648&lt;br /&gt;&lt;br /&gt;scala&gt; C&lt;br /&gt;res2: C.type = C$@1b9e7fc&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;b&gt;Modified 2009-06-23: &lt;/b&gt; Previous implemention of lazy singleton was incorrect and led to wrong conclusions.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-457961130928699758?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/457961130928699758/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/06/design-patterns-in-scala-singleton.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/457961130928699758?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/457961130928699758?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/06/design-patterns-in-scala-singleton.html" title="Design patterns in Scala: Singleton" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DU8HRXc4fSp7ImA9WxJWEko.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-1918910251878112160</id><published>2009-06-18T00:10:00.002+02:00</published><updated>2009-06-18T00:30:34.935+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-18T00:30:34.935+02:00</app:edited><title>Wroclaw Area Situated Scala Enthusiasts group established !!</title><content type="html">I am happy to announce that Przemysław Pokrywka and Piotr Adamski established &lt;a href="http://groups.google.pl/group/wroclaw-scala-enthusiasts"&gt;WrASSE&lt;/a&gt; (Wroclaw Area Situated Scala Enthusiasts) here in Wroclaw!! It's really amazing to meet people that care about Scala and hope for this great language to become the next Java :D&lt;br /&gt;&lt;div style="text-align: center"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 306px;" src="http://groups.google.pl/group/wroclaw-scala-enthusiasts/web/wrasse.png?hl=pl&amp;display=thumb&amp;width=420&amp;height=420" border="0" alt="" /&gt;If you're curious how this image is connected to this post visit &lt;a href="http://groups.google.pl/group/wroclaw-scala-enthusiasts"&gt;WrASSE discussion group&lt;/a&gt;&lt;/div&gt;&lt;br /&gt;There are regular meetings planned in the (hopefully near) future, but a group is veeery young and all your great ideas for &lt;a href="http://groups.google.pl/group/wroclaw-scala-enthusiasts"&gt;WraSSE&lt;/a&gt; are welcome!&lt;br /&gt;&lt;br /&gt;If you are Scala fun (slash zealot .. whatever ;)) and do care about your professional future (which would be Scala mostly ;P) I encourage you to join this group and actively participate!&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-1918910251878112160?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/1918910251878112160/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/06/wroclaw-area-situated-scala-enthusiasts.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/1918910251878112160?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/1918910251878112160?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/06/wroclaw-area-situated-scala-enthusiasts.html" title="Wroclaw Area Situated Scala Enthusiasts group established !!" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CkcFQ3Y_fyp7ImA9WxJWEUQ.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-5693316997290454617</id><published>2009-06-15T22:02:00.013+02:00</published><updated>2009-06-17T00:06:52.847+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-17T00:06:52.847+02:00</app:edited><title>My two cents on Agile adoption</title><content type="html">&lt;blockquote&gt;&lt;i&gt;Agile is like teenage sex, everybody is talking about it, most are not doing it and those that are doing it, are doing it wrong.&lt;/i&gt;&lt;div style="text-align: right"&gt;paraphrase of James O. Coplien &lt;a href="#reference_1"&gt;&lt;sup&gt;1&lt;/sup&gt;&lt;/a&gt;&lt;/div&gt;&lt;/blockquote&gt;So a guy - let's call him John - wants his company to be hip'n'cool and be &lt;a href="http://agilemanifesto.org/"&gt;&lt;b&gt;Agile&lt;/b&gt;&lt;/a&gt;. He goes by the book, put some things into work and yeeeeaahh.. nooo.. - people scream, tools don't work, tests breaks, client's pissed.. He begins ranting on Agile being unable to deliver him its expected awesomeness.. trying harder and harder.. right until it breaks completely. &lt;br /&gt;&lt;br /&gt;Yeeah... &lt;br /&gt;&lt;br /&gt;You know Albert Einstein was a pretty smarty guy? He actually said:&lt;br /&gt;&lt;blockquote&gt;&lt;i&gt;Insanity: doing the same thing over and over again and expecting different results.&lt;/i&gt;&lt;/blockquote&gt;That is exaaactly what John is doing. I am honestly amazed how vast majority of people approach this problem. It may be characterized as: "Doesn't work? Let's ditch it". I mean.. WTF? Are they really that lazy to make any alterations? It's either that or they thought they'd be anointed by Holy Ghost with Agile skills.. I mean be reasonable you don't expect to become Software Architect one month after graduation...&lt;br /&gt;&lt;br /&gt;However there's still a question to answer: "What might be a better solution than moving back to RUP" (which is bad and stinks and even &lt;a href="http://memeagora.blogspot.com/2009/06/aml-arbitrary-markup-language.html#c5334105441966176219"&gt;IBM knows it&lt;/a&gt; :P).&lt;br /&gt;&lt;br /&gt;You know how &lt;a href="http://www.testdriven.com/"&gt;TDD&lt;/a&gt; cycle looks like don't you:&lt;br /&gt;&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_EGp5yUlgDtc/SjgG399abdI/AAAAAAAAABg/s6nwYFpIwfU/s1600-h/code-test-refactor.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 220px;" src="http://4.bp.blogspot.com/_EGp5yUlgDtc/SjgG399abdI/AAAAAAAAABg/s6nwYFpIwfU/s400/code-test-refactor.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5348032116097183186" /&gt;&lt;/a&gt;What if I've shown you something quite similar:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://3.bp.blogspot.com/_EGp5yUlgDtc/SjgG89HtVvI/AAAAAAAAABo/m-NpGx_Gu90/s1600-h/problem-introduce-refactor.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 207px;" src="http://3.bp.blogspot.com/_EGp5yUlgDtc/SjgG89HtVvI/AAAAAAAAABo/m-NpGx_Gu90/s400/problem-introduce-refactor.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5348032201771276018" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;b&gt;First&lt;/b&gt; - move slowly, take small steps. Otherwise you won't know what works and what doesn't, you will overwhelm your team&lt;a href="#reference_2"&gt;&lt;sup&gt;2&lt;/sup&gt;&lt;/a&gt; with too much change and slow down development process down to nothing.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Second&lt;/b&gt; - use feedback! You're getting negative - may it be - in TDD red tests have the same value as green ones. &lt;br /&gt;&lt;br /&gt;&lt;b&gt;Third&lt;/b&gt; - don't expect to become Agile star overnight.&lt;br /&gt;&lt;br /&gt;It requires &lt;b&gt;time&lt;/b&gt;. &lt;br /&gt;It requires &lt;b&gt;effort&lt;/b&gt;. &lt;br /&gt;It may deliver &lt;b&gt;profits&lt;/b&gt;. &lt;br /&gt;If you're not determined to take a risk don't put blame on a process. Just admit it.&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;div id="reference_1"&gt;1. From his superb &lt;a href="http://jaoo.dk/presentation/Not+your+Grandfather's+Architecture:+Taking+Architecture+into+the+Agile+World"&gt;presentation on DCI&lt;/a&gt;.&lt;/div&gt;&lt;br /&gt;&lt;div id="reference_2"&gt;2. "Gently introduce change to a team. Don't expect things to suddenly change overnight." Ryan XXX [don't know last name]&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-5693316997290454617?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/5693316997290454617/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/06/my-two-cents-on-agile-adoption.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/5693316997290454617?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/5693316997290454617?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/06/my-two-cents-on-agile-adoption.html" title="My two cents on Agile adoption" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://4.bp.blogspot.com/_EGp5yUlgDtc/SjgG399abdI/AAAAAAAAABg/s6nwYFpIwfU/s72-c/code-test-refactor.png" height="72" width="72" /><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D0QASXs9eip7ImA9WxJXEUQ.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-77126562464802058</id><published>2009-06-04T21:16:00.007+02:00</published><updated>2009-06-05T11:49:08.562+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-06-05T11:49:08.562+02:00</app:edited><title>Been busy preparing presentation "Scala for practitioners"</title><content type="html">Last month it was pretty silent on this blog and I got to say sorry for that. It was quite busy month for me and I couldn't even find the time to tweet not mentioning blogging. The most important thing that came out to live during this time was a presentation - on probably the best language in the world - titled: "Scala for practitioners". I gave it for the first time yesterday in &lt;a href="http://www.power.com.pl"&gt;Power Media S.A.&lt;/a&gt; (which is the company I'm currently cooperating with as a freelancer :)) and you can find the project I used during the presention &lt;a href="http://github.com/pbadenski/scala-presentation/"&gt;here on github&lt;/a&gt;. The primary goal was to show Scala as language having real business value here and now, being really close to get significant impact in software projects. From all the feedback that I've gathered I guess I can safely state - it was a success! :D Next I'm planning on giving this presentation on Wroclaw JUG. It actually needs some minor corrections (what again will probably cause absence of new posts on this blog .. ;P) but I really hope it will trigger more enthusiasm for Scala in Java community. I'm also thinking on doing some screencasts on Scala but the exact idea is not fully matured yet, so all tips are welcome!&lt;br /&gt;&lt;br /&gt;For all of you not to feel like you've lost another 2 minutes of your life reading this post:&lt;br /&gt;&lt;a href="http://ikaisays.com/2009/04/04/using-pattern-matching-with-regular-expressions-in-scala/"&gt;Mindblowing example of how cool is regexp matching in Scala&lt;/a&gt; (if you think you've seen it try checking it out anyways - it's not the same old regexp matching example :P).&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-77126562464802058?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/77126562464802058/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/06/been-busy-preparing-presentation-scala.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/77126562464802058?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/77126562464802058?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/06/been-busy-preparing-presentation-scala.html" title="Been busy preparing presentation &quot;Scala for practitioners&quot;" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DE8GQnY9fSp7ImA9WxJSFE4.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-3319080244842501970</id><published>2009-05-03T23:59:00.009+02:00</published><updated>2009-05-04T13:33:43.865+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-04T13:33:43.865+02:00</app:edited><title>Delivering the code is like doing the laundry</title><content type="html">I hate doing the laundry.. it's definitely in the top 5 of housework activities I hate.. Recently I talked with my friend about - no, not about doing the laundry ;) but nonetheless the topic came around. He was actually amazed how might I not like this particular activity - 'cause in his eyes it was nothing more than putting your dirty stuff to the washing machine, switching it on and doing nothing for an hour or so. I couldn't answer right away so I decided to focus next time I'm doing the laundry on what exactly I don't like about it. Identifying the precise reason behind reluctance to a certain thing or activity is after all the first step to overcome it ;)). Then the day came - stuff started to pour out of the clothes basket (as usual) and I was forced to clean this mess up.. To spare you the details, the list of activities being part of doing the laundry is:&lt;br /&gt;&lt;ol style="list-style-type: lower-alpha;"&gt;&lt;br /&gt;&lt;li&gt;sorting the laundry&lt;br /&gt;&lt;/li&gt;&lt;li&gt;stuffing it to the washing machine&lt;br /&gt;&lt;/li&gt;&lt;li&gt;going to the market because you forgot you were low on the @#$#@ washing powder&lt;br /&gt;&lt;/li&gt;&lt;li&gt;taking the laundry out and hanging it on a dryer&lt;br /&gt;&lt;/li&gt;&lt;li&gt;collecting the laundry after it dries&lt;br /&gt;&lt;/li&gt;&lt;li&gt;ironing (personally at this point I'm too pissed about the whole activity and skip this point)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;folding clothes and putting them to the drawers, wardrobe or wherever they should be stuffed..&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;So this basic task is as a matter of fact damn strategic operation ;] And that's the precise reason why I hate doing the laundry :) (And will probably continue to not like it :]) At this point you must already be wondering "what the hell is this guy prattling about?" Let's begin a second story then! ;)&lt;br /&gt;&lt;br /&gt;Recently I had a small discussion with my colleague about the (un) importance of testing. He defended the concept of testing being time-consuming and thus not acceptable in software business. He represented the old school of "yes I know it's important but we don't have time for this stuff we need to get the implementation fast". What drew my attention was the last part of this sentence "we need to get the implementation fast". As if in the software business we were responsible to push the code out of the door and not give a damn where/when/what it'll be used (for). This is not the first time I hear this opinion - software developers too often forget that the code is not what we produce (yes, I know it's easy to see it this way). Our job is however do deliver functionality to the client and not the crappy, low-quality kind of functionality which she/he never wanted. The high-quality and precise reflection of her/his requirements (which she/he might have not even been aware of.. that's the hard part).&lt;br /&gt;When unit testing is not the &lt;B&gt;elementary part&lt;/b&gt; of software development the whole activity of delivering a single requirement consists of:&lt;br /&gt;&lt;ol style="list-style-type: lower-alpha;"&gt;&lt;br /&gt;&lt;li&gt;requirements elicitation&lt;br /&gt;&lt;/li&gt;&lt;li&gt;coding&lt;br /&gt;&lt;/li&gt;&lt;li&gt;QA testing&lt;br /&gt;&lt;/li&gt;&lt;li&gt;fixing the code&lt;br /&gt;&lt;/li&gt;&lt;li&gt;QA testing&lt;br /&gt;&lt;/li&gt;&lt;li&gt;deployment&lt;br /&gt;&lt;/li&gt;&lt;li&gt;client finding bugs (this is the optimistic version where the software actually reflects her/his requirements)&lt;br /&gt;&lt;/li&gt;&lt;li&gt;fixing the code&lt;br /&gt;&lt;/li&gt;&lt;li&gt;deployment&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;Finally what's the resemblance between doing the laundry and delivering the code, you ask. There is a clear tendency for both to be interpreted too narrow! :)&lt;br /&gt;&lt;br /&gt;Just like doing the laundry is more than putting clothes to the washing machine,&lt;br /&gt;&lt;b&gt;delivering the code is more than coding the implementation.&lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-3319080244842501970?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/3319080244842501970/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/05/delivering-code-is-like-doing-laundry.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/3319080244842501970?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/3319080244842501970?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/05/delivering-code-is-like-doing-laundry.html" title="Delivering the code is like doing the laundry" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>3</thr:total></entry><entry gd:etag="W/&quot;C04HSH46fip7ImA9WxJSE0Q.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-5287031420685773991</id><published>2009-04-29T00:05:00.010+02:00</published><updated>2009-05-04T01:05:39.016+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-05-04T01:05:39.016+02:00</app:edited><title>It's not about how fast you code the requirements but how soon you get them right</title><content type="html">&lt;blockquote&gt;&lt;span style="font-style:italic;"&gt;The actual software is just a byproduct of the process of building an understanding of a given domain.&lt;/span&gt;&lt;br /&gt;&lt;a href="http://blog.jonasbandi.net/2009/02/agile-lean-wait-moment.html"&gt;Jonas Bandi&lt;/a&gt;&lt;/blockquote&gt;&lt;br /&gt;The misconception behind the RAD tools comes from the desire to implement the software (ie. do the coding) as quickly as possible. People believe that producing software is hard - and they're correct, it really is! The problem is that it is not the implementation that is tough. Meeting blurry, vague wishes of your client - sometimes erroneously called requirements - is the hardest part in software development. And unless you work on really dumb system for feeding the data using few hundreds of forms (which most probably means you do software for govmt) you really need to get the domain right.&lt;br /&gt;&lt;br /&gt;On all projects with non-trivial business domain you spend most of the time analyzing clients requirements, evolving (expanding and refactoring) the domain model to meet your clients demands. You spend hours in front of the whiteboard with the marker in your hand talking about the domain. You do Proof-of-Concept, you revert, do it again, revert.. And then if you're totally, 100% sure what's really going on in this damn business domain (and BTW most probably you're still wrong about it ;)) you go to do some front-end, mailing, logging and &lt;a href="http://www.adam-bien.com/roller/abien/entry/a_good_architecture_is_all"&gt;all that supportive stuff&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;In my first job I had a teammate who was a decent programmer but he shone big time. I spent a gigantic amount of time on learning every detail in technology we used and I knew the class model very good. He knew just enough about it but still when it came to talking about the project he always knew better. The thing was it that he focused on and understanding specifics of business domain what almost always gave him massive advantage.&lt;br /&gt;&lt;br /&gt;&lt;b&gt;Most of the time you do &lt;a href="http://www.typo3-media.com/blog/domain-driven-design-introduction.html"&gt;the knowledge crunching&lt;/a&gt;. &lt;/b&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-5287031420685773991?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/5287031420685773991/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/04/its-not-about-how-fast-you-code.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/5287031420685773991?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/5287031420685773991?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/04/its-not-about-how-fast-you-code.html" title="It's not about how fast you code the requirements but how soon you get them right" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;AkUBRXs_eyp7ImA9WxJSEEw.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-2506486181215356181</id><published>2009-04-28T21:42:00.009+02:00</published><updated>2009-04-29T17:17:34.543+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-29T17:17:34.543+02:00</app:edited><title>OO design, reuse and serendipity</title><content type="html">Steve Vinoski said pretty wise stuff about &lt;a href="http://www.infoq.com/presentations/vinoski-rest-serendipity"&gt;reusability of REST-based systems&lt;/a&gt;. He said that powerful stuff as Unix small languages was probably incidental just because the design (&lt;a href="http://en.wikipedia.org/wiki/Pipeline_(Unix)"&gt;unix pipe&lt;/a&gt;) was based on modularity and simplicity.&lt;br /&gt;&lt;br /&gt;It is entirely the same for Object Oriented design. Keep your interfaces simple (ie. &lt;a href="http://www.objectmentor.com/resources/articles/isp.pdf"&gt;make them have clear boundaries [PDF warning!]&lt;/a&gt;) and your abstractions simple (ie. &lt;a href="http://www.objectmentor.com/resources/articles/srp.pdf"&gt;having clear and sharp definitions [PDF warning!]&lt;/a&gt;* - and modularity comes for free. Simplicity enables modularity! &lt;br /&gt;&lt;br /&gt;The important part is that, what is easily forgotten, reuse is not only about using parts of the code on different projects - this should actually be quite rare - I mean most of the time you use external frameworks to do generic stuff.. don't you?. But you should constantly reuse domain classes by using them second, third and nth time in different contexts. And by different contexts I mean implementation of the most exotic requirements of your clients. It's definitely not a good sign if you catch yourself saying "naahh.. we can't use that method for the new requirement, 'cause it's doing this thing and the other thing to do that stuff here.. here.. and over theeeere.. we gotta write a new one".&lt;br /&gt;&lt;br /&gt;What you might rather try is:&lt;br /&gt; - refactor (decouple),&lt;br /&gt; - test,&lt;br /&gt; - reuse.&lt;br /&gt;&lt;br /&gt;Do it &lt;a href="http://en.wikipedia.org/wiki/KISS_principle"&gt;KISS&lt;/a&gt;, &lt;a href="http://97-things.near-time.net/wiki/Simplicity%20before%20generality,%20use%20before%20reuse"&gt;don't strive for too much generality&lt;/a&gt;, but do it right! After the umpteen requirement (and refactoring) you'll be amazed that you have &lt;a href="http://www.ibm.com/developerworks/java/library/j-eaed1/index.html"&gt;evolved&lt;/a&gt; a very sharp abstraction with clear boundaries. Moreover you gained a fair amount of domain knowledge because you kept on building larger coherent structure and not only solving single problems. Always remember about GPS** (Gain Perspective Stupid).&lt;br /&gt;&lt;br /&gt;"Serendipitous reuse" is definitely a good sign and if you do OO right it'll come for free.&lt;br /&gt;&lt;br /&gt;* The rule of a thumb is that if you have to use two metaphors (or more, sic!) to explain a role of an abstraction to the person from outside the project it means that your domain model stinks in that particular area.&lt;br /&gt;** Coined by my good colleague and great software developer Piotr Wójcicki.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-2506486181215356181?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/2506486181215356181/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/04/oo-design-reuse-and-serendipitykk.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/2506486181215356181?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/2506486181215356181?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/04/oo-design-reuse-and-serendipitykk.html" title="OO design, reuse and serendipity" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;D0QGSXk8eyp7ImA9WxJTFE4.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-6036100703505657941</id><published>2009-04-22T22:03:00.002+02:00</published><updated>2009-04-22T23:22:08.773+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-22T23:22:08.773+02:00</app:edited><title>My view on different level of abstractions in OO</title><content type="html">Lately I've been trying to invent my very own classification of classes of abstractions you come across when creating object-oriented software. As every more-or-less formal classification it should give me (at least that's what I hope for) a possibility to infer various qualities and evaluate use-cases for each of the class of abstraction. It also gives you quite a nice foundation to introduce heuristics and conception of refactorings from/to certain class of abstraction.&lt;br /&gt;&lt;br /&gt;I've come up with the idea of 3 categories which I call "nth class citizens":&lt;br /&gt; - 1st class citizens - (abstract) domain classes,&lt;br /&gt; - 2nd class citizens - (abstract) classes included in general purpose libraries - various data structures (eg. Collection, Set, Date, etc.),&lt;br /&gt; - 3rd class citizens - primitive types and classes (eg. int, Long, BigDecimal).&lt;br /&gt;&lt;br /&gt;In case of 1st class citizens the main problem is the metaphor. Every abstraction is described by either an abstract or real entity constituting its role. It is not always possible to model a goal and responsiblities of an entity in a programming language of your choice. It may happen that an object lose some meaning or demonstrates additional features. The first issue is easy to resolve as it requires us only to judge whether the lost qualities were necessary to fully express the intent of object existence. As for the latter:&lt;br /&gt; - demonstrated features (qualities) may be the actual functions of the modeled abstraction - in this case by incident we get the useful extra "feedback of the metaphor",&lt;br /&gt; - the new features have nothing in common with the modeled abstraction - the domain model is contaminated with false information. These features cause unnecessary confusion and draw away the attention of developers from the actual intent of choosing certain abstraction.&lt;br /&gt;&lt;br /&gt;2nd class citizens use a general interface to communicate (this interface have a precise definition in the domain of computer science). Incidentally it matches the one of a modeled business domain. In most of cases (as in 80/20 rule) there is no need to hide the information they share with the external world - you should just use the standard "wide" general purpose interface. There is however a danger that:&lt;br /&gt; - there are in fact 1st class citizens in disguise (eg. Set&amp;lt;Map&amp;lt;Account, Order&amp;gt;&amp;gt;),&lt;br /&gt; - they either share too much information or their messages are too generic and hard too understand by their collaborators. In both situations they should be rather represented by 1st class citizens (implemented with encapsulation).&lt;br /&gt;&lt;br /&gt;3rd class citizens, well... they just exist :). In most cases you just push them around - and in 99,999% of situations you should not use them to perform any business operation (eg. DON'T DO chargeClient(BigDecimal price)). They should always be "represented" by 1st class citizens (encapsulation).&lt;br /&gt;&lt;br /&gt;This article is one of the first drafts and I hope I'll come back to this topic. There is never enough of polishing object oriented modelling, design and implementation skills! :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-6036100703505657941?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/6036100703505657941/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/04/my-view-on-different-level-of.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/6036100703505657941?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/6036100703505657941?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/04/my-view-on-different-level-of.html" title="My view on different level of abstractions in OO" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CkcCQnk9fip7ImA9WxVbFUo.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-6168454573168970241</id><published>2009-03-31T22:24:00.008+02:00</published><updated>2009-04-01T09:14:23.766+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-04-01T09:14:23.766+02:00</app:edited><title>the beauty of scala traits and self types</title><content type="html">So I'm working on &lt;a href="http://github.com/pbadenski/edukacjax/tree/master"&gt;a small throw-away project&lt;/a&gt; to check out the &lt;a href="http://www.scala-lang.org/"&gt;Scala&lt;/a&gt;+&lt;a href="https://jersey.dev.java.net/"&gt;Jersey&lt;/a&gt;+&lt;a href="http://xstream.codehaus.org/"&gt;XStream&lt;/a&gt; stack and I've come across a nice implementation pattern (more precisely I found a way to use one I've heard of previously in the slight different context, see &lt;a href="http://blog.jaoo.dk/2009/03/04/handling-architecture-in-the-agile-world/"&gt;James Coplien presentation on DCI&lt;/a&gt; and &lt;a href="http://www.artima.com/articles/dci_vision.html"&gt;the article on the subject&lt;/a&gt;).&lt;br /&gt;&lt;br /&gt;I hold a reference to an instance of XStream class somewhere in my app. It is responsible for marshalling objects and it looks like this (examples are shortened for clarity):&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;val XML = new XStream(new xml.JDomDriver()) {{&lt;br /&gt;    setMode(XStream.NO_REFERENCES);&lt;br /&gt;    alias("courses", ScalaCollectionClasses.ListBuffer)&lt;br /&gt;    alias("course", classOf[resources.Course])&lt;br /&gt;}}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;That looks nice - the initialisation block gives the instantiation of XStream object nice DSLish look of a spec. But when I decided to use both XML and JSON and following chunk of code appeared on the screen.&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;val XML = new XStream(new xml.JDomDriver()) {{&lt;br /&gt;    setMode(XStream.NO_REFERENCES);&lt;br /&gt;    alias("courses", ScalaCollectionClasses.ListBuffer)&lt;br /&gt;    alias("course", classOf[resources.Course])&lt;br /&gt;}}&lt;br /&gt;val JSON = new XStream(new json.JsonHierarchicalStreamDriver()) {{&lt;br /&gt;    setMode(XStream.NO_REFERENCES);&lt;br /&gt;    alias("courses", ScalaCollectionClasses.ListBuffer)&lt;br /&gt;    alias("course", classOf[resources.Course])&lt;br /&gt;}}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Ok.. duplication strikes you right away. So how do you fight that monster? There are actually a few options to choose from:&lt;br /&gt;&lt;ul&gt;&lt;br /&gt;&lt;li&gt;inheritance&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;class MyXStream extends XStream {&lt;br /&gt;    setMode(XStream.NO_REFERENCES);&lt;br /&gt;    alias("courses", ScalaCollectionClasses.ListBuffer)&lt;br /&gt;    alias("course", classOf[resources.Course])&lt;br /&gt;}&lt;br /&gt;val XML = new MyXStream(new xml.JDomDriver())&lt;br /&gt;val JSON = new MyXStream(new json.JsonHierarchicalStreamDriver())&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;delegation&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;val XML = new XStream(new xml.JDomDriver()) {{ configure(this) }}&lt;br /&gt;val JSON = new XStream(new json.JsonHierarchicalStreamDriver()) {{ configure(this) }}&lt;br /&gt;def configure(xstream : XStream) = {&lt;br /&gt;  setMode(XStream.NO_REFERENCES);&lt;br /&gt;  alias("courses", ScalaCollectionClasses.ListBuffer)&lt;br /&gt;  alias("course", classOf[resources.Course])&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;or&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;val XML = configure(new XStream(new xml.JDomDriver()))&lt;br /&gt;val JSON = configure(new XStream(new json.JsonHierarchicalStreamDriver()))&lt;br /&gt;def configure(xstream : XStream) = {&lt;br /&gt;  xstream.setMode(XStream.NO_REFERENCES);&lt;br /&gt;  xstream.alias("courses", ScalaCollectionClasses.ListBuffer)&lt;br /&gt;  xstream.alias("course", classOf[resources.Course])&lt;br /&gt;  xstream&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;/li&gt;&lt;br /&gt;&lt;li&gt;implicit conversion&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;val XML = new XStream(new xml.JDomDriver()).configure()&lt;br /&gt;val JSON = new XStream(new json.JsonHierarchicalStreamDriver()).configure()&lt;br /&gt;def xstreamToConfigurableXStream(xstream : XStream) = new {&lt;br /&gt;  def configure() = {&lt;br /&gt;    setMode(XStream.NO_REFERENCES);&lt;br /&gt;    alias("courses", ScalaCollectionClasses.ListBuffer)&lt;br /&gt;    alias("course", classOf[resources.Course])&lt;br /&gt;  }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;Ok as for the first one - inheritance sux.. I mean really.. inheritance is for most of the time the last resort and you know it. &lt;br /&gt;&lt;br /&gt;Second and the third one are ok.. I mean most of the time I'd say ok to this solution and implement something like this in Java.&lt;br /&gt;&lt;br /&gt;Fourth one.. imho this is a hack and clear abuse of implicit conversion in Scala. Personally I believe that the use of implicit conversion can be justified when trying to bend the existing API for your purposes (ie. trying to seamlessly extend non-functional Java classes to full-blown Scala versions).&lt;br /&gt;&lt;br /&gt;So what is the best solution I've found?&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;  trait Configuration&lt;br /&gt;  /* 1. */ trait DefaultConfiguration extends Configuration { /* 3. */ this: XStream =&gt; &lt;br /&gt;    /* 4. begin */&lt;br /&gt;    setMode(XStream.NO_REFERENCES);&lt;br /&gt;    alias("courses", ScalaCollectionClasses.ListBuffer)&lt;br /&gt;    alias("course", classOf[resources.Course])&lt;br /&gt;    /* 4. end */&lt;br /&gt;  }&lt;br /&gt;&lt;br /&gt;  /* 2. */val XML = new XStream(new xml.JDomDriver()) with DefaultConfiguration;  &lt;br /&gt;  val JSON = new XStream(new json.JsonHierarchicalStreamDriver()) with DefaultConfiguration;  &lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;&lt;ol&gt;&lt;br /&gt;&lt;li&gt;Create a trait that will bind the reference to an instance of a class it extends to "this"&lt;/li&gt;&lt;br /&gt;&lt;li&gt;Create an instance XStream for XML marshalling and extend with 'DefaultConfiguration' trait which..&lt;/li&gt;&lt;br /&gt;&lt;li&gt;in fact will bind the instance of XStream to 'this' and..&lt;/li&gt;&lt;br /&gt;&lt;li&gt;perform an initialisation of a bound object&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;A powerful (and strikingly easy after you see it for the first time and get the 'aha moment') mechanism for introducing behavior into existing classes. It gives you a perfect decoupling and let you introduce an explicit abstraction for the extension ('configuration' in this case). And now I can do:&lt;br /&gt;&lt;pre name="code" class="scala"&gt;&lt;br /&gt;  def foo(xstream : XStream with Configuration) = "thanks for configured xstream instance bro"&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Which basically means: "give me an xstream instance.. but the configured one if you may!"&lt;br /&gt;&lt;br /&gt;I am not sure I have fully explained the reason why I like the last one the most.. I got the gut-feeling this is the right path to go. Reusable, expressive, explicit.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-6168454573168970241?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/6168454573168970241/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/03/beauty-of-scala-traits-and-self-types.html#comment-form" title="5 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/6168454573168970241?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/6168454573168970241?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/03/beauty-of-scala-traits-and-self-types.html" title="the beauty of scala traits and self types" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>5</thr:total></entry><entry gd:etag="W/&quot;AkICRH47fyp7ImA9WxVbFEU.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-7599985424425739398</id><published>2009-03-31T09:47:00.008+02:00</published><updated>2009-03-31T10:36:05.007+02:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-31T10:36:05.007+02:00</app:edited><title>Keywords vs API, continued</title><content type="html">Przekonany postem Jeffa Atwooda (którego &lt;a href="http://pbadenski.blogspot.com/2009/02/joel-i-jeff-czyli-o-dwoch-takich-co.html"&gt;mimo wszystko&lt;/a&gt; jeszcze czytam :P) postanowiłem, że decyzją pragmatyczną będzie zmiana języka bloga na 'informatyczne esperanto' czyli angielski. Z dniem dzisiejszym wszystkie posty będą ukazywały się w tymże języku.&lt;br /&gt;-- Translation --&lt;br /&gt;Jeff Atwood (whose blog I continued to read &lt;a href="http://pbadenski.blogspot.com/2009/02/joel-i-jeff-czyli-o-dwoch-takich-co.html"&gt;in spite of everything&lt;/a&gt; :P) convinced me in his latest post that it'd be a pragmatic decision to switch the langugage of posts to 'Esperanto of software world', ie. English. Therefore starting today all posts are written in English.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;Here we go then!&lt;br /&gt;&lt;br /&gt;In &lt;a href="http://pbadenski.blogspot.com/2008/07/polyglot-programming-sowa-kluczowe-vs.html"&gt;one of the older posts&lt;/a&gt; I mentioned that it may be quite a problem to migrate from Scala to Java world. The keywords chosen for Scala might have been used already for name of the methods or classes in existing Java APIs (e.g. 'match' or 'yield') thus preventing us from using them in our code. BTW the well known example of such a case is Java evolution itself (1.4 -&gt; 1.5 and the appearance of 'enum' keyword')&lt;br /&gt;&lt;br /&gt;It appears that in Scala nothing is impossible! Well it is not feasible to define/use functions as presented below:&lt;br /&gt;&lt;pre class="scala" name="code"&gt;&lt;br /&gt;def match() = "Hello world! I am a 'match'!"&lt;br /&gt;def yield() = "Hello world! I am a 'yield'!"&lt;br /&gt;&lt;br /&gt;match()&lt;br /&gt;yield()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Yet nothing prevents us from doing it this way:&lt;br /&gt;&lt;pre class="scala" name="code"&gt;&lt;br /&gt;def `match`() = "Hello world! I am a 'match'!"&lt;br /&gt;def `yield`() = "Hello world! I am a 'yield'!"&lt;br /&gt;&lt;br /&gt;`match`()&lt;br /&gt;`yield`()&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;It is incredibly useful not only for Scala adoption among Java developers but also quite helpful during the development of 'Scala greenfield projects'. While in Java it is not that big issue (due to relatively small number of keywords) in Scala it'd have probably started being a bit of pain in the ass (with keywords like 'val' or 'match').&lt;br /&gt;&lt;br /&gt;The conclusion? Scala rox! :D&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-7599985424425739398?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/7599985424425739398/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/03/keywords-vs-api-continued.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/7599985424425739398?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/7599985424425739398?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/03/keywords-vs-api-continued.html" title="Keywords vs API, continued" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;C0ENRnY9eip7ImA9WxVUEk8.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-7505404338576508862</id><published>2009-03-15T22:32:00.009+01:00</published><updated>2009-03-16T17:41:37.862+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-16T17:41:37.862+01:00</app:edited><title>404 done the right way</title><content type="html">Ponieważ po raz kolejny napotykam się na beznadziejny komunikat 404 .. postanowiłem poprawić jeden z nich. Na poprawce spędziłem +/- 30 sekund i przepraszam za ewentualne błędy.&lt;br /&gt;&lt;br /&gt;Przed Pawłem:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://1.bp.blogspot.com/_EGp5yUlgDtc/Sb12ez12N5I/AAAAAAAAAAc/XNzO51-Glrk/s1600-h/404-not-usable.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 190px;" src="http://1.bp.blogspot.com/_EGp5yUlgDtc/Sb12ez12N5I/AAAAAAAAAAc/XNzO51-Glrk/s400/404-not-usable.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5313533407051265938" /&gt;&lt;/a&gt;&lt;br /&gt;Po Pawle:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://4.bp.blogspot.com/_EGp5yUlgDtc/Sb12fZUvN7I/AAAAAAAAAAk/DEOFO9D1oNU/s1600-h/404-usable.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 178px;" src="http://4.bp.blogspot.com/_EGp5yUlgDtc/Sb12fZUvN7I/AAAAAAAAAAk/DEOFO9D1oNU/s400/404-usable.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5313533417112942514" /&gt;&lt;/a&gt;&lt;br /&gt;Po Pawle wersja minimalistyczna:&lt;br /&gt;&lt;a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://2.bp.blogspot.com/_EGp5yUlgDtc/Sb18IWIZCNI/AAAAAAAAAAs/xfe82sPvvHw/s1600-h/404-most-usable.png"&gt;&lt;img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 400px; height: 139px;" src="http://2.bp.blogspot.com/_EGp5yUlgDtc/Sb18IWIZCNI/AAAAAAAAAAs/xfe82sPvvHw/s400/404-most-usable.png" border="0" alt=""id="BLOGGER_PHOTO_ID_5313539618188626130" /&gt;&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;Dlaczego uważam, że moje wersje są lepsze? Pozwolę sobie skomentować niektóre fragmenty komunikatu:&lt;br /&gt;1) "Welcome to 404 error page"&lt;br /&gt;Przeciętnego użytkownika Internetu doprawdy niewiele obchodzi czy kod błędu w protokole HTTP to 404, Alfa8 czy Dupa16.. Chciałbym, żeby programiści wreszcie zaczęli sobie z tego zdawać sprawę. Z drugiej strony świadomy użytkownik internetu zdaje sobię sprawę że nie istniejąca strona to kod 404 - więc po co mu o tym przypominać?! Kolejna rzecz, że obsługa błędów powinna być transparentna dla użytkownika i wtedy nie będzie musiał się uczyć różnicy między 404 a dajmy na to 410. Informacje czytelne dla komputerów zostawmy komputerom.&lt;br /&gt;&lt;br /&gt;2) "Welcome to this customized error page. You've reached this page because you've clicked on a link that does not exist."&lt;br /&gt;Ok.. odniosłem wrażenie jakbym celowo otworzył tę stronę i to co czytam było początkiem artykułu o kodzie błędu 404. Naprawdę nie wystarczyło krótkie i treściwe "Page does not exist" ?&lt;br /&gt;&lt;br /&gt;3) "This is probably our fault..."&lt;br /&gt;Nie miejsce i czas na unoszenie się honorem. Stare porzekadło ludowe mówi: "Klient ma zawsze rację". Komunikat powinen brzmieć: "This is totally our fault! We beg for forgiveness!"&lt;br /&gt;&lt;br /&gt;4) "but instead of showing you the basic '404 Error' page that is confusing and doesn't really explain anything, we've created this page to explain what went wrong."&lt;br /&gt;I co? Mam być wdzięczny, że straciłem 10 cennych sekund mojego życia czytając komunikat błędu ?!?!&lt;br /&gt;&lt;br /&gt;5) "You can either (a) click on the 'back' button in your browser and try to navigate through our site in a different direction, or (b) click on the following link to go to homepage."&lt;br /&gt;&lt;br /&gt;Chociaż mogli &lt;b&gt;a&lt;/b&gt; i &lt;b&gt;b&lt;/b&gt; pogrubić bo zajęło mi z dobre kilka sekund (a to dużo; odsyłam do badań z usability) żeby się dowiedzieć co mogę zrobić.&lt;br /&gt;&lt;br /&gt;Reasumując:&lt;br /&gt;Tworząc komunikaty z błędami kierujmy się &lt;a href="http://pl.wikipedia.org/wiki/KISS_(regu%C5%82a)"&gt;zasadą KISS&lt;/a&gt;. Zaoszczędzimy użytkownikom dużo cennego czasu, który mogą spędzić, np. stymulując polski rynek browarniczny ;)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-7505404338576508862?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/7505404338576508862/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/03/404-done-right-way.html#comment-form" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/7505404338576508862?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/7505404338576508862?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/03/404-done-right-way.html" title="404 done the right way" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><media:thumbnail xmlns:media="http://search.yahoo.com/mrss/" url="http://1.bp.blogspot.com/_EGp5yUlgDtc/Sb12ez12N5I/AAAAAAAAAAc/XNzO51-Glrk/s72-c/404-not-usable.png" height="72" width="72" /><thr:total>3</thr:total></entry><entry gd:etag="W/&quot;C0MCQXg-fSp7ImA9WxVVEU8.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-3018562448150652188</id><published>2009-03-03T23:53:00.004+01:00</published><updated>2009-03-04T00:04:20.655+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-04T00:04:20.655+01:00</app:edited><title>Scala nabiera prędkości</title><content type="html">Widać, że zainteresowanie Scalą rośnie (Hura!). Chyba czas najwyższy poważnie zacząć w nią inwestować (np. ruszyć Dage'a :P).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.scala-lang.org/node/959"&gt;Książki o Scali&lt;/a&gt; które są - lub w najbliższej przyszłości będą - wydane.&lt;br /&gt;&lt;br /&gt;Ponieważ już wiele osób mnie pytało jak zacząć przygodę ze Scalą, poniżej zamieszczam kilka przydatnych linków:&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.slideshare.net/jboner/pragmatic-real-world-scala-45-min-presentation?type=powerpoint"&gt;Prezentacja o Scali&lt;/a&gt; - Konkretna, pragmatyczna, krótka (108 slajdów :P).&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaTutorial.pdf"&gt;Tutorial&lt;/a&gt; - szybkie wyprowadzenie do języka. (15 stron)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.scala-lang.org/node/104"&gt;Przegląd możliwości języka&lt;/a&gt; - naprawdę "mind-blowing". &lt;b&gt;Polecam!!&lt;/b&gt; (kiedyś 55 stron w PDF - teraz dostępne na stronie)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaByExample.pdf"&gt;Scala poprzez przykłady - wprowadzenie do języka.&lt;/a&gt; (145 stron)&lt;br /&gt;&lt;br /&gt;&lt;a href="http://www.scala-lang.org/sites/default/files/linuxsoft_archives/docu/files/ScalaReference.pdf"&gt;Specyfikacja języka&lt;/a&gt; - tylko jeśli wybrałeś czerwoną pigułkę ;) (180 stron)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-3018562448150652188?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/3018562448150652188/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/03/scala-nabiera-predkosci.html#comment-form" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/3018562448150652188?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/3018562448150652188?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/03/scala-nabiera-predkosci.html" title="Scala nabiera prędkości" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>2</thr:total></entry><entry gd:etag="W/&quot;AkcNQH4zfyp7ImA9WxVUE08.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-883859412881127946</id><published>2009-03-02T22:54:00.011+01:00</published><updated>2009-03-17T23:14:51.087+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-03-17T23:14:51.087+01:00</app:edited><title>Streszczenie: Investigating architecture and design</title><content type="html">Jedną z rad w przeczytanej ostatnio przeze mnie książce &lt;a href="http://www.amazon.com/Pragmatic-Thinking-Learning-Refactor-Programmers/dp/1934356050/ref=pd_bbs_sr_1?ie=UTF8&amp;s=books&amp;qid=1232489162&amp;sr=8-1"&gt;"Pragmatic Thinking &amp; Learning: Refactor your wetware"&lt;/a&gt; autorstwa &lt;a href="http://blog.toolshed.com/"&gt;Andy'ego Hunta&lt;/a&gt; jest prowadzenie wiki. W takiej wiki może znaleźć się wszystko od ciekawych cytatów, poprzez przemyślenia aż do streszczeń książek oraz artykułów (itd. itp.). Streszczanie książek/artykułów, podkreślanie ważnych fragmentów, dopisywanie komentarzy etc. samo w sobie jest polecane przez Hunta jako świetny sposób na lepsze przyswojenie tematu... Nie będę jednak przepisywał porad z książki Andy'ego bo nie o tym miało być :) (choć gorąco zachęcam do jej przeczytania!).&lt;br /&gt;&lt;br /&gt;Zamiast tego zamieszczam streszczenie artykułu &lt;a href="http://memeagora.blogspot.com/"&gt;Neal'a Forda&lt;/a&gt; &lt;a href="http://www.ibm.com/developerworks/java/library/j-eaed1/index.html"&gt;"Investigating architecture and design"&lt;/a&gt; przeplatane moimi przemyśleniami. &lt;br /&gt;&lt;br /&gt;&lt;p&gt;&lt;br /&gt;Jeśli komuś spośród garstki osób, które odwiedza mojego bloga ;) podoba się pomysł takiego właśnie dzielenia się wiedzą będę od czasu do czasu publikował notki tego typu. W przeciwnym razie, żeby się nie pozbawiać i tak nielicznego grona czytelników :P odpuszczę sobie. &lt;br/&gt;Czekam na feedback!&lt;br /&gt;&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;hr /&gt;Notatka powstała przy użyciu pluginu do &lt;a href="http://www.vim.org"&gt;VIM&lt;/a&gt;'a - &lt;a href="http://www.vim.org/scripts/script.php%3Fscript_id%3D861"&gt;viki&lt;/a&gt; oraz konwertera &lt;a href="http://sourceforge.net/projects/deplate/"&gt;deplate&lt;/a&gt; (dla zainteresowanych wystarczy: sudo gem install deplate).&lt;br /&gt;&lt;hr /&gt;&lt;br /&gt;&lt;br /&gt;Źródło: &lt;br /&gt;Evolutionary architecture and emergent design: Investigating architecture and design[1]&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;1 Introduction&lt;br /&gt;==============&lt;br /&gt;&lt;br /&gt;Architecture is being separated into two categories:&lt;br /&gt;&lt;br /&gt;  * application architecture - coarse-grained pieces that compose an &lt;br /&gt;    application - which is further dived into:&lt;br /&gt;      + framework-level architecture - the combination of frameworks,&lt;br /&gt;      + application architecture - logical separation of concerns.&lt;br /&gt;  * enterprise architecture - how enterprise as a whole consumes &lt;br /&gt;    application.&lt;br /&gt;&lt;br /&gt;+++ Metaphor for software architectures&lt;br /&gt;&lt;br /&gt;Enterprise architecture  =&gt;  city planning&lt;br /&gt;&lt;br /&gt;Application architecture =&gt;  building architecture&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;2 Definitions of architecture&lt;br /&gt;=============================&lt;br /&gt;&lt;br /&gt;"In most successful software projects, the expert developers working on &lt;br /&gt;that project have a shared understanding of the design system design. &lt;br /&gt;This shared understanding is called 'architecture'. This understanding &lt;br /&gt;includes how the system is divided into components and how the &lt;br /&gt;components interact through interfaces." Ralph Johnson&lt;br /&gt;&lt;br /&gt;"Architecture is about the important stuff. Whatever it is." Martin &lt;br /&gt;Fowler&lt;br /&gt;&lt;br /&gt;"Stuff that's hard to change later." Neal Ford&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;3 Important note&lt;br /&gt;================&lt;br /&gt;&lt;br /&gt;!!! Architecture -&gt; Evolves !!!&lt;br /&gt;&lt;br /&gt;Because it consists of elements that must exist before you start &lt;br /&gt;building an application.&lt;br /&gt;&lt;br /&gt;!!! Design       -&gt; Emerge  !!!&lt;br /&gt;&lt;br /&gt;Because it is grown over time.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;4 Useful equations&lt;br /&gt;==================&lt;br /&gt;&lt;br /&gt;"Flexible architecture" + "Reversible decisions" = "Evolving &lt;br /&gt;architecture"&lt;br /&gt;&lt;br /&gt;"Just-in-time dirty hacks" = "Technical debt" = "Rising entropy"&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;5 Complexity&lt;br /&gt;============&lt;br /&gt;&lt;br /&gt;  * essential,&lt;br /&gt;&lt;br /&gt;          !!! Watch out for essential complexity! It might be possible to &lt;br /&gt;            !!! lower it by asking customer to consider her/his choices more &lt;br /&gt;            !!! carefully. Money argument is the ultimate way of doing that.&lt;br /&gt;  * accidental.&lt;br /&gt;&lt;br /&gt;Accidential complexity:&lt;br /&gt;&lt;br /&gt;  1. Just-in-time hacks.&lt;br /&gt;  2. Duplication.&lt;br /&gt;  3. Irreversibility.&lt;br /&gt;&lt;br /&gt;+++ Because genericness adds entropy, you damage your ability to evolve &lt;br /&gt;the design in interesting ways early in the projects.&lt;br /&gt;&lt;br /&gt;[1] &lt;a href="http://www.ibm.com/developerworks/java/library/j-eaed1/index.html"&gt;http://www.ibm.com/developerworks/java/library/j-eaed1/index.html&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-883859412881127946?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/883859412881127946/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/03/streszczenie-investigating-architecture.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/883859412881127946?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/883859412881127946?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/03/streszczenie-investigating-architecture.html" title="Streszczenie: Investigating architecture and design" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CUIBR387eyp7ImA9WxVWFUw.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-1820457017803752323</id><published>2009-02-24T23:09:00.003+01:00</published><updated>2009-02-24T23:12:36.103+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-24T23:12:36.103+01:00</app:edited><title>moje książki (for share)</title><content type="html">Ponieważ kupowanie książek na Amazon w ostatnim czasie stało się wyjątkowo drogie (albo raczej realistycznie mówiąc ceny powróciły do dawnych standardów) postanowiłem, że być może lepiej zorganizować coś swoim w środowisku. I tak doszedłem do wniosku, że najłatwiej będzie się po prostu powymieniać :D Posiadane przeze mnie książki znaleźć można &lt;b&gt;&lt;a href="http://pbadenski.listal.com/owned/books "&gt;tutaj&lt;/a&gt;&lt;/b&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-1820457017803752323?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/1820457017803752323/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/02/moje-ksiazki-for-share.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/1820457017803752323?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/1820457017803752323?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/02/moje-ksiazki-for-share.html" title="moje książki (for share)" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;AkADR3g7fyp7ImA9WxVXGEg.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-4398347345232549126</id><published>2009-02-16T23:01:00.015+01:00</published><updated>2009-02-17T09:19:36.607+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-17T09:19:36.607+01:00</app:edited><title>Java jakiej nie znacie</title><content type="html">Dzisiejszy post dedykuję wszystkim, którzy podobnie jak ja myśleli, że choć arkana ClassLoader'a są im obce, znajomośc refleksji jeszcze nie ta i garbage collector wciąż zaskakuje to składnie języka znają od podszewki.&lt;br /&gt;Dalszą część pozostawiam bez komentarza :)&lt;br /&gt;&lt;pre name="code" class="java"&gt;&lt;br /&gt;interface Quacks {&lt;br /&gt; void quack();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;interface Walks {&lt;br /&gt; void walk();&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;class Duck implements Quacks, Walks {&lt;br /&gt; public void quack() {&lt;br /&gt;  System.out.println("Quack!");&lt;br /&gt; }&lt;br /&gt;&lt;br /&gt; public void walk() {&lt;br /&gt;  System.out.println("[a sound of a duck walking :P]");&lt;br /&gt; } &lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;public class Hunter {&lt;br /&gt; &amp;lt;T extends Quacks &amp;amp; Walks&amp;gt; void shoot(T animal) {&lt;br /&gt;  animal.walk();&lt;br /&gt;  System.out.println("[a sound of a gunshot]");&lt;br /&gt;  animal.quack();&lt;br /&gt;  System.out.println("[a sound of a quacking, walking animal dying]");&lt;br /&gt; }&lt;br /&gt; &lt;br /&gt; public static void main(String[] args) {&lt;br /&gt;  new Hunter().shoot(new Duck());&lt;br /&gt; }&lt;br /&gt;}&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Amazing ain't it ?&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-4398347345232549126?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/4398347345232549126/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/02/java-jakiej-nie-znacie.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/4398347345232549126?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/4398347345232549126?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/02/java-jakiej-nie-znacie.html" title="Java jakiej nie znacie" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;DUIFRn49eip7ImA9WxVQGEg.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-2442901407820574076</id><published>2009-02-05T19:04:00.005+01:00</published><updated>2009-02-05T19:11:57.062+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-05T19:11:57.062+01:00</app:edited><title>Odpowiedź wujka Boba na podcast takich dwóch..</title><content type="html">Zachęcam do przeczytania &lt;a href="http://blog.objectmentor.com/articles/2009/01/31/quality-doesnt-matter-that-much-jeff-and-joel"&gt;odpowiedzi Roberta C. Martina&lt;/a&gt; aka Uncle Boba na podcast Jeffa i Joela o którym pisałem&lt;a href="http://pbadenski.blogspot.com/2009/02/joel-i-jeff-czyli-o-dwoch-takich-co.html"&gt;&lt;/a&gt; kilka dni temu.&lt;br /&gt;&lt;br /&gt;Dla zachęty pozwolę sobie zacytować jeden z komentarzy Pana Eduardo Scoz'y (Scoza?):&lt;br /&gt;&lt;blockquote&gt;I was listening to the podcast during my way to work when they started talking about TDD and quality, and I the same WTF?? feeling. Honestly, I started laughing in the bus..&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;Być może ma rację. Może zamiast się denerwować należało tę dyskusję wyśmiać ? :P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-2442901407820574076?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/2442901407820574076/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/02/odpowiedz-wujka-boba-na-podcast-takich.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/2442901407820574076?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/2442901407820574076?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/02/odpowiedz-wujka-boba-na-podcast-takich.html" title="Odpowiedź wujka Boba na podcast takich dwóch.." /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DEcFRns8cCp7ImA9WxVQF0U.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-4630527019296270086</id><published>2009-02-04T00:13:00.007+01:00</published><updated>2009-02-04T23:20:17.578+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-04T23:20:17.578+01:00</app:edited><title>jak bezwzględnie wykorzystać i porzucić RFC 2616</title><content type="html">&lt;a href="http://www.rfc-editor.org/rfc/rfc2616.txt"&gt;RFC 2616&lt;/a&gt; to oczywiście nasze ulubione HTTP/1.1 :)&lt;br /&gt;&lt;br /&gt;Siedzę tak sobie w domu i się nudzę (głównie gdyż ponieważ na czwartek przygotować mam wstęp teoretyczny do pracy dyplomowej ;P). I tak z braku zajęć przerabiam skrypt powiadamiający mnie o ogłoszeniu wyników z egzaminu... a że jakiś czas temu zakończyłem czytanie w/w specyfikacji doszło do mnie, że w sumie warto wreszcie chociaż w minimalnym stopniu spróbować tę wiedzę wykorzystać!&lt;br /&gt;&lt;br /&gt;Tak powstał poniższy skrypcik:&lt;br /&gt;&lt;pre&gt;&lt;br /&gt;#!/bin/zsh&lt;br /&gt;function get {&lt;br /&gt; curl -Iis -H"If-None-Match: `cat $ETAG_FILE`" \&lt;br /&gt;   http://sun10.ci.pwr.wroc.pl/~kwiatkow/archdwa/mat_archdwa.html&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;function put_etag {&lt;br /&gt; echo "$RESPONSE" | grep ETag | cut -f2 -d' ' &gt; /var/tmp/exam1-ak2.etag&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;ETAG_FILE=/var/tmp/exam1-ak2.etag&lt;br /&gt;RESPONSE=`get`&lt;br /&gt;&lt;br /&gt;if [ ! -e $ETAG_FILE ]; then&lt;br /&gt; `put_etag`&lt;br /&gt; exit &lt;br /&gt;fi&lt;br /&gt;&lt;br /&gt;if [ `echo "$RESPONSE" | head -n1 | cut -f2 -d' '` != "304"  ]; then &lt;br /&gt; `put_etag`&lt;br /&gt; sms -g plus -n XXXYYYZZZ -m "Zmiana na stronie dr Kwiatkowskiego ! \&lt;br /&gt;   Czyzby wyniki z egzaminu ?"&lt;br /&gt;fi&lt;br /&gt;&lt;/pre&gt;&lt;br /&gt;Enjoy ! :)&lt;br /&gt;&lt;br /&gt;P.S. Skrypt zadziałał - AK2 zaliczone na 4.0 :)&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-4630527019296270086?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/4630527019296270086/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/02/jak-bezwzglednie-wykorzystac-i-porzucic.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/4630527019296270086?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/4630527019296270086?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/02/jak-bezwzglednie-wykorzystac-i-porzucic.html" title="jak bezwzględnie wykorzystać i porzucić RFC 2616" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;CU4MRX4zcCp7ImA9WxVQFU8.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-7647502724185391412</id><published>2009-02-01T21:24:00.011+01:00</published><updated>2009-02-01T22:33:04.088+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-01T22:33:04.088+01:00</app:edited><title>Joel i Jeff - czyli o dwóch takich co gadają niemądrze..</title><content type="html">Dzisiaj nadziałem się (a przynajmniej uczucie po przeczytaniu było takie jakbym się nadział) na zapis z podcastu rozmowy &lt;a href="http://www.joelonsoftware.com"&gt;Joela Spolsky'ego&lt;/a&gt; i &lt;a href="http://www.codinghorror.com"&gt;Jeffa Atwooda&lt;/a&gt;. Ponieważ przedstawione opinie mocno mi napsuły krwi prezentuje je poniżej, coby się trochę wyzewnętrznić :].&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Joel: But, I feel like if a team really did have 100% code coverage of their unit tests, there'd be a couple of problems. One, they would have spent an awful lot of time writing unit tests, and they wouldn't necessarily be able to pay for that time in improved quality. I mean, they'd have some improved quality, and they'd have the ability to change things in their code with the confidence that they don't break anything, but that's it.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Ok.. Zgadzam się z powyższym - ale jeśli ktoś ma choć trochę oleju w głowie, zawsze - ale to zawsze - zgodzi się z jakąkolwiek krytyką skrajności. Skrajność jest zła !! ZŁAAAA! "Being extreme is evil and wrong. EOF" - to idealna odpowiedź, dyskusja z głupotą ją nobilituje..&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;But the real problem with unit tests as I've discovered is that the type of changes that you tend to make as code evolves tend to break a constant percentage of your unit tests. Sometimes you will make a change to your code that, somehow, breaks 10% of your unit tests. Intentionally. Because you've changed the design of something... &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Ok.. to ma sens.. zdarzają się zmiany które puszczą z dymem 10% testów jednostkowych. Pomijając fakt, że przy poprawnie napisanych unit testach najpewniej będzie to zmiana archiektury, istotnej dla projektu technologii albo jakaś hiper-istotna zmiana biznesowa - zdarza się. &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;you've moved a menu, and now everything that relied on that menu being there... the menu is now elsewhere. And so all those tests now break. And you have to be able to go in and recreate those tests to reflect the new reality of the code.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;MENU !?! ok.. wtf ? jakie menu ?! testy jednostkowe i menu ? .. no sorry, ale po gościu który jest autorytetem w IT spodziewam się conajmniej zrozumienia róznicy między testami jednostkowymi, a innymi - te też mylę nigdy nie wiem czy testy UI to integracyjne, akceptacyjne czy jakie tam, ale _na pewno_ nie jednostkowe!&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;So the end result is that, as your project gets bigger and bigger, if you really have a lot of unit tests, the amount of investment you'll have to make in maintaining those unit tests, keeping them up-to-date and keeping them passing, starts to become disproportional to the amount of benefit that you get out of them.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Zgadzam się.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;&lt;br /&gt;Jeff:&lt;br /&gt;I think that's a great point. Although, I do think if you're working on older code bases that don't have a lot of churn, ...&lt;br /&gt;&lt;br /&gt;Joel:&lt;br /&gt;Yeah.&lt;br /&gt;&lt;br /&gt;Jeff:&lt;br /&gt;To me it's about churn. If you're working on an old code base that isn't going to have that much churn, and you want to change it where you can't break anything, where if you break anything it's really really bad, then it's probably worth your time to go in and develop a bunch of unit tests. You're building scaffolding around this grand old building, this classic old building that's not going to change for another 200 years, so sure, build a bunch of scaffolding around the building.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Ok.. gdyby te testy tam były "in the first place" to byśmy mogli zmienić i mieli spokój. Co więcej napisanie testów do istniejącego kodu - którego nie znasz - jest na moje oko przynajmniej rząd trudniejsze. Oczywiście po raz kolejny ważny jest zdrowy rozsądek, bo trzeba mieć wyczucie kiedy testy pisać bardziej, ile tych testów, umieć wyczuć kiedy implementacja się stabilizuje itp., itd. miałem nie pisać o rzeczach oczywistych - ale jak widać Jeff Atwood albo sobie żartuje albo ich nie rozumie.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Joel:&lt;br /&gt;Yeah. They work really for things like a compiler, where the design is not going to change because the language is fixed.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Ok. To idealnie pokazuje ile wspólnego ma Joel z oprogramowaniem biznesowym :P Kompilator ..&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Jeff:&lt;br /&gt;That's right.&lt;br /&gt;&lt;br /&gt;Joel:&lt;br /&gt;I might do more black-box tests, sort of like unit tests but more from the perspective of "does this compile all code correctly," with enormous numbers of tests, than just the internal, "does this particular function work in this particular way at all times."&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;W językach obiektowych mamy metody i to je testujemy. Dla mnie to niesamowicie duża różnica konceptualna bo metody służą do komunikacji między obiektami podczas gdy funkcje obliczają wynik.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Last week I was listening to a podcast on Hanselminutes, with Robert Martin talking about the SOLID principles. (That's a real easy-to-Google term!) It's object-oriented design, and they're calling it agile design, which it really, really isn't. It's principles for how to design your classes, and how they should work. And, when I was listening to them, they all sounded to me like extremely bureaucratic programming that came from the mind of somebody that has not written a lot of code, frankly.&lt;br /&gt;&lt;br /&gt;And here I am ranting against somebody that doesn't have a chance to respond. But just to give you one example, a part of the SOLID principles was that if you write a class, that class has contracts with all the other classes that it interacts with, and those contracts should be expressed in interfaces [PDF]. So you shouldn't just interact with the class, because that class may change. If you have a particular class that you need to use, you should make a custom interface just for what you're going to use in that class. That interface, then, never has to change. And the interface is the only thing that you have to #include.&lt;br /&gt;&lt;br /&gt;Does that make sense? So, you've got some class, with 40 different little methods on it, and I'm only going to use six of them, so I should make an interface with those six things that I can use, and the class will implement that interface, and that's my contract with the class, that those are the only six things I'm going to use.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Dla mnie osobiście to podejście Uncle Bob'a brzmi akurat niesamowicie rozsądnie ...&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;People that say things like this have just never written a heck of a lot of code. &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Pozwolę sobie skontrować słowami znanego autorytetu w dziedzinie IT: "People that say things like this have just never written a heck of a lot of code. ".&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Because what they're doing is spending an enormous amount of time writing a lot of extra code, a lot of verbiage, a lot of files, and a million little classes that don't do anything and thousands of little interface classes and a lot of robustness to make each of these classes individually armed to go out into the world alone and do things, and you're not going to need it. You're spending a lot of time in advance writing code that is just not going to be relevant, it's not going to be important. It could, theoretically, protect you against things, but, how about waiting until those things happen before you protect yourself against them?&lt;br /&gt;&lt;br /&gt;This seems to be where a lot of the Object Oriented Design community went, and if anybody has any strong feelings about this, call in and tell me what you think--tell me if I'm totally off track here--but it seems to me like a lot of the Object Oriented Design principles you're hearing lately from people like Robert Martin and Kent Beck and so forth have gone off the deep end into architecture for architecture's sake. It doesn't seem like you could actually get any code written if you're spending all your time writing 8,000,000 unit tests, and every single dinky little class that you need to split a URL into four parts becomes an engineering project worthy of making a bridge, where you spend six months defining 1000 little interfaces. They've just gone off the deep end, and I don't think these people write very much code if they're coming up with these principles, to be honest, it doesn't even make sense.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Ok.. tu zaczynają mnie ponosić emocje i chciałoby się podsumować "Blablablabla". Powiem jedno.. jeśli Joel nie rozumie projektowanie zorientowanego obiektowo to ja straciłem nadzieję w ludzi - albo po prostu on jest dobrze ukrywającym się w przebraniu programisty bardzo dobrym biznesmenem. A już byłem pełen optymizmu gdy na ostatniej konferencji JAOO usłyszałem słowa: "Ludzie [programiści, projektanci, architekci, etc.] zaczynają wreszcie po 30 latach rozumieć o co chodzi w programowaniu obiektowym".&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Jeff:&lt;br /&gt;Well, there are places where that level of testing makes sense. If you're working at Microsoft and you're working on the .NET Framework...&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;M$ SUUUX !!! :P Przepraszam za brak profesjonalizmu ;) Nie mogłem sobie darować :D&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Joel:&lt;br /&gt;Yeah.&lt;br /&gt;&lt;br /&gt;Jeff:&lt;br /&gt;... you have a totally different set of obligations to your public ...&lt;br /&gt;&lt;br /&gt;Joel:&lt;br /&gt;Correct.&lt;br /&gt;&lt;br /&gt;Jeff:&lt;br /&gt;... Your code's going to be used millions and millions of times.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;W przypadku oprogramowania biznesowego: "Your code's going to be SEEN millions and millions of times." &lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Joel:&lt;br /&gt;Yeah. In fact, if you're making any kind of API, a plug in API, it is very important to separate things into interfaces and be very very contractual, and tightly engineered. Just like you want to put a lot of effort into your user interface, you also want to put a lot of effort into your API that people are calling... it's just an interface, and you want it to be good and solid and robust. And that's fine.&lt;br /&gt;&lt;br /&gt;But this idea that every single class in your code, all these classes interacting with each other, should be so tightly defined ...&lt;br /&gt;&lt;br /&gt;Listening to this interview on Hanselminutes, there seemed to be an intense obsession with creating lots and lots of little classes that all did one particular thing...&lt;br /&gt;&lt;br /&gt;One of the SOLID principles, and I'm totally butchering this, but, one of the principles was that you shouldn't have two things in the same class that would be changed for a different reason [PDF]. Like, you don't want to have an Employee class, because it's got his name which might get changed if he gets married, and it has his salary, which might get changed if he gets a raise. Those have to be two separate classes, because they get changed under different circumstances. &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Amm .. ok.. dobra bo nie kumam - co jest dziwnego w osobnym trzymaniu Employee i Salary.. czyli mam naćpać wszystkie algorytmy obliczania ZUS'ów, progów podatkowych, urlopów do klasy Employee ? Zresztą, w każdym sensownym systemie kadrowym byłoby jak najbardziej wskazane te dwie klasy wyróżnić. No chyba że to portal WEB 2.0 w którym zarobki to zwykły prymitywny float... ale to skrajny przykład (patrz wyżej na temat skrajności).&lt;br /&gt;&lt;br /&gt;Nie wspomnę już o tym, że Joel (albo ja) absolutnie nie zrozumiał na czym polega Single Responsibility Principle. Podczas gdy on mówi o zmianie stanu obiektu Uncle Bob wyraźnie pisze o zmianie klasy !! Obiekt a klasa .. no proszę, mnie na 2 roku uczyli je rozróżniać.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;And you wind up with millions of tiny little classes, like the EmployeeSalary class, and it's just... (laughs) idiotic! You can't build software that way! &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Racja, ah Ci głupi zwolennicy OO. Assembler ROX !&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;The way real software works is that you create these very imperfect things, and they work great. &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;.. jak problem roku 2000.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;They really do. &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;.. really do make people rich. (vide programiści systemów bankowych w roku 1999 :P).&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;And then you have a little problem, and you go and you fix the little problem, because it's code, and you have an editor, and you edit it. &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;.. jak problem roku 2000. khy khy&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;These classes are not going to go wander off flying in the universe all by themselves and need to work perfectly and unchanged until the end of time.&lt;br /&gt;&lt;br /&gt;Jeff:&lt;br /&gt;Right. The longer I think about this, the less I care about code hygiene issues (laughs). Because the unit of measure that really matters to me is, how quickly you can respond to real business needs with your code. And by that I mean, how well are you serving the people that are using your code. &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;A w restauracji Twoim jedynym obowiązkiem jest obsługiwać klientów. Naczynia się posprzątają same.&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;To me that's what it's all about. Anything that gets in the way of you fixing your code or improving your code in a way that your customers can appreciate, is a negative. If that means using Ruby, or having lots of unit tests: whatever's working for you: do that. But if it's getting in the way, if it becomes friction, like, "I'd love to have this great new feature but I'd have to have 1000 unit tests," that's a negative.&lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;Kwestia balansu oczywiście... ale do tego trzeba hmmm.. myśleć ?&lt;br /&gt;&lt;br /&gt;&lt;blockquote&gt;&lt;br /&gt;Joel:&lt;br /&gt;Yeah. And the worst thing that happens is that you get people that just stop thinking about what they're doing. &lt;br /&gt;&lt;/blockquote&gt;&lt;br /&gt;&lt;br /&gt;.. and saying - vide ta dyskusja Joela z Jeffem.&lt;br /&gt;&lt;br /&gt;Reszta rozmowy dostępna jest na &lt;a href="http://www.joelonsoftware.com/items/2009/01/31.html"&gt;blogu Joela&lt;/a&gt; bo ja naprawdę nie mam siły... Przyznaję, że kilka razy zastosowałem trochę nieczyste chwyty (np. z przykładem problemu roku 2000), ale ogólnie opinie Joela i Jeffa mocno mnie zdenerwowały. Nie spodziewałem się że inteligentni i świadomi (jak sądziłem) programiści będą pier.. wygadywać takie głup.. niemądre rzeczy.&lt;br /&gt;&lt;br /&gt;Pozostawiam tę ichnią rozmowę do Waszej rozwagi.&lt;br /&gt;&lt;br /&gt;P.S. Jeśli Joel z Jeffem po prostu "robili sobie jaja" (co jest bardzo prawdopodobne) proszę mnie powiadomić abym mógł zdjąć tego posta lub odpowiednio go zkorygować. :P&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-7647502724185391412?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/7647502724185391412/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/02/joel-i-jeff-czyli-o-dwoch-takich-co.html#comment-form" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/7647502724185391412?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/7647502724185391412?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/02/joel-i-jeff-czyli-o-dwoch-takich-co.html" title="Joel i Jeff - czyli o dwóch takich co gadają niemądrze.." /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>1</thr:total></entry><entry gd:etag="W/&quot;DEMBQH4-cCp7ImA9WxVQFEQ.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-2332133985795140335</id><published>2009-02-01T14:19:00.002+01:00</published><updated>2009-02-01T14:54:11.058+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-02-01T14:54:11.058+01:00</app:edited><title>Co z tą Javą</title><content type="html">Od pewnego czasu popularne stały się posty w których autorzy próbują spekulować na temat: "Czy język XXX zastąpi Javę?". Oczywiście założeniem implicite jest, że Java potrzebuje i będzie przez coś zastąpiona. Osobiście jestem zwolennikiem teorii, iż Java powinna się powoli kończyć. Nie wiem czy i kiedy się to stanie. Mimo że my - programiści, jesteśmy w pewnym stopniu odpowiedzialni za tę decyzję należy ona w dużej mierze do naszych szefów ;).&lt;br /&gt;&lt;br /&gt;Biorąc pod uwagę fakt, że ogólnie jestem zwolennikiem &lt;a href="http://olabini.com/blog/2008/06/fractal-programming/"&gt;koncepcji polyglot programming&lt;/a&gt; - wierzę, że językiem przyszłości dla JVM w warstwie "stabilnej" jest Scala. Ponieważ jednak wciąż przoduje wiara w teorię "jeden jęzka do wszystkich zastosowań" coraz częsciej zdarza mi się czytać &lt;a href="http://jackcoughonsoftware.blogspot.com/2008/12/ruby-over-scala.html"&gt;posty porównujące Scalę z Ruby&lt;/a&gt;. Według mnie świadczy to bardzo dobrze o samej Scali i tym bardziej przekonuje mnie, żę powinna ona zastąpić Javę. Sądzę, że takie porównanie wynika z niesamowitej elastyczności i ekspresywności języka - mimo tego, że Scala jest typowana statycznie (burzy mit, że "static typing" == Java). Pozwala to na rozmycie się argumentów w odwiecznym &lt;a href="http://fishbowl.pastiche.org/2003/05/06/weighing_into_the_static_vs_dynamic_typing_debate/"&gt;sporze zwolennków języków statycznych i dynamicznych&lt;/a&gt;. Java w tym świetle jest językiem "zeszłego Millenium" - do bólu imperatywnym, nadmiarowym (verbose) i ordynarnym (crude) - &lt;a href="http://rickyclarkson.blogspot.com/2008/12/java-just-died-no-closures-in-java-7.html"&gt;i nic nie zapowiada że się to szybko zmieni&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Ostatnio odbyłem krótka dyskusję ze &lt;a href="http://paulszulc.blogspot.com/"&gt;znajomym&lt;/a&gt; właśnie na temat "Co dalej?", w której staraliśmy się rozstrzygnąć czy należy zainwestować w Scalę, Ruby'ego (i Railsy) czy też pozostać przy Javie. Na dziś dzień moja decyzja to polyglot programming w oparciu o:&lt;br /&gt; - Scala (warstwa "stabilna"), &lt;br /&gt; - Grails (Groovy) albo Lift (Scala) albo Rails (Ruby) (warstwa "dynamiczna" - prezentacji),&lt;br /&gt; - JVM (istniejące technologie i frameworki).&lt;br /&gt;&lt;br /&gt;W oparciu o powyższe: TAK - dla Scali, NIE - dla Javy, MOŻE - dla reszty.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-2332133985795140335?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/2332133985795140335/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/02/co-z-ta-java.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/2332133985795140335?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/2332133985795140335?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/02/co-z-ta-java.html" title="Co z tą Javą" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry><entry gd:etag="W/&quot;A0AAQH07fCp7ImA9WxVRFkg.&quot;"><id>tag:blogger.com,1999:blog-36484905.post-7988915121140115973</id><published>2009-01-21T23:10:00.004+01:00</published><updated>2009-01-22T22:29:01.304+01:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2009-01-22T22:29:01.304+01:00</app:edited><title>blogowania ciąg dalszy - hibernate tips&amp;tricks</title><content type="html">Od daaaawna nie było żadnego posta (od lipca zeszłego roku ;]). Nie będę się na ten temat zbytnio rozpisywał bo tematem bloga w końcu nie jest "Dlaczego regularnie zarzucam blogowanie?", a przyczyna jest prozaiczna - brak czasu. Ponieważ jednak różne przemyślenia w głowie już mi się kotłują, a ciekawych linków na sieci coraz więcej postanowiłem, że od dziś będę starał się wrzucać posty regularniejsze a krótsze (dosłownie 2 zdania jeśli nie będę miał czasu na więcej). Ponieważ szcerze mowiąc sciągnąłem ten pomysł z &lt;a href="http://www.innoq.com/blog/st/"&gt;bloga Stefana Tilkova&lt;/a&gt; nie mam zamiaru się go wstydzić :)&lt;br /&gt;&lt;br /&gt;Do rzeczy - czyli Hibernate tips and tricks:&lt;br /&gt;&lt;br /&gt;1) &lt;span style="font-weight:bold;"&gt;Strategie nazewnictwa "bytów" w bazie danych&lt;/span&gt;&lt;br /&gt;Jeśli w projekcie każde pole (tudzież setter) opakowane jest kupą adnotacji z tym jak nazywać poszczególne elementy w bazie danych (skądinąd przygotowane takiego standardu w zakresie projektu to bardzo dobry pomysł) być może przyszedł czas zcentraliować te informację. Hibernate przychodzi nam z pomocą i &lt;a href="http://www.hibernate.org/hib_docs/v3/api/org/hibernate/cfg/NamingStrategy.html"&gt;dostarcza możliwość określenia strategii&lt;/a&gt; jak poszczególne elementy po-naszemu nazywać :)&lt;br /&gt;Tip: Warto dodać strategię nie tylko do aplikacji ale (i to zwłaszcza) do ant'owego taska generującego schemat :)&lt;br /&gt;&lt;br /&gt;2) &lt;span style="font-weight:bold;"&gt;Filtrowanie kolekcji po stronie bazy danych&lt;/span&gt;&lt;br /&gt;Nie raz zdarzyło mi się znaleźć kawałki kodu przepuszczające kolekcje przez jakąś logikę (mniej lub bardziej biznesową) które albo:&lt;br /&gt; - zamiast wykorzystać istniejącą asocjację kolekcji po prostu zbierały te informację z bazy danych, dodając do zapytania warunek 'WHERE'.&lt;br /&gt;albo&lt;br /&gt; - zbierały z bazy całą kolekcję (na ogół przez lazy fetch, czyli po prostu wywołanie gettera) po czym sobie po niej radośnie iterowały szukając odpowiednich danych.&lt;br /&gt; Tymczasem &lt;a href="http://www.hibernate.org/hib_docs/v3/reference/en-US/html/objectstate-querying.html#objectstate-filtering"&gt;Hibernate pozwala na przefiltrowanie kolekcji&lt;/a&gt; (oraz tablic) do których dostęp mamy po stronie Javy za pomocą mechanizmu filtrów. Już nie musimy wybierać między szybkością (HQL i baza danych) oraz czytelnością (zrobić to po stronie Javy).&lt;br /&gt;&lt;br /&gt;3) &lt;span style="font-weight:bold;"&gt;Nazywanie kolumny a nazwy zabronione&lt;/span&gt;&lt;br /&gt;Jeśli tylko korzystasz z PostgreSQL pewno nie raz już ucieszył Cię error "wszystko wybucha wywołaj getNextException() żeby odkryć gdzie" (skądinąd takie połykanie Exceptionów przyprawia mnie o lekki ból głowy) tylko po to by dowiedzieć się że Twoja klasa User (chyba User.. o ile pamiętam że właśnie ten wybuch zaliczyłem na PostgreSQL :]) niestety tak się nazywać nie może :) Jeśli nie chcesz użyć nazw typu: Ape, Non_Geek dla swoich klientów polecam &lt;a href="http://www.hibernate.org/hib_docs/v3/reference/en-US/html/mapping-quotedidentifiers.html"&gt;zapoznanie się z lekturą&lt;/a&gt;.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/36484905-7988915121140115973?l=pbadenski.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel="replies" type="application/atom+xml" href="http://pbadenski.blogspot.com/feeds/7988915121140115973/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="http://pbadenski.blogspot.com/2009/01/blogowania-cig-dalszy-hibernate-tips.html#comment-form" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/7988915121140115973?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/36484905/posts/default/7988915121140115973?v=2" /><link rel="alternate" type="text/html" href="http://pbadenski.blogspot.com/2009/01/blogowania-cig-dalszy-hibernate-tips.html" title="blogowania ciąg dalszy - hibernate tips&amp;tricks" /><author><name>Paweł Badeński</name><uri>http://www.blogger.com/profile/02544441831377477201</uri><email>noreply@blogger.com</email><gd:image rel="http://schemas.google.com/g/2005#thumbnail" width="16" height="16" src="http://img2.blogblog.com/img/b16-rounded.gif" /></author><thr:total>0</thr:total></entry></feed>

